Je travaille sur un gros projet C ++ dans Visual Studio 2008, et il y a beaucoup de fichiers avec des #include
directives inutiles . Parfois, les #include
s ne sont que des artefacts et tout se compilera correctement s'ils sont supprimés, et dans d'autres cas, les classes peuvent être déclarées en avant et le #include peut être déplacé vers le .cpp
fichier. Existe-t-il de bons outils pour détecter ces deux cas?
la source
PC Lint fonctionne très bien pour cela, et il trouve pour vous toutes sortes d'autres problèmes loufoques aussi. Il a des options de ligne de commande qui peuvent être utilisées pour créer des outils externes dans Visual Studio, mais j'ai trouvé que le complément Visual Lint est plus facile à utiliser. Même la version gratuite de Visual Lint aide. Mais essayez PC-Lint. Le configurer pour qu'il ne vous donne pas trop d'avertissements prend un peu de temps, mais vous serez étonné de voir ce que cela donne.
la source
Il existe un nouvel outil basé sur Clang, include-what-you-use , qui vise à le faire.
la source
!!AVERTISSEMENT!! Je travaille sur un outil commercial d'analyse statique (pas PC Lint). !!AVERTISSEMENT!!
Il y a plusieurs problèmes avec une approche simple sans analyse:
1) Ensembles de surcharge:
Il est possible qu'une fonction surchargée ait des déclarations provenant de différents fichiers. Il se peut que la suppression d'un fichier d'en-tête entraîne le choix d'une surcharge différente plutôt qu'une erreur de compilation! Le résultat sera un changement silencieux de sémantique qui peut être très difficile à retracer par la suite.
2) Spécialisations de modèles:
Similaire à l'exemple de surcharge, si vous avez des spécialisations partielles ou explicites pour un modèle, vous voulez qu'elles soient toutes visibles lorsque le modèle est utilisé. Il se peut que les spécialisations pour le modèle principal se trouvent dans des fichiers d'en-tête différents. La suppression de l'en-tête avec la spécialisation ne provoquera pas d'erreur de compilation, mais peut entraîner un comportement non défini si cette spécialisation avait été sélectionnée. (Voir: Visibilité de la spécialisation des modèles de la fonction C ++ )
Comme indiqué par «msalters», effectuer une analyse complète du code permet également d'analyser l'utilisation des classes. En vérifiant comment une classe est utilisée via un chemin spécifique de fichiers, il est possible que la définition de la classe (et donc de toutes ses dépendances) puisse être supprimée complètement ou au moins déplacée à un niveau plus proche de la source principale dans l'inclusion arbre.
la source
Je ne connais pas de tels outils, et j'ai pensé à en écrire un dans le passé, mais il s'avère que c'est un problème difficile à résoudre.
Supposons que votre fichier source comprend ah et bh; ah contient
#define USE_FEATURE_X
et bh utilise#ifdef USE_FEATURE_X
. Si#include "a.h"
est mis en commentaire, votre fichier peut toujours être compilé, mais peut ne pas faire ce que vous attendez. Détecter cela par programme n'est pas trivial.Quel que soit l'outil utilisé, il faudrait également connaître votre environnement de construction. Si ah ressemble à:
Alors
USE_FEATURE_X
n'est défini que siWINNT
est défini, de sorte que l'outil aurait besoin de savoir quelles directives sont générées par le compilateur lui-même ainsi que celles qui sont spécifiées dans la commande de compilation plutôt que dans un fichier d'en-tête.la source
Comme Timmermans, je ne connais aucun outil pour cela. Mais j'ai connu des programmeurs qui ont écrit un script Perl (ou Python) pour essayer de commenter chaque ligne d'inclusion une à la fois, puis compiler chaque fichier.
Il semble que maintenant Eric Raymond dispose d'un outil pour cela .
Le fichier cpplint.py de Google a une règle "inclure ce que vous utilisez" (parmi beaucoup d'autres), mais pour autant que je sache, non "inclure uniquement ce que vous utilisez". Même ainsi, cela peut être utile.
la source
Si vous êtes intéressé par ce sujet en général, vous voudrez peut-être consulter la conception de logiciels C ++ à grande échelle de Lakos . Il est un peu daté, mais aborde de nombreux problèmes de "conception physique", comme trouver le minimum absolu d'en-têtes à inclure. Je n'ai pas vraiment vu ce genre de chose discuté ailleurs.
la source
Essayez Inclure Manager . Il s'intègre facilement dans Visual Studio et visualise vos chemins d'inclusion, ce qui vous aide à trouver des éléments inutiles. En interne, il utilise Graphviz mais il existe de nombreuses autres fonctionnalités intéressantes. Et bien qu'il s'agisse d'un produit commercial, son prix est très bas.
la source
Vous pouvez créer un graphique d'inclusion à l'aide de l' observateur de dépendances de fichiers d' inclusion C / C ++ et rechercher visuellement les inclusions inutiles.
la source
Si vos fichiers d'en-tête commencent généralement par
(au lieu d'utiliser #pragma une fois), vous pouvez le changer en:
Et puisque le compilateur affiche le nom du fichier cpp en cours de compilation, cela vous permettrait de savoir au moins quel fichier cpp provoque l'ajout de l'en-tête plusieurs fois.
la source
A.h
etB.h
que les deux dépendezC.h
et que vous incluezA.h
etB.h
, parce que vous avez besoin à la fois, vous allez inclureC.h
deux fois, mais c'est très bien, parce que le compilateur sauter la deuxième fois et si vous ne l' avez pas, vous auriez à retenir à toujours inclureC.h
avantA.h
ouB.h
se retrouver dans des inclusions beaucoup plus inutiles.PC-Lint peut effectivement le faire. Un moyen simple de le faire est de le configurer pour détecter uniquement les fichiers d'inclusion inutilisés et ignorer tous les autres problèmes. C'est assez simple - pour activer uniquement le message 766 ("Fichier d'en-tête non utilisé dans le module"), incluez simplement les options -w0 + e766 sur la ligne de commande.
La même approche peut également être utilisée avec des messages associés tels que 964 ("Fichier d'en-tête non directement utilisé dans le module") et 966 ("Fichier d'en-tête indirectement inclus non utilisé dans le module").
FWIW J'ai écrit à ce sujet plus en détail dans un article de blog la semaine dernière à http://www.riverblade.co.uk/blog.php?archive=2008_09_01_archive.xml#3575027665614976318 .
la source
Si vous cherchez à supprimer des
#include
fichiers inutiles afin de réduire les temps de construction, votre temps et votre argent pourraient être mieux dépensés à paralléliser votre processus de construction à l'aide de cl.exe / MP , make -j , Xoreax IncrediBuild , distcc / icecream , etc.Bien sûr, si vous avez déjà un processus de construction parallèle et que vous essayez toujours de l'accélérer, alors nettoyez vos
#include
directives et supprimez ces dépendances inutiles.la source
Commencez par chaque fichier d'inclusion et assurez-vous que chaque fichier d'inclusion n'inclut que ce qui est nécessaire pour se compiler. Tous les fichiers d'inclusion qui sont alors manquants pour les fichiers C ++ peuvent être ajoutés aux fichiers C ++ eux-mêmes.
Pour chaque fichier d'inclusion et source, commentez chaque fichier d'inclusion un par un et voyez s'il se compile.
Il est également judicieux de trier les fichiers d'inclusion par ordre alphabétique, et lorsque ce n'est pas possible, ajoutez un commentaire.
la source
L'ajout d'un ou des deux #defines suivants exclura les fichiers d'en-tête souvent inutiles et peut considérablement améliorer les temps de compilation, en particulier si le code n'utilise pas les fonctions API Windows.
Voir http://support.microsoft.com/kb/166474
la source
Si vous ne l'êtes pas déjà, l'utilisation d'un en-tête précompilé pour inclure tout ce que vous n'allez pas modifier (en-têtes de plate-forme, en-têtes de SDK externes ou parties statiques déjà terminées de votre projet) fera une énorme différence dans les temps de construction.
http://msdn.microsoft.com/en-us/library/szfdksca(VS.71).aspx
De plus, bien qu'il soit peut-être trop tard pour votre projet, organiser votre projet en sections et ne pas regrouper tous les en-têtes locaux dans un seul grand en-tête principal est une bonne pratique, même si cela demande un peu de travail supplémentaire.
la source
Si vous travaillez avec Eclipse CDT, vous pouvez essayer http://includator.com pour optimiser votre structure d'inclusion. Cependant, Includator peut ne pas en savoir suffisamment sur les inclusions prédéfinies de VC ++ et la configuration de CDT pour utiliser VC ++ avec des inclusions correctes n'est pas encore intégrée à CDT.
la source
Le dernier IDE Jetbrains, CLion, affiche automatiquement (en gris) les inclusions qui ne sont pas utilisées dans le fichier actuel.
Il est également possible d'avoir la liste de tous les includes inutilisés (ainsi que les fonctions, méthodes, etc ...) de l'EDI.
la source
Certaines des réponses existantes indiquent que c'est difficile. C'est en effet vrai, car vous avez besoin d'un compilateur complet pour détecter les cas dans lesquels une déclaration directe serait appropriée. Vous ne pouvez pas analyser C ++ sans savoir ce que signifient les symboles; la grammaire est simplement trop ambiguë pour cela. Vous devez savoir si un certain nom nomme une classe (peut être déclarée en avant) ou une variable (impossible). En outre, vous devez être conscient de l'espace de noms.
la source
Peut-être un peu tard, mais j'ai trouvé une fois un script perl WebKit qui faisait exactement ce que vous vouliez. Il faudra quelques adaptations je crois (je ne connais pas très bien perl), mais cela devrait faire l'affaire:
http://trac.webkit.org/browser/branches/old/safari-3-2-branch/WebKitTools/Scripts/find-extra-includes
(il s'agit d'une ancienne branche car le tronc n'a plus le fichier)
la source
S'il y a un en-tête particulier qui ne vous semble plus nécessaire (par exemple string.h), vous pouvez commenter cet include, puis le mettre sous tous les includes:
Bien sûr, les en-têtes de votre interface peuvent utiliser une convention #define différente pour enregistrer leur inclusion dans la mémoire CPP. Ou pas de convention, auquel cas cette approche ne fonctionnera pas.
Puis reconstruisez. Il existe trois possibilités:
Il construit bien. string.h n'était pas critique pour la compilation, et l'inclusion correspondante peut être supprimée.
Les voyages #error. string.g a été inclus indirectement. Vous ne savez toujours pas si string.h est requis. S'il est nécessaire, vous devez directement # l'inclure (voir ci-dessous).
Vous obtenez une autre erreur de compilation. string.h était nécessaire et n'est pas inclus indirectement, donc l'inclusion était correcte au départ.
Notez que dépendre de l'inclusion indirecte lorsque votre .h ou .c utilise directement un autre .h est presque certainement un bogue: vous promettez en effet que votre code ne nécessitera cet en-tête que tant qu'un autre en-tête que vous utilisez le requiert, ce n'est probablement pas ce que vous vouliez dire.
Les mises en garde mentionnées dans d'autres réponses sur les en-têtes qui modifient le comportement plutôt que la déclaration de choses qui provoquent des échecs de construction s'appliquent également ici.
la source