Comment détecter les fichiers inutiles #include dans un grand projet C++?

je travaille sur un grand projet C++ dans Visual Studio 2008, et il y a beaucoup de fichiers avec des directives #include inutiles. Parfois, les #include s ne sont que des artefacts et tout se compilera très bien avec eux supprimés, et dans d'autres cas, les classes pourraient être avancées et le #include pourrait être déplacé vers le fichier .cpp . Existe-t-il de bons outils pour détecter ces deux cas?

88
demandé sur LogicStuff 2008-09-16 20:38:54

20 réponses

bien qu'il ne révèlera pas les fichiers include non nécessaires, Visual studio a un paramètre /showIncludes (clic droit sur un fichier .cpp , Properties->C/C++->Advanced ) qui affichera un arbre de tous les fichiers inclus au moment de la compilation. Cela peut aider à identifier les fichiers qui ne devraient pas être inclus.

vous pouvez également jeter un coup d'oeil à l'idiome pimpl pour vous en tirer avec moins de dépendances de fichiers d'en-tête pour rendre plus facile de voir la fissure que vous pouvez enlever.

45
répondu Eclipse 2015-12-22 22:49:10

PC Peluches fonctionne très bien pour cela, et il trouve toutes sortes d'autres dingo problèmes pour vous 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 Lint visuel addin est plus facile à travailler avec. Même la version gratuite de Visual Lint aide. Mais donnez une chance à PC-Lint. Le configurer pour qu'il ne vous donne pas trop d'Avertissements prend un peu de temps, mais vous serez étonné de ce qu'il tourne jusqu'.

28
répondu Joe 2008-09-16 17:34:20

Il y a un Bruit outil comprennent ce que vous utilisez , qui vise à faire cela.

26
répondu Josh Kelley 2016-08-05 14:56:32

!!DISCLAIMER!! Je travaille sur un outil d'analyse statique Commerciale (Pas PC Lint). !!DISCLAIMER!!

il y a plusieurs problèmes avec une approche simple de non parsing:

1) Jeux De Surcharge:

il est possible qu'une fonction surchargée ait des déclarations provenant de fichiers différents. Il se peut que la suppression d'un fichier d'en-tête entraîne une surcharge différente plutôt qu'une erreur de compilation! Le résultat sera un silencieux changement sémantique qui peuvent être très difficiles à repérer par la suite.

2) modèles de spécialisation:

semblable à 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. Supprimer l'en-tête avec la spécialisation ne causera pas d'erreur de compilation, mais peut il en résulte un comportement non défini si cette spécialisation avait été choisie. (Voir: visibilité de la spécialisation de la fonction c++ )

comme le souligne "msalters", la réalisation d'une analyse complète du code permet également une analyse de l'utilisation de la classe. En vérifiant comment une classe est utilisée à travers un chemin spécifique de fichiers, il est possible que la définition de la classe (et donc toutes ses dépendances) puisse être supprimée complètement ou au moins déplacé à un niveau plus proche de la source principale dans l'arbre d'inclusion.

25
répondu Richard Corden 2017-05-23 12:18:04

Je ne connais aucun de ces 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.

dites que votre fichier source inclut un.h et B. h; a. h contient #define USE_FEATURE_X et B. h utilise #ifdef USE_FEATURE_X . Si #include "a.h" est commenté, votre fichier peut encore être compilé, mais ne pas faire ce que vous attendez. La détection de cette programmatically est non-triviale.

quel que soit l'outil utilisé ce besoin de connaître votre environnement de construction. Si a. h ressemble à:

#if defined( WINNT )
   #define USE_FEATURE_X
#endif

puis USE_FEATURE_X n'est défini que si WINNT est défini, de sorte que l'outil devrait 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.

10
répondu Graeme Perrow 2008-09-16 17:00:00

comme Timmermans, Je ne connais aucun outil pour ça. Mais j'ai connu des programmeurs qui ont écrit un script Perl (ou Python) pour essayer de commenter chaque ligne d'include une à une puis compiler chaque fichier.


il semble que maintenant Eric Raymond ait un outil pour ce .

Google cpplint.py a une règle" include what you use " (among many others), mais pour autant que je peut dire, pas de "comprendre seulement ce que vous utilisez."De la même façon, il peut être utile.

9
répondu Max Lybbert 2013-12-13 20:09:08

si vous êtes intéressé par ce sujet en général, vous pouvez jeter un oeil à Lakos' Large Scale C++ Software Design . C'est un peu désuet, mais il y a beaucoup de problèmes de "conception physique" comme trouver le minimum absolu de en-têtes qui doivent être inclus. Je n'ai jamais vraiment vu ce genre de chose discuter ailleurs.

5
répondu Adrian 2008-11-07 21:19:03

si vos fichiers d'en-tête commencent généralement par

#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#endif

(au lieu d'utiliser #pragma une fois) vous pouvez changer cela en:

#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#else 
#pragma message("Someheader.h superfluously included")
#endif

et puisque le compilateur affiche le nom du fichier cpp compilé, cela vous permettrait de savoir au moins quel fichier cpp fait que l'en-tête est introduit plusieurs fois.

4
répondu Sam 2008-09-21 00:40:49

vous pouvez construire un graphique include en utilisant C/C++ Include File Dependencies Watcher , et trouver visuellement des includes non nécessaires.

4
répondu Vladimir 2010-03-30 08:32:26

PC-Lint peut effectivement le faire. Une façon facile de le faire est de le configurer pour détecter juste les fichiers include inutilisés et ignorer tous les autres problèmes. C'est assez simple - pour activer juste le message 766 ("fichier D'en-tête non utilisé dans le module"), il suffit d'inclure les options-w0 +e766 sur la ligne de commande.

La même approche peut également être utilisé avec des messages tels que 964 ("fichier d'en-Tête ne sont pas directement utilisés dans le module") et 966 ("Indirectement inclus l'en-tête d'un fichier non utilisé dans module.)"

FWIW j'ai écrit à ce sujet plus en détail dans un billet de blog la semaine dernière à http://www.riverblade.co.uk/blog.php?archive=2008_09_01_archive.xml#3575027665614976318 .

3
répondu 2008-09-27 20:42:30

si vous cherchez à supprimer les fichiers inutiles #include afin de réduire les temps de construction, votre temps et votre argent pourraient être mieux dépensés parallèlement à votre processus de construction en utilisant 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 par tous signifie nettoyer vos directives #include et supprimer ces dépendances inutiles.

2
répondu bk1e 2008-09-17 06:02:15

commence par chaque fichier include, et assure-toi que chaque fichier include n'inclut que ce qui est nécessaire pour se compiler. Tous les fichiers include qui manquent alors pour les fichiers c++, peuvent être ajoutés aux fichiers C++ eux-mêmes.

pour chaque fichier include et source, commentez chaque fichier include un à la fois et voyez s'il compile.

c'est également une bonne idée de trier les fichiers include par ordre alphabétique, et si cela n'est pas possible, Ajouter un commentaire.

2
répondu selwyn 2008-09-17 16:55:16

ajout d'un ou des deux numéros suivants définit excluent souvent inutiles fichiers d'en-tête et peut s'améliorer considérablement compilez les temps en particulier si le code n'utilise pas les fonctions de L'API Windows.

#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN

voir http://support.microsoft.com/kb/166474

1
répondu Roger Nelson 2008-09-17 04:28:17

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 changer (des en-têtes de plate-forme, des en-têtes SDK externes, ou des pièces 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

aussi, bien qu'il soit peut-être trop tard pour votre projet, l'organisation de votre projet en sections et non de regrouper tous les en-têtes d'un grand en-tête principal est une bonne pratique, même si cela prend un peu de travail supplémentaire.

1
répondu anon6439 2008-09-17 11:12:51

si vous voulez travailler avec Eclipse CDT vous pouvez essayer http://includator.com pour optimiser votre structure d'inclusion. Cependant, Includator pourrait ne pas en savoir assez 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 dans CDT.

1
répondu PeterSom 2011-06-01 12:44:43

la dernière version de JetBrains IDE, CLion, affiche automatiquement (en gris) les inclusions qui ne sont pas utilisées dans le fichier courant.

il est également possible d'avoir la liste de tous les non utilisés comprend (et aussi les fonctions, les méthodes, etc...) à partir de l'IDE.

1
répondu Jean-Michaël Celerier 2015-04-26 21:08:59

certaines des réponses existantes indiquent que c'est difficile. C'est vrai, parce que vous avez besoin d'un compilateur complet pour détecter les cas dans lesquels une déclaration anticipée serait approprié. Vous ne pouvez pas analyser C++ sans savoir ce que les symboles signifient; la grammaire est tout simplement trop ambiguë pour cela. Vous devez savoir si un certain nom nomme une classe (pourrait être forward-declared) ou une variable (ne peut pas). Vous devez également être l'espace de noms courant.

0
répondu MSalters 2008-09-17 09:17:39

peut-être un peu tard, mais j'ai trouvé un script WebKit perl qui faisait exactement ce que vous vouliez. Il faudra s'adapter, je crois (Je ne connais pas bien perl), mais ça devrait faire l'affaire:

http://trac.webkit.org/browser/branches/old/safari-3-2-branch/WebKitTools/Scripts/find-extra-includes

(c'est une vieille branche parce que le tronc n'a plus le fichier)

0
répondu rubenvb 2010-06-30 14:47:08

S'il y a un en-tête particulier que vous pensez n'est plus nécessaire (dire chaîne.h), Vous pouvez commenter qui comprennent puis mettre ce sous tous les comprend:

#ifdef _STRING_H_
#  error string.h is included indirectly
#endif

bien sûr, vos en-têtes d'interface peuvent utiliser une convention #define différente pour enregistrer leur inclusion dans la mémoire du CPP. Ou pas de convention, auquel cas cette approche ne fonctionnera pas.

puis reconstruire. Il y a trois possibilités:

  • , Il s'appuie sur ok. chaîne.h n'a pas été compilé-critique, et l'inclure pour lui peut être enlevé.

  • #erreur de voyages. chaîne.g est inclus indirectement en quelque sorte Tu ne sais toujours pas si string.h est nécessaire. Si cela est nécessaire, vous directement #inclure (voir ci-dessous).

  • vous obtenez une autre erreur de compilation. chaîne.h était nécessaire et n'est pas inclus indirectement, donc l'inclusion était correcte pour commencer avec.

notez que selon l'inclusion indirecte lorsque votre .h ou .C Utilisations directes l'autre .h est presque certainement un bug: vous êtes en effet promettant que votre le code ne requerra cet en-tête que si un autre en-tête que vous utilisez l'exige, ce qui n'est probablement pas ce que vous voulez dire.

les mises en garde mentionnées dans d'autres réponses au sujet des en-têtes qui modifient le comportement plutôt que de déclarer des choses qui causent construire les échecs s'appliquent également ici.

0
répondu Britton Kerin 2014-11-10 22:12:07