Ich muss die Größe meiner ausführbaren Datei stark optimieren ( ARM
Entwicklung) und habe festgestellt, dass in meinem aktuellen Build-Schema ( gcc
+ ld
) nicht verwendete Symbole nicht entfernt werden.
Die Verwendung von arm-strip --strip-unneeded
für die resultierenden ausführbaren Dateien / Bibliotheken ändert nichts an der Ausgabegröße der ausführbaren Datei (ich habe keine Ahnung warum, vielleicht kann es einfach nicht) .
Wie kann ich meine Gebäude-Pipeline so ändern (falls vorhanden) , dass die nicht verwendeten Symbole aus der resultierenden Datei entfernt werden?
Ich würde nicht einmal daran denken, aber meine derzeitige eingebettete Umgebung ist nicht sehr "leistungsfähig" und das Speichern selbst 500K
von 2M
Ergebnissen führt zu einer sehr schönen Steigerung der Ladeleistung.
Aktualisieren:
Leider hat die aktuelle gcc
Version, die ich verwende, keine -dead-strip
Option und das -ffunction-sections... + --gc-sections
for ld
gibt keinen signifikanten Unterschied für die resultierende Ausgabe.
Ich bin schockiert, dass dies sogar zu einem Problem wurde, weil ich mir sicher war, dass gcc + ld
nicht verwendete Symbole automatisch entfernt werden sollten (warum müssen sie sie überhaupt behalten?).
boost
Bibliotheken verwenden, die resultierende.exe
Datei viele nicht verwendete Objektdateien enthält und aufgrund der Spezifikationen meiner aktuellen eingebetteten Laufzeit Das Starten einer10mb
Anwendung dauert viel länger als beispielsweise das Starten einer500k
Anwendung.Antworten:
Für GCC erfolgt dies in zwei Schritten:
Kompilieren Sie zuerst die Daten, aber weisen Sie den Compiler an, den Code in separate Abschnitte innerhalb der Übersetzungseinheit zu unterteilen. Dies erfolgt für Funktionen, Klassen und externe Variablen mithilfe der folgenden zwei Compiler-Flags:
Verknüpfen Sie die Übersetzungseinheiten mithilfe des Linker-Optimierungsflags (dies führt dazu, dass der Linker nicht referenzierte Abschnitte verwirft):
Wenn Sie also eine Datei namens test.cpp hatten, in der zwei Funktionen deklariert waren, von denen jedoch eine nicht verwendet wurde, können Sie die nicht verwendete mit dem folgenden Befehl an gcc (g ++) weglassen:
(Beachten Sie, dass -Os ein zusätzliches Compiler-Flag ist, das GCC anweist, die Größe zu optimieren.)
quelle
mingw
diesem nicht funktioniert , wenn mit der Flagge statisch statisch libstdc ++ und libgcc verbindet-static
. Die Linker-Option-strip-all
hilft einiges, aber die generierte ausführbare Datei (oder DLL) ist immer noch ungefähr viermal größer als das, was Visual Studio generieren würde. Punkt ist, ich habe keine Kontrolle darüber, wielibstdc++
kompiliert wurde. Es sollte eineld
einzige Option geben.Wenn dieser Thread angenommen werden soll, müssen Sie das
-ffunction-sections
und-fdata-sections
an gcc angeben, wodurch jedes Funktions- und Datenobjekt in einem eigenen Abschnitt platziert wird. Dann geben Sie und--gc-sections
an GNU ld, um die nicht verwendeten Abschnitte zu entfernen.quelle
Sie sollten Ihre Dokumente auf Ihre Version von gcc & ld überprüfen:
Für mich (OS X gcc 4.0.1) finde ich diese jedoch für ld
Und diese hilfreiche Option
Es gibt auch einen Hinweis im gcc / g ++ - Mann, dass bestimmte Arten der Beseitigung von totem Code nur durchgeführt werden, wenn die Optimierung beim Kompilieren aktiviert ist.
Diese Optionen / Bedingungen gelten möglicherweise nicht für Ihren Compiler. Ich empfehle jedoch, dass Sie in Ihren Dokumenten nach etwas Ähnlichem suchen.
quelle
mingw
.-dead_strip
ist keinegcc
Option.Programmiergewohnheiten könnten ebenfalls helfen; zB
static
Funktionen hinzufügen, auf die außerhalb einer bestimmten Datei nicht zugegriffen wird; Verwenden Sie kürzere Namen für Symbole (kann ein bisschen helfen, wahrscheinlich nicht zu viel). verwenden ,const char x[]
sofern möglich; ... dieses Papier , obwohl es sich um dynamische gemeinsam genutzte Objekte handelt, kann Vorschläge enthalten, die, wenn sie befolgt werden, dazu beitragen können, Ihre endgültige binäre Ausgabegröße zu verkleinern (wenn Ihr Ziel ELF ist).quelle
.so
unter Linux) . Daher müssen die Symbolnamen beibehalten werden, damit APIs wie dasctypes
FFI-Modul von Python sie zur Laufzeit nach Namen suchen können.Die Antwort lautet
-flto
. Sie müssen es sowohl an Ihre Kompilierungs- als auch an Ihre Linkschritte übergeben, sonst macht es nichts.Es funktioniert tatsächlich sehr gut - die Größe eines Mikrocontroller-Programms, das ich geschrieben habe, wurde auf weniger als 50% seiner vorherigen Größe reduziert!
Leider schien es ein bisschen fehlerhaft zu sein - ich hatte Fälle, in denen Dinge nicht richtig gebaut wurden. Möglicherweise lag es an dem von mir verwendeten Build-System (QBS; es ist sehr neu), aber ich würde auf jeden Fall empfehlen, es nur für Ihren endgültigen Build zu aktivieren, wenn möglich, und diesen Build gründlich zu testen.
quelle
-flto
ich nicht verstehe, was sie hinter den Kulissen tut.-flto
dass damit nicht jede Datei zu Assembly kompiliert wird, sondern sie zu LLVM IR kompiliert werden und der letzte Link sie dann kompiliert, als ob sie alle in einer Kompilierungseinheit wären. Dies bedeutet, dass nicht verwendete Funktionen und Inline-Funktionenstatic
und wahrscheinlich auch andere Dinge eliminiert werden können . Siehe llvm.org/docs/LinkTimeOptimization.htmlWenn es um Größe geht, kompilieren Sie immer mit
-Os
und-s
Flags.-Os
optimiert den resultierenden Code für die minimale Größe-s
der ausführbaren Datei und entfernt die Symboltabelle und die Verschiebungsinformationen aus der ausführbaren Datei.Manchmal - wenn eine kleine Größe gewünscht wird - kann das Herumspielen mit verschiedenen Optimierungsflags von Bedeutung sein oder auch nicht. Zum Beispiel können Sie durch Umschalten
-ffast-math
und / oder-fomit-frame-pointer
manchmal sogar Dutzende von Bytes sparen.quelle
-ffast-math
Chaos in vollständig standardkonformem C ++ - Code angerichtet, daher würde ich ihn niemals empfehlen.Es scheint mir, dass die Antwort von Nemo die richtige ist. Wenn diese Anweisungen nicht funktionieren, hängt das Problem möglicherweise mit der von Ihnen verwendeten Version von gcc / ld zusammen. Als Übung habe ich ein Beispielprogramm mit den hier beschriebenen Anweisungen zusammengestellt
Dann habe ich den Code mit zunehmend aggressiveren Schaltern zum Entfernen von totem Code kompiliert:
Diese Kompilierungs- und Verknüpfungsparameter ergaben ausführbare Dateien der Größe 8457, 8164 bzw. 6160 Byte, wobei der wichtigste Beitrag aus der "Strip-All" -Deklaration stammt. Wenn Sie auf Ihrer Plattform keine ähnlichen Reduzierungen erzielen können, unterstützt Ihre Version von gcc diese Funktionalität möglicherweise nicht. Ich verwende gcc (4.5.2-8ubuntu4), ld (2.21.0.20110327) unter Linux Mint 2.6.38-8-generic x86_64
quelle
strip --strip-unneeded
funktioniert nur mit der Symboltabelle Ihrer ausführbaren Datei. Es wird kein ausführbarer Code entfernt.Die Standardbibliotheken erzielen das gewünschte Ergebnis, indem sie alle ihre Funktionen in separate Objektdateien aufteilen, die mithilfe von kombiniert werden
ar
. Wenn Sie dann das resultierende Archiv als Bibliothek verknüpfen (dh-l your_library
ld die Option geben ), enthält ld nur die Objektdateien und damit die tatsächlich verwendeten Symbole.Möglicherweise finden Sie auch einige Antworten auf diese ähnliche Verwendungsfrage.
quelle
Ich weiß nicht, ob dies bei Ihrer aktuellen Situation hilfreich sein wird, da dies eine neuere Funktion ist, aber Sie können die Sichtbarkeit von Symbolen auf globale Weise festlegen. Das Übergeben
-fvisibility=hidden -fvisibility-inlines-hidden
bei der Kompilierung kann dem Linker helfen, nicht benötigte Symbole später zu entfernen. Wenn Sie eine ausführbare Datei erstellen (im Gegensatz zu einer gemeinsam genutzten Bibliothek), müssen Sie nichts weiter tun.Weitere Informationen (und einen detaillierten Ansatz für z. B. Bibliotheken) finden Sie im GCC-Wiki .
quelle
Aus dem GCC 4.2.1-Handbuch, Abschnitt
-fwhole-program
:quelle
-flto
.Sie können Strip Binary für Objektdatei (z. B. ausführbare Datei) verwenden, um alle Symbole daraus zu entfernen.
Hinweis: Es ändert die Datei selbst und erstellt keine Kopie.
quelle