Question

Toutes les pratiques recommandées pour nettoyer " en-tête spaghetti " ce qui cause extrêmement temps de compilation lents (Linux / Unix)?

Existe-t-il un équivalent à "#pragma une fois"? avec GCC?
(messages contradictoires trouvés à ce sujet)

Merci.

Était-ce utile?

La solution

En supposant que vous maîtrisiez " inclure des gardes " (#ifdef au début de l’en-tête ..), un autre moyen d’accélérer le temps de compilation consiste à utiliser des protections d’inclusion externes. Il a été discuté dans " Conception de logiciels à grande échelle C ++ " ;. L’idée est que les protecteurs d’inclusion classiques, contrairement à #pragma une fois, ne vous épargnent pas l’analyse du préprocesseur requise pour ignorer l’en-tête à partir de la deuxième fois (c’est-à-dire qu’il doit encore analyser et rechercher le début et la fin de la protection d’inclusion. les gardes d'inclusion externes vous placez le # ifdef autour de la ligne #include elle-même.

Cela ressemble donc à ceci:

#ifndef MY_HEADER
#include "myheader.h"
#endif

et bien sûr, dans le fichier H, vous avez le classique garde inclus

#ifndef MY_HEADER
#define MY_HEADER

// content of header

#endif

De cette manière, le fichier myheader.h n'est même pas ouvert / analysé par le préprocesseur, ce qui peut vous faire gagner beaucoup de temps dans les grands projets, en particulier lorsque les fichiers d'en-tête sont placés sur des emplacements distants partagés, comme ils le font parfois. / p>

encore une fois, tout est dans ce livre. hth

Autres conseils

Si vous souhaitez effectuer un nettoyage complet et avoir le temps de le faire, la meilleure solution consiste à supprimer tous les #includes de tous les fichiers (à l'exception des fichiers évidents, par exemple abc.h dans abc.cpp), puis à les compiler. le projet. Ajoutez la déclaration ou l'en-tête nécessaire pour corriger la première erreur, puis répétez l'opération jusqu'à ce que vous vous complétiez correctement.

Cela ne résout pas les problèmes sous-jacents pouvant entraîner des problèmes d'inclusion, mais garantit que les seuls inclus sont ceux qui sont obligatoires.

J'ai lu que GCC considérait #pragma une fois comme obsolète, bien que même # pragma une fois ne puisse faire que tant pour accélérer les choses.

Pour essayer de démêler les spaghettis #include , vous pouvez consulter doxygen . Il devrait être capable de générer des graphiques d'en-têtes inclus, ce qui peut vous donner un avantage en termes de simplification. Je ne me souviens pas des détails, mais les fonctions graphiques peuvent vous obliger à installer GraphViz et à dire à doxygen le chemin où il peut trouver le fichier dotty.exe de GraphViz.

Une autre approche que vous pourriez envisager si le temps de compilation est votre principale préoccupation consiste à configurer les en-têtes précompilés . .

J'ai lu l'autre jour à propos d'une astuce intéressante pour réduire les dépendances d'en-tête: écrivez un script qui

  • trouver toutes les instructions #include
  • supprime une instruction à la fois et recompile
  • si la compilation échoue, ajoutez l'instruction include dans

À la fin, vous obtiendrez, espérons-le, le minimum d'inclusions requises dans votre code. Vous pouvez écrire un script similaire qui réorganise les inclus pour savoir s’ils sont autonomes ou exigent que d’autres en-têtes soient inclus avant eux (incluez d’abord l’en-tête, voyez si la compilation échoue, signalez-le). Cela devrait permettre de nettoyer votre code.

Quelques notes supplémentaires:

  • Les compilateurs modernes (parmi eux gcc) reconnaissent les gardes d'en-tête et optimisent de la même manière que pragma une fois, en n'ouvrant le fichier qu'une fois.
  • Une fois, pragma peut poser problème lorsque le même fichier a des noms différents dans le système de fichiers (c'est-à-dire avec des liens symboliques)

  • gcc prend en charge #pragma une fois, mais l’appelle "obsolète"
  • Une fois, pragma n'est pas supporté par tous les compilateurs, et ne fait pas partie du standard C

  • non seulement les compilateurs peuvent être problématiques. Des outils comme Incredibuild ont également des problèmes avec #pragma une fois

Richard avait un peu raison (pourquoi sa solution a-t-elle été notée?).

Quoi qu'il en soit, tous les en-têtes C / C ++ doivent utiliser des protections d'inclusion internes.

Ceci dit, soit:

1 - Votre code hérité n’est plus vraiment mis à jour et vous devez utiliser des en-têtes pré-compilés (qui sont un hack, mais bon ... Votre besoin est d’accélérer votre compilation, pas de refactoriser du code non maintenu)

2 - Votre ancien code est toujours en vigueur. Vous utiliserez ensuite les en-têtes précompilés et / ou les gardes / gardes externes pour une solution temporaire, mais vous devrez au final supprimer tous vos inclus, un .C ou .CPP à la fois, et les compiler. C ou un fichier .CPP, corrigeant leurs inclus avec des déclarations en aval ou si nécessaire (ou même en découpant un plus gros include en un plus petit pour être sûr que chaque fichier .C ou .CPP obtiendra uniquement les en-têtes dont il a besoin). Quoi qu’il en soit, tester et supprimer les includes obsolètes fait partie de la maintenance d’un projet, donc ...

Ma propre expérience avec les en-têtes précompilés n’était pas vraiment bonne, car le compilateur ne trouvait pas le symbole défini une fois dans son temps, et j’ai donc essayé de procéder à un "nettoyage / reconstruction" complet. pas l'en-tête précompilé qui était obsolète. Donc, je suppose que je l’utiliserai pour les bibliothèques externes que vous ne toucherez même pas (comme les en-têtes STL, C API, Boost, peu importe). Pourtant, ma propre expérience était avec Visual C ++ 6, donc je suppose (ils espèrent?), Ils ont bien compris, maintenant.

Maintenant, une dernière chose: les en-têtes devraient toujours être autosuffisants. Cela signifie que si l'inclusion d'en-têtes dépend de l'ordre d'inclusion, vous avez un problème. Par exemple, si vous pouvez écrire:

#include "AAA.hpp"
#include "BBB.hpp"

Mais pas:

#include "BBB.hpp"
#include "AAA.hpp"

Parce que BBB dépend de AAA, tout ce que vous avez est une dépendance que vous n'avez jamais reconnue dans le code. Ne pas le reconnaître avec une définition ne fera que rendre votre compilation un cauchemar. BBB devrait également inclure AAA (même si cela pourrait être un peu plus lent: en fin de compte, les déclarations en aval seront de toute façon des nettoyages inutiles, alors vous devriez avoir une minuterie de compilation plus rapide).

Utilisez un ou plusieurs de ceux-ci pour accélérer le temps de construction

  1. Utiliser les en-têtes précompilés
  2. Utiliser un mécanisme de mise en cache (scons par exemple)
  3. Utiliser un système de compilation distribué (distcc, Incredibuild ($))

Dans les en-têtes: incluez les en-têtes uniquement si vous ne pouvez pas utiliser la déclaration, mais incluez toujours les fichiers dont vous avez besoin (les dépendances d'inclusion sont néfastes!).

Comme indiqué dans l’autre réponse, vous devez absolument utiliser les déclarations en aval chaque fois que cela est possible. À ma connaissance, GCC n’a rien d’équivalent à #pragma une seule fois, c’est pourquoi je reste fidèle à l’ancien style de garde inclus.

Merci pour les réponses, mais la question concerne le code existant, qui inclut les instructions strictes "Inclure la commande". etc. La question est de savoir s’il existe des outils / scripts pour clarifier ce qui se passe réellement.

Les gardes d'en-tête ne sont pas la solution car ils n'empêchent pas le compilateur de lire tout le fichier, encore et encore et ...

PC-Lint contribuera grandement à nettoyer les en-têtes de spaghettis. En outre, cela résoudra d’autres problèmes, comme des variables non initialisées, etc.

Comme onebyone.livejournal.com a commenté dans une réponse à votre question, certains compilateurs prennent en charge inclut l'optimisation de la protection , que la page que j'ai liée définit comme suit:

  

L’optimisation d’inclusion protège s’effectue lorsqu'un compilateur reconnaît l’idiome interne d’inclusion décrit ci-dessus et prend des mesures pour éviter d’ouvrir le fichier plusieurs fois. Le compilateur peut examiner un fichier d'inclusion, supprimer des commentaires et des espaces, et déterminer si l'ensemble du fichier se trouve dans les gardes d'inclusion. Si c'est le cas, il stocke le nom de fichier et inclut la condition de garde dans une carte. La prochaine fois que le compilateur est invité à inclure le fichier, il peut vérifier la condition d'inclusion et décider s'il doit ou non ignorer le fichier ou l'inclure sans avoir besoin de l'ouvrir.

Là encore, vous avez déjà répondu que les protecteurs d'inclusion externes ne constituaient pas la réponse à votre question. Pour démêler les fichiers d'en-tête qui doivent être inclus dans un ordre spécifique, je suggérerais ce qui suit:

  • Chaque fichier .c ou .cpp doit tout d'abord #include le fichier .h correspondant, puis le fichier. le reste de ses directives #include doit être trié par ordre alphabétique. Vous obtiendrez généralement des erreurs de construction lorsque cela coupera les dépendances non déclarées entre les fichiers d'en-tête.
  • Si vous avez un fichier d'en-tête qui définit les typefefs globaux pour les types de base ou les directives globales #define utilisées pour la plupart du code, chaque fichier .h doit < code> #include ce fichier en premier, et le reste de ses directives #include doit être trié par ordre alphabétique.
  • Lorsque ces modifications génèrent des erreurs de compilation, vous devrez généralement ajouter une dépendance explicite d'un fichier d'en-tête à un autre, sous la forme d'un #include .
  • Lorsque ces modifications ne provoquent pas d’erreurs de compilation, elles peuvent entraîner des modifications de comportement. J'espère que vous avez une sorte de suite de tests que vous pouvez utiliser pour vérifier les fonctionnalités de votre application.

Il semble également qu’une partie du problème réside dans le fait que les versions incrémentielles sont beaucoup plus lentes qu’elles ne devraient l’être. Cette situation peut être améliorée avec des déclarations anticipées ou un système de build distribué, comme d'autres l'ont souligné.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top