Frage

Ich arbeite an einem großen C++-Projekt in Visual Studio 2008 und es gibt viele unnötige Dateien #include Richtlinien.Manchmal die #includes sind nur Artefakte und alles lässt sich problemlos kompilieren, wenn sie entfernt werden. In anderen Fällen könnten Klassen vorwärts deklariert und #include in die verschoben werden .cpp Datei.Gibt es gute Tools zur Erkennung dieser beiden Fälle?

War es hilfreich?

Lösung

Es ist zwar nicht nicht benötigte Include-Dateien offenbaren wird, Visual Studio eine Einstellung /showIncludes hat (Rechtsklick auf eine Datei .cpp, Properties->C/C++->Advanced) dieser ausgeben wird ein Baum aller Dateien während der Kompilierung enthalten. Dies kann bei der Identifizierung von Dateien helfen, die nicht aufgenommen werden sollten müssen.

Sie können auch einen Blick auf dem Pimpl Idiom nehmen Sie mit weniger Header-Datei Abhängigkeiten weg kommen zu lassen, um es den cruft zu erleichtern zu sehen, die Sie entfernen können.

Andere Tipps

PC Lint ganz gut funktioniert, und es findet alle möglichen anderen für Sie zu doof Probleme. Es verfügt über Kommandozeilen-Optionen, die verwendet werden können Externe Tools in Visual Studio zu erstellen, aber ich habe festgestellt, dass die Visueller Lint Addin ist einfacher, mit zu arbeiten. Auch die kostenlose Version von Visual Lint hilft. Aber geben Sie PC-Lint einen Schuss. Konfigurieren es so dass es nicht zu viele Warnungen geben braucht ein wenig Zeit, aber Sie werden erstaunt sein, was es auftaucht.

Es gibt ein neues Clang-basiertes Tool, umfassen-was- Sie verwenden , dass dies tun soll.

!! HAFTUNGSAUSSCHLUSS !! Ich arbeite auf einem kommerziellen statischen Analyse-Tool (nicht PC Lint). !! HAFTUNGSAUSSCHLUSS !!

Es gibt einige Probleme mit einem einfachen, nicht-Parsing-Ansatz:

1) Überlast Sets:

Es ist möglich, dass eine überladene Funktionsdeklarationen hat, die aus verschiedenen Dateien kommen. Es könnte sein, dass ein Header-Datei führt zu einer unterschiedlichen Überlastung Entfernen eher gewählt wird, als ein Compiler-Fehler! Das Ergebnis wird eine stille Veränderung in der Semantik, die sehr schwierig sein kann, danach auf der Spur.

2) Template Spezialisierungen:

ähnlich wie bei der Überlastung Beispiel, wenn Sie haben teilweise oder explizite Spezialisierungen für eine Vorlage, die Sie wollen, dass sie alle sichtbar sein, wenn die Vorlage verwendet wird. Es könnte sein, dass Spezialisierungen für die primäre Vorlage wird in verschiedenen Header-Dateien. Das Entfernen des Header mit der Spezialisierung nicht ein Compiler-Fehler verursachen, aber in nicht definiertem Verhalten führen kann, wenn diese Spezialisierung würde ausgewählt wurde. (Siehe: Sichtbarkeit der Template-Spezialisierung von C ++ Funktion )

Wie ‚msalters‘ wies darauf hin, eine vollständige Analyse des Codes durchführen kann auch für die Analyse von Klasse-Nutzung. Durch die Überprüfung, wie eine Klasse allerdings einen bestimmten Pfad von Dateien verwendet wird, ist es möglich, dass die Definition der Klasse (und damit alle seiner dependnecies) vollständig entfernt werden kann, oder zumindest auf ein Niveau bewegt näher an der Hauptquelle im Include Baum.

Ich weiß nicht, von solchen Tools, und ich habe darüber nachgedacht, eine in der Vergangenheit zu schreiben, aber es stellt sich heraus, dass dies ein schwieriges Problem zu lösen.

Sagen Sie Ihre Quelldatei A. h und b.h enthält; A. h enthält #define USE_FEATURE_X und b.h verwendet #ifdef USE_FEATURE_X. Wenn #include "a.h" Kommentar gesetzt ist, können Sie Ihre Datei noch kompilieren, kann aber nicht tun, was Sie erwarten. Erkennen dieser programmatisch ist nicht trivial.

Was auch immer Werkzeug tut dies müßte auch Ihre Build-Umgebung kennen zu lernen. Wenn A. h wie folgt aussieht:

#if defined( WINNT )
   #define USE_FEATURE_X
#endif

Dann wird USE_FEATURE_X nur definiert, wenn WINNT definiert ist, so dass das Werkzeug würde müssen wissen, welche Richtlinien durch den Compiler selbst erzeugt werden sowie welche sind in der Kompilierungsbefehl angegeben anstatt in einer Header-Datei.

Wie Timmermans, bin ich mit Werkzeugen für diese nicht vertraut. Aber ich habe bekannt Programmierer, die ein Perl (oder Python) Skript geschrieben, um zu versuchen jeweils Linie einer nach dem anderen zu kommentieren und dann jede Datei kompilieren.


Es scheint, dass jetzt Eric Raymond hat ein Werkzeug für diese .

Google cpplint.py hat eine „umfassen, was Sie verwenden“-Regel (unter vielen anderen), aber soweit ich das beurteilen kann, keine‚enthalten nur , was Sie verwenden.‘ Trotzdem kann es sinnvoll sein.

Wenn Sie in diesem Thema im Allgemeinen interessiert sind, möchten Sie vielleicht Lakos check out Large Scale C ++ Software Design . Es ist ein bisschen veraltet, aber geht in eine Menge „physische Design“ Themen wie das absolute Minimum von Headern zu finden, die einbezogen werden müssen. Ich habe nicht wirklich so etwas gesehen anderswo diskutiert.

Include-Manager einen Versuch . Es integriert sich leicht in Visual Studio und visualisiert Ihre Wege umfassen die Ihnen hilft, unnötige Sachen zu finden. Intern verwendet es Graphviz aber es gibt viele weitere coole Features. Und obwohl es ist ein kommerzielles Produkt es einen sehr niedrigen Preis hat.

können Sie bauen eine Include-Graph mit C / C ++ Dateiabhängigkeiten Watcher einschließen, und finden Sie nicht benötigte umfasst visuell.

Wenn Sie Ihre Header-Dateien mit der Regel beginnen

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

(im Gegensatz zur Verwendung von Pragma einmal) Sie könnte die ändern zu:

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

Und da der Compiler den Namen der CPP-Datei ausgibt, kompiliert wird, das würde Sie wissen lassen, zumindest die CPP-Datei den Header verursachen in mehrfach gebracht werden.

PC-Lint kann dies tatsächlich tun. Eine einfache Möglichkeit, dies zu tun ist, um es zu konfigurieren nur ungenutzt Include-Dateien zu erkennen und alle anderen Probleme zu ignorieren. Das ist ziemlich einfach -. Nur Meldung 766 ( „Header-Datei nicht verwendet in Modul“) zu ermöglichen, sind nur die Optionen w0 + e766 auf der Kommandozeile

Der gleiche Ansatz kann auch mit verwandten Nachrichten wie 964 ( „Header-Datei nicht direkt verwendet in Modul“) und 966 ( „Indirekt enthalten Header-Datei nicht verwendeten in Modul“).

verwendet werden

FWIW schrieb ich über diese im Detail in einer Blog-Post letzte Woche unter http://www.riverblade.co.uk/blog.php?archive=2008_09_01_archive.xml#3575027665614976318 .

Wenn Sie schauen, unnötige #include Dateien zu entfernen, um Bauzeiten zu verringern, Ihre Zeit und Geld könnte besser ausgegeben werden Ihren Build-Prozess Parallelisierung mit cl.exe / MP , make -j , Xoreax IncrediBuild , distcc / Eis , etc.

Natürlich, wenn Sie bereits über einen parallel Build-Prozess haben, und Sie sind immer noch versuchen, es zu beschleunigen, dann mit allen Mitteln aufzuräumen Ihre #include Richtlinien und entfernen Sie diese unnötigen Abhängigkeiten.

Starten Sie mit jeder Datei enthalten, und stellen Sie sicher, dass jeweils nur Datei enthält, was notwendig ist, selbst zu kompilieren. Alle Include-Dateien, die dann für die C ++ Dateien fehlen, kann an den C ++ hinzugefügt werden Dateien selbst.

Für jede umfassen und Quelldatei, kommentieren Sie jede einen nach dem anderen Datei enthalten und sehen, ob es kompiliert wird.

Es ist auch eine gute Idee, die Dateien alphabetisch zu sortieren sind, und wo dies nicht möglich ist, einen Kommentar abzugeben.

Das Hinzufügen eines oder beide der folgenden #defines ausschließen oft unnötige Header-Dateien und kann wesentlich verbessern kompilieren Zeiten vor allem, wenn der Code, der nicht mit dem Windows-API-Funktionen wird.

#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN

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

Wenn Sie nicht bereits sind, eine vorkompilierte Header verwenden, alles zu umfassen, die Sie nicht ändern werden (Plattform-Header, externe SDK-Header oder statische bereits abgeschlossene Stücke Ihres Projektes) wird einen großen Unterschied in Bauzeiten machen .

http://msdn.microsoft.com/ en-us / library / szfdksca (VS.71) aspx

Auch, obwohl es für Ihr Projekt zu spät sein kann, Ihr Projekt in Abschnitte zu organisieren und nicht alle lokalen Header zu einem großen Haupt-Header eines Topf zu werfen ist eine gute Praxis, auch wenn es eine wenig zusätzliche Arbeit nimmt.

Wenn Sie mit Eclipse CDT funktionieren würde könnte man versuchen, http://includator.com zu optimieren Ihre Struktur umfassen. Allerdings Includator vielleicht weiß nicht genug über VC ++ 's vordefinierten enthält und CDT Einrichtung VC ++ zu verwenden mit der richtigen enthält in CDT noch nicht gebaut.

Das neueste Jetbrains IDE, CLION, zeigt automatisch (in grau) das enthält, die nicht in der aktuellen Datei verwendet werden.

Es ist auch möglich, die Liste der haben, alle nicht verwendeten enthält (und auch Funktionen, Methoden, etc ...) von der IDE.

Einige der vorhandenen Antworten erklären, dass es schwer ist. Das ist in der Tat wahr, weil Sie einen vollständigen Compiler benötigen, um die Fälle, in denen eine Vorwärts-Erklärung angemessen wäre zu erkennen. Sie kann nicht C ++ analysieren, ohne zu wissen, was die Symbole bedeuten; die Grammatik ist einfach zu vieldeutig dafür. Sie müssen wissen, ob ein bestimmten Namen Namen eine Klasse (voraus erklärt werden könnte) oder eine Variable (nicht kann). Außerdem müssen Sie sein Namespace-aware.

Vielleicht ein wenig spät, aber ich fand einmal einen WebKit Perl-Skript, das nur getan, was Sie wollten. Es werde einige Adaptierungs brauchen Ich glaube (ich bin nicht gut in Perl auskennt), aber es sollte es tun:

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

(dies ist ein alter Zweig, weil Stamm mehr die Datei nicht hat)

Wenn es einen bestimmten Header gibt, den Sie glauben, dass nicht mehr benötigt wird (sagen Sie String.h), können Sie sich ausgeben, die enthalten, dann geben Sie dies unter alles ein, was Folgendes enthält:

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

Natürlich verwenden Ihre Schnittstellenheader möglicherweise eine andere #Define Convention, um ihre Aufnahme in den CPP -Speicher aufzuzeichnen.Oder keine Konvention, in diesem Fall funktioniert dieser Ansatz nicht.

Dann neu aufbauen.Es gibt drei Möglichkeiten:

  • Es baut sich gut auf.String.h wurde nicht kompilekritisch und das Einfügen für es kann entfernt werden.

  • Der #Fehler löst aus.String.g wurde indirekt irgendwie eingeschlossen, dass Sie immer noch nicht wissen, ob String.h erforderlich ist.Wenn dies erforderlich ist, sollten Sie es direkt #Include (siehe unten).

  • Es wird ein anderer Kompilierungsfehler angezeigt.String.h wurde benötigt und wurde nicht indirekt aufgenommen, sodass das Einfügen von Anfang an korrekt war.

Beachten Sie, dass abhängig von der indirekten Einbeziehung, wenn Ihr .h oder .c direkt einen anderen verwendet. H ist mit ziemlicher Sicherheit ein Fehler:Sie versprechen, dass Ihr Code diesen Header nur erfordert, solange ein anderer Header, den Sie verwenden, ihn benötigt, was wahrscheinlich nicht das ist, was Sie gemeint haben.

Die in anderen Antworten über Header erwähnten Vorbehalte, die das Verhalten eher verändern, die auch hier zu deklarieren, die zu Aufbauversagen führen, gelten auch hier.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top