web-dev-qa-db-fra.com

Comment accélérer le temps de compilation g ++ (en utilisant beaucoup de modèles)

Cette question est peut-être quelque peu étrange, mais comment puis-je accélérer le temps de compilation de g ++? Mon code C++ utilise beaucoup de boost et de templates. J'ai déjà sorti le plus possible les fichiers d'en-tête et utilisé l'option -j, mais la compilation (et le lien) prend un certain temps.

Existe-t-il des outils permettant d'analyser mon code et de signaler les goulots d'étranglement au compilateur? Ou peut-on en quelque sorte profiler le compilateur exécuté sur mon code? Ce serait vraiment sympa, car parfois j'ai l'impression que j'ai passé trop de temps à regarder le journal de la console du compilateur ...

61
Danvil

Ce qui a été le plus utile pour moi:

  • Construire sur un système de fichiers RAM. Ceci est trivial sous Linux. Vous pouvez également conserver une copie des fichiers d’en-tête courants (fichiers précompilés ou réels .h) sur le système de fichiers RAM.
  • En-têtes précompilés . J'ai une bibliothèque (majeure) (par exemple, Boost, Qt, stdlib).
  • Déclarez au lieu d'inclure des classes dans la mesure du possible. Cela réduit les dépendances et donc le nombre de fichiers à recompiler lorsque vous modifiez un fichier d'en-tête.
  • Paralléliser make . Cela aide généralement au cas par cas, mais j'ai -j3 globalement pour make. Assurez-vous cependant que vos graphes de dépendance sont corrects dans votre Makefile, sinon vous pourriez avoir des problèmes.
  • Utilisez -O0 si vous ne testez pas la vitesse d’exécution ou la taille du code (et que votre ordinateur est suffisamment rapide pour que vous ne vous préoccupiez pas trop de la perte de performances (probablement minime)).
  • Compilez chaque fois que vous enregistrez. Certaines personnes n'aiment pas cela, mais cela vous permet de détecter les erreurs plus tôt et peut être fait en arrière-plan, ce qui réduit le temps que vous devez attendre lorsque vous avez terminé d'écrire et que vous êtes prêt à tester.
47
strager

Je suppose que nous parlons de minutes pour compiler un fichier, c’est-à-dire que les en-têtes précompilés ou les problèmes de disque local ne sont pas le problème.

Les longs temps de compilation avec un code de modèle profond (boost, etc.) sont souvent enracinés dans le comportement asymptotique inimitable de gcc en ce qui concerne l’instanciation de modèle, en particulier lorsque les modèles variadiques sont émulés avec des arguments par défaut. 

Voici un document qui nomme le temps de compilation réduit comme une motivation pour les modèles variadiques:

cpptruths a écrit un article sur la façon dont gcc-4.5 est bien meilleur à cet égard et comment il fonctionne brillamment avec ses modèles variadiques:

IIRC then BOOST a le moyen de limiter la génération de paramètres de modèle par défaut pour les pseudo-variables, je pense que 'g ++ -DBOOST_MPL_LIMIT_LIST_SIZE = 10' devrait fonctionner (la valeur par défaut est 20)

UPDATE: Il existe également un fil de Nice avec des techniques générales pour accélérer la compilation ici sur SO qui pourrait être utile: 

UPDATE: Celui-ci concerne les problèmes de performances lors de la compilation de modèles. La réponse acceptée recommande également gcc-4.5. Clang est également cité en exemple positif:

17
Nordic Mainframe

Voici ce que j'ai fait pour accélérer les builds dans un scénario très similaire à celui décrit (boost, templates, gcc).

  • construire sur un disque local au lieu d'un système de fichiers réseau tel que NFS
  • passer à une version plus récente de gcc
  • enquêter distcc
  • systèmes de construction plus rapides, en particulier plus de RAM
17
Sam Miller

Si vous faites beaucoup de recompilation, ccache pourrait vous aider. Cela n'accélère pas réellement la compilation, mais vous obtiendrez un résultat en cache si vous effectuez une recompilation inutile pour une raison quelconque. Cela peut donner l'impression de s'attaquer au mauvais problème, mais parfois, les règles de reconstruction sont tellement complexes que vous vous retrouvez avec la même étape de compilation lors d'une nouvelle génération.

Idée supplémentaire: si votre code est compilé avec clang , utilisez-le à la place. C'est généralement plus rapide que gcc.

9
viraptor

En plus de ce que tout le monde a ajouté et de ce que vous faites déjà (construction parallélisée, options de compilateur, etc.), envisagez de masquer les modèles dans les classes d'implémentation, accessibles via des interfaces. Cela signifie qu'au lieu d'avoir une classe comme celle-ci:

// ClsWithNoTemplates.h file, included everywhere

class ClsWithTemplates
{
    ComplicatedTemplate<abc> member;
    // ...

public:
    void FunctionUsingYourMember();
};

tu aurais dû:

// ClsWithNoTemplates.h file:

class ClsWithTemplatesImplementation; // forward declaration
  // definition included in the ClsWithNoTemplates.cpp file
  // this class will have a ComplicatedTemplate<abc> member, but it is only 
  // included in your ClsWithNoTemplates definition file (that is only included once)


class ClsWithNoTemplates
{
     ClsWithTemplatesImplementation * impl; // no templates mentioned anywhere here
public:
    void FunctionUsingYourMember(); // call impl->FunctionUsingYourMember() internally
};

Ceci modifie un peu votre conception OOP, mais c'est pour le bien: inclure la définition de 'ClsWithNoTemplates' est maintenant fast et vous ne compilez (pré)) la définition de 'ClsWithNoTemplates' qu'une fois.

De plus, si vous modifiez le code d'implémentation, il ne sera probablement pas nécessaire de redéfinir tout code incluant ClsWithNoTemplates.h.

Cette modification devrait augmenter considérablement votre temps de compilation partielle et sera également utile dans le cas où votre ClsWithNoTemplates est une interface publique exportée depuis un fichier de bibliothèque: puisque le fichier n'est pas modifié lorsque vous modifiez uniquement l'implémentation, votre code client dépendant ne le fait pas. pas besoin d’être recompilé du tout.

3
utnapistim

Essayez la technique PIMPL, cette question: Quelles techniques peuvent être utilisées pour accélérer les temps de compilation C++?

Cela empêchera le compilateur de suivre la chaîne de fichiers d'en-tête et d'implémentations à chaque fois que vous devez faire quelque chose.

3
gtrak

S'il y a beaucoup de fichiers, vous pouvez accélérer beaucoup la compilation en ne disposant que d'un seul fichier .cpp contenant # tous les autres fichiers .cpp. Cela nécessite bien sûr que vous soyez plus prudent avec les macros et que vous ayez déjà défini par fichier, car elles seront désormais visibles par d'autres fichiers cpp.

S'il y a beaucoup de fichiers, cela peut réduire beaucoup le temps de compilation.

2
Zitrax

Instanciez moins de modèles et de fonctions en ligne. Précompilez autant que vous le pouvez et associez-le plutôt que de tout compiler à partir de zéro. Assurez-vous que vous utilisez la dernière version de GCC.

Cependant, il est un fait que C++ est un langage incroyablement complexe et sa compilation prend un certain temps.

1
Puppy

Cet article décrit une méthode de compilation de code de gabarit très semblable aux fichiers objets "traditionnels" non gabarit. Économise le temps de compilation et de liaison, avec une seule ligne de surcharge de code par instanciation de modèle.

1
Chris Tonkinson

Compiler avec g ++ en utilisant plusieurs cœurs 

Compiler avec g ++ en utilisant plusieurs cœurs

0
karlphillip

Habituellement, les parties les plus coûteuses de la compilation sont (a) la lecture des fichiers sources (TOUSd’eux) et (b) le chargement du compilateur en mémoire pour chaque fichier source.

Si vous avez 52 fichiers sources (.cc), chacun comprenant # comprend 47 fichiers #include (.h), vous allez charger le compilateur 52 fois et parcourir 2496 fichiers. En fonction de la densité des commentaires dans les fichiers, vous passerez peut-être beaucoup de temps à manger des caractères inutiles. (Dans une organisation que j'ai vue, les fichiers d'en-tête variaient entre 66% et 90% des commentaires, seuls 10% à 33% des fichiers étant "significatifs". La meilleure chose à faire pour améliorer la lisibilité de ces fichiers était de chaque dernier commentaire, ne laissant que le code.)

Jetez un long regard sur la façon dont votre programme est organisé physiquement. Voyez si vous pouvez combiner des fichiers source et simplifiez votre hiérarchie de fichiers #include.

Il y a des décennies, des entreprises comme IBM l'avaient bien compris et écrivaient leurs compilateurs afin que le compilateur puisse recevoir une liste de fichiers à compiler, pas un seul fichier, et que le compilateur ne soit chargé qu'une seule fois.

0
John R. Strohm