mercredi 8 juillet 2009

Vive les en-têtes précompilées!

J'adore cette fonctionnalité de gcc, d'ailleurs présente, si mes souvenirs sont justes, dans le compilo de Microsoft, bien avant son arrivée dans le compilateur GNU.

L'idée est simple: dans n'importe quel programme d'une taille un peu conséquente, beaucoup de fichiers en-tête sont inclus dans pratiquement toutes les unités de compilation (pensez à la bibliothèque standard, par exemple). Le compilateur passe donc beaucoup de temps à lire et à parser les mêmes fichiers. Pourquoi donc ne pas mouliner ces en-têtes souvent utilisées, une seule fois, vers un format efficace, utilisé ensuite dans chaque unité de compilation.

Dans gcc, c'est d'une simplicité enfantine.

  • Créez un fichier en-tête (par exemple All.h), mettez-y toutes vos en-têtes souvent utilisées.

  • Dans tous vos fichiers source, incluez en premier All.h, et enlevez toutes les inclusions déjà présentes dans All.h

  • Vérifiez que tout compile gentiment

  • Puis, compilez All.h comme un bête fichier source, avec les mêmes options de compilation que tout le rèste. Par exemple, pour le c++:
    g++ -c All.h

  • Admirez le fichier All.h.gch qui vient d'être généré, et compilez vos sources normalement!



Voilà ce que je mets dans mon All.h, pour le serveur AdH:

#ifndef __ALL_H__
#define __ALL_H__

#include <istream>
#include <ostream>
#include <stdexcept>
#include <cmath>
#include <sstream>
#include <vector>
#include <set>
#include <iostream>

#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/static_assert.hpp>
#include <boost/operators.hpp>
#include <boost/optional.hpp>
#include <boost/scoped_array.hpp>
#include <boost/foreach.hpp>
#include <boost/noncopyable.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/bind.hpp>
#include <boost/variant.hpp>
#include <boost/scoped_array.hpp>
#include <boost/timer.hpp>
#include <boost/date_time/posix_time/ptime.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/random.hpp>
#include <boost/function.hpp>
#include <boost/program_options.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/regex.hpp>

#include <pqxx/pqxx>

#endif


Il me semble avoir déjà dit ici que j'aimais bien Boost.

Voilà les temps de compilation du serveur.
  • Tout seul: 26.16 secondes

  • Avec l'en-tête précompilée:12.92 secondes


Probablement un peu injuste, puisque par exemple je n'inclurais pas boost/regex.hpp dans chaque fichier. Mais la différence est quand même significative, ne serais-ce que pour ne pas avoir à s'embêter à choisir soigneusement les fichiers à inclure dans chaque source, et se retrouver avec des listes d'inclusions standards longues comme le bras dans chaque fichier.

Petite remarque: ma préférence quand à choisir ce qui va dans les en-têtes précompilées est d'y mettre toutes les dépendances extérieures. Les entêtes libpqxx ou wxWidgets y appartiennent, mais ma bibliothèque d'utilitaires non!

Et une dernière pour la route: assurez vous qu'il y a de l'espace disque. Mon gch fait 113 megs!

Aucun commentaire: