Ich weiß, dass PC-Lint Sie über Header informieren kann, die enthalten sind, aber nicht verwendet werden. Gibt es andere Tools, die dies tun können, vorzugsweise unter Linux?
Wir haben eine große Codebasis, in der sich in den letzten 15 Jahren viele Funktionen verschoben haben, aber die verbleibenden # include-Direktiven werden selten entfernt, wenn die Funktionalität von einer Implementierungsdatei in eine andere verschoben wird, was uns zu diesem Zeitpunkt ein ziemlich gutes Durcheinander hinterlässt. Ich kann natürlich mühsam alle # include-Direktiven entfernen und mir vom Compiler mitteilen lassen, welche Direktiven wieder eingeschlossen werden sollen, aber ich würde das Problem lieber umgekehrt lösen - die nicht verwendeten finden - anstatt eine Liste der verwendeten neu zu erstellen.
quelle
Antworten:
HAFTUNGSAUSSCHLUSS: Mein Tagesjob besteht darin, für ein Unternehmen zu arbeiten, das statische Analysewerkzeuge entwickelt.
Es würde mich wundern, wenn die meisten (wenn nicht alle) statischen Analysetools keine Form der Überprüfung der Header-Nutzung hätten. Sie können diese Wikipedia-Seite verwenden, um eine Liste der verfügbaren Tools abzurufen und die Unternehmen per E-Mail zu fragen.
Einige Punkte, die Sie bei der Bewertung eines Tools berücksichtigen sollten:
Bei Funktionsüberladungen möchten Sie, dass alle Header mit Überladungen sichtbar sind, nicht nur der Header, der die Funktion enthält, die durch die Überlastungsauflösung ausgewählt wurde:
// f1.h void foo (char); // f2.h void foo (int); // bar.cc #include "f1.h" #include "f2.h" int main () { foo (0); // Calls 'foo(int)' but all functions were in overload set }
Wenn Sie den Brute-Force-Ansatz wählen, entfernen Sie zuerst alle Header und fügen Sie sie erneut hinzu, bis sie kompiliert werden. Wenn zuerst 'f1.h' hinzugefügt wird, wird der Code kompiliert, aber die Semantik des Programms wurde geändert.
Eine ähnliche Regel gilt, wenn Sie Teil- und Spezialisierungen haben. Es spielt keine Rolle, ob die Spezialisierung ausgewählt ist oder nicht, Sie müssen sicherstellen, dass alle Spezialisierungen sichtbar sind:
// f1.h template <typename T> void foo (T); // f2.h template <> void foo (int); // bar.cc #include "f1.h" #include "f2.h" int main () { foo (0); // Calls specialization 'foo<int>(int)' }
Was das Überlastungsbeispiel betrifft, kann der Brute-Force-Ansatz zu einem Programm führen, das zwar noch kompiliert wird, aber ein anderes Verhalten aufweist.
Eine andere verwandte Art der Analyse, auf die Sie achten können, ist die Überprüfung, ob Typen vorwärts deklariert werden können. Folgendes berücksichtigen:
// A.h class A { }; // foo.h #include "A.h" void foo (A const &); // bar.cc #include "foo.h" void bar (A const & a) { foo (a); }
Im obigen Beispiel ist die Definition von 'A' nicht erforderlich, daher kann die Header-Datei 'foo.h' so geändert werden, dass sie nur für 'A' eine Vorwärtsdeklaration enthält:
// foo.h class A; void foo (A const &);
Diese Art der Überprüfung reduziert auch die Header-Abhängigkeiten.
quelle
Hier ist ein Skript, das es tut:
#!/bin/bash # prune include files one at a time, recompile, and put them back if it doesn't compile # arguments are list of files to check removeinclude() { file=$1 header=$2 perl -i -p -e 's+([ \t]*#include[ \t][ \t]*[\"\<]'$2'[\"\>])+//REMOVEINCLUDE $1+' $1 } replaceinclude() { file=$1 perl -i -p -e 's+//REMOVEINCLUDE ++' $1 } for file in $* do includes=`grep "^[ \t]*#include" $file | awk '{print $2;}' | sed 's/[\"\<\>]//g'` echo $includes for i in $includes do touch $file # just to be sure it recompiles removeinclude $file $i if make -j10 >/dev/null 2>&1; then grep -v REMOVEINCLUDE $file > tmp && mv tmp $file echo removed $i from $file else replaceinclude $file echo $i was needed in $file fi done done
quelle
-Werror=missing-prototypes
Sie die Header zu Funktionen entfernen, die in der Quelldatei definiert sind und später Probleme verursachen können (Sie werden nicht bemerken, wenn der Header nicht mehr synchron ist).Schauen Sie sich Dehydra an .
Von der Website:
Es sollte möglich sein, ein Skript zu erstellen, das nach nicht verwendeten # include-Dateien sucht.
quelle
Googles cppclean scheint gute Arbeit zu leisten, um nicht verwendete Header-Dateien zu finden. Ich habe gerade angefangen, es zu benutzen. Es werden einige Fehlalarme erzeugt. In Header-Dateien werden häufig unnötige Includes gefunden. Es wird jedoch nicht angegeben, dass Sie eine Vorwärtsdeklaration der zugeordneten Klasse benötigen und das Include in die zugehörige Quelldatei verschoben werden muss.
quelle
cppclean
reinigt zu viel. Wenn ich eine Header-Datei habefoo.h
, die explizit Funktionen und Typen verwendet, die inbar.h
und in definiert sind,baz.h
würde ich erwarten,foo.h
dass a#include "bar.h"
und a angezeigt werden#include "baz.h"
. Angenommen, dasbar.h
passiert auch#include "baz.h"
. Dies bedeutet nicht , dass ich loswerden der bekommen kann#include "baz.h"
infoo.h
. Die meisten nicht benötigten Header-Dateiprüfungen sagen, dass ich es loswerden sollte. Dies ist ein falsches Positiv, das fast so schlecht ist wie falsches Negativ. (Und vielleicht noch schlimmer; zu viele Fehlalarme und ich werde das Tool nicht mehr verwenden. Lint ist ein gutes Beispiel.)#include "baz.h"
. Morgen vielleicht nicht. Angenommen, esbar.h
liegt in Ihrer Verantwortung und auch Sie sind dabei, nicht benötigte Header zu entfernen. Siebar.h
brauchen nichtbaz.h
, also löschen Sie das Fremde#include "baz.h"
ausbar.h
. Sie haben gerade jeden Code gebrochen, der auf diesem Fremdkörper huckepack genommen hat#include
. Die Lösung besteht darin, sich nicht auf solche Huckepack-Geräte zu verlassen. Wenn Ihre Datei eine an anderer Stelle#include
definierte Funktionalität verwendet, die Datei, die diese Funktionalität definiert. Lassen Sie das nicht von einem anderen Header#include
für Sie tun .Wenn Sie Eclipse CDT verwenden, können Sie Includator ausprobieren, das für Betatester (zum Zeitpunkt dieses Schreibens) kostenlos ist und überflüssige #includes automatisch entfernt oder fehlende hinzufügt.
Haftungsausschluss: Ich arbeite für das Unternehmen, das Includator entwickelt, und benutze es seit einigen Monaten. Es funktioniert ganz gut für mich, also probieren Sie es aus :-)
quelle
Soweit ich weiß, gibt es keinen (der nicht PC-Lint ist), was schade und überraschend ist. Ich habe den Vorschlag gesehen, diesen Pseudocode zu verwenden (der im Grunde Ihren "sorgfältigen Prozess" automatisiert:
Legen Sie das in einen nächtlichen Cron, und es sollte die Arbeit erledigen und das betreffende Projekt frei von nicht verwendeten Headern halten (Sie können es natürlich immer manuell ausführen, aber die Ausführung wird lange dauern). Das einzige Problem ist, wenn ohne Header kein Fehler generiert wird, aber dennoch Code erzeugt wird.
quelle
Ich habe dies manuell gemacht und es lohnt sich kurzfristig (Oh, ist es langfristig? - Es dauert lange), da die Kompilierungszeit verkürzt ist:
Es ist auch eine rekursive Prozess - jeder Headerdatei , die Aufenthalte in Prüfung des Bedürfnisses zu sehen , ob die Header - Dateien es entfernt werden kann enthält. Außerdem können Sie manchmal Forward-Deklarationen für Header-Includes ersetzen.
Dann muss der gesamte Prozess alle paar Monate / Jahr wiederholt werden, um den Überblick über die verbleibenden Header zu behalten.
Eigentlich ärgere ich mich ein bisschen über C ++ - Compiler, sie sollten Ihnen sagen können, was nicht benötigt wird - der Microsoft-Compiler kann Ihnen sagen, wann eine Änderung an einer Header-Datei beim Kompilieren sicher ignoriert werden kann.
quelle
Wenn jemand interessiert ist, habe ich gerade ein kleines Java-Befehlszeilentool auf sourceforge geputtet, um genau das zu tun. Da es in Java geschrieben ist, kann es offensichtlich unter Linux ausgeführt werden.
Der Link für das Projekt lautet https://sourceforge.net/projects/chksem/files/chksem-1.0/
quelle
Die meisten Ansätze zum Entfernen nicht verwendeter Funktionen funktionieren besser, wenn Sie zunächst sicherstellen, dass jede Ihrer Header-Dateien für sich kompiliert wird. Ich habe das relativ schnell wie folgt gemacht (Entschuldigung für Tippfehler - ich schreibe das zu Hause:
find . -name '*.h' -exec makeIncluder.sh {} \;
wo
makeIncluder.sh
enthält:#!/bin/sh echo "#include \"$1\"" > $1.cpp
Bei
./subdir/classname.h
diesem Ansatz wird für jede Datei eine Datei erstellt,./subdir/classname.h.cpp
die die Zeile enthält#include "./subdir/classname.h"
Wenn Sie
makefile
in der. Das Verzeichnis kompiliert alle CPP-Dateien und enthält-I.
. Durch erneutes Kompilieren wird getestet, ob jede Include-Datei für sich kompiliert werden kann. Kompilieren Sie in Ihrer bevorzugten IDE mit goto-error und beheben Sie die Fehler.Wenn du fertig bist,
find . -name '*.h.cpp' -exec rm {} \;
quelle