Wird g ++ meine Programme mit Klassen verknüpfen, die es nicht aus einer Bibliothek benutzt?

8

Ich habe eine einfache statische Bibliothek erstellt, die in einer .a -Datei enthalten ist. Ich könnte es in einer Vielzahl von Projekten verwenden, von denen einige einfach nicht 90% davon brauchen. Zum Beispiel, wenn ich neuronale Netzwerke, die ein Teil meiner Bibliothek sind, auf einem AVR-Mikrocomputer verwenden möchte, werde ich wahrscheinlich nicht eine Tonne anderer Sachen brauchen, aber wird das in meinem Code verlinkt, was möglicherweise eine ziemlich große Datei erzeugt? / p>

Ich beabsichtige Programme wie folgt zu kompilieren:

g++ myProg.cpp myLib.a -o prog

    
corazza 29.09.2012, 11:39
quelle

4 Antworten

4

G ++ holt nur die benötigten Objektdateien aus der Bibliothek, aber wenn ein Symbol aus einer einzelnen Objektdatei verwendet wird, wird alles in dieser Objektdatei zu Ihrer ausführbaren Datei hinzugefügt.

Eine Quelldatei wird zu einer Objektdatei, daher ist es logisch, Dinge nur zusammen zu gruppieren, wenn sie sicher zusammen benötigt werden.

Diese Vorgehensweise variiert je nach Compiler (eigentlich nach Linker). Zum Beispiel wird der Microsoft Linker Objektdateien auseinander nehmen und nur die Teile enthalten, die tatsächlich benötigt werden.

    
mah 29.09.2012, 11:45
quelle
2

Sie könnten auch versuchen, Ihre Bibliothek in unabhängige kleinere Teile aufzuteilen und nur die Teile zu verknüpfen, die Sie wirklich benötigen.

    
Pablo 29.09.2012 11:49
quelle
1

Wenn Sie eine Verknüpfung zu einer statischen Bibliothek herstellen, ruft der Linker Objekte auf, die Namen auflösen, die in anderen Teilen des Codes verwendet werden. Im Allgemeinen wird der Name nicht verwendet, wenn er nicht verwendet wird.

    
Pete Becker 29.09.2012 11:44
quelle
1

Der GNU-Linker holt den benötigten Inhalt aus den Bibliotheken, die Sie für eine Objektdatei angegeben haben, nach Objektdateibasis. Objektdateien sind atomare Einheiten, soweit es den GNU-Linker betrifft. Es teilt sie nicht auseinander. Der Linker wird eine Objektdatei einbringen, wenn diese Objektdatei eine oder mehrere nicht aufgelöste externe Referenzen definiert. Diese Objektdatei kann externe Referenzen haben. Der Linker wird versuchen, diese zu lösen, aber wenn es nicht möglich ist, fügt der Linker diese zu dem Satz der Referenzen hinzu, die aufgelöst werden müssen.

Es gibt ein paar Fehler, die zu einer viel größeren als benötigten ausführbaren Datei führen können. Mit größer als benötigt, meine ich eine ausführbare Datei, die Funktionen enthält, die niemals aufgerufen werden, globale Objekte, die während der Ausführung des Programms niemals untersucht oder modifiziert werden. Sie werden Binärcode haben, der nicht erreichbar ist.

Eines dieser Fehler tritt auf, wenn eine Objektdatei eine große Anzahl von Funktionen oder globalen Objekten enthält. Ihr Programm benötigt möglicherweise nur eines von diesen, aber Ihre ausführbare Datei erhält alle, weil Objektdateien atomare Einheiten für den Linker sind. Diese zusätzlichen Funktionen sind nicht erreichbar, da es keinen Aufrufpfad von% code_% zu diesen Funktionen gibt, aber sie befinden sich immer noch in Ihrer ausführbaren Datei. Die einzige Möglichkeit, dies zu verhindern, ist die Verwendung der Regel "Eine Funktion pro Quelldatei". Ich befolge diese Regel nicht selbst, aber ich verstehe ihre Logik.

Wenn Sie polymorphe Klassen verwenden, treten weitere Fehler auf. Ein Konstruktor enthält automatisch generierten Code sowie den Rumpf des Konstruktors selbst. Dieser automatisch generierte Code ruft die Konstruktoren für übergeordnete Klassen auf, fügt einen Zeiger auf die vtable für die Klasse im Objekt ein und initialisiert Datenelemente in der Initialisierungsliste. Diese übergeordneten Klassenkonstruktoren, die vtable und die Mechanismen zum Verarbeiten der Initialisierungsliste können externe Referenzen sein, die der Linker auflösen muss. Wenn sich der Elternklassenkonstruktor in einer größeren Headerdatei befindet, haben Sie einfach all das Zeug in Ihre ausführbare Datei gezogen.

Was ist mit der vtable? Der GNU-Compiler wählt eine Schlüsselelementfunktion als den Ort zum Speichern der V-Tabelle aus. Diese Schlüsselfunktion ist die erste Elementfunktion in der Klasse, die keine Inline-Definition hat. Selbst wenn Sie diese Member-Funktion nicht aufrufen, erhalten Sie die Objektdatei, die sie enthält, in Ihrer ausführbaren Datei - und Sie erhalten alles, was diese Objektdatei hineinzieht.

Halten Sie Ihre Quelldateien noch einmal auf eine kleine Größe und helfen Sie dabei "schauen Sie, was die Katze hineingezogen hat!" Problem. Es ist eine gute Idee, der Datei, die diese Schlüsselelementfunktion enthält, besondere Aufmerksamkeit zu schenken. Halten Sie diese Quelldatei klein, zumindest in Bezug auf die Dinge, die die Katze hineinzieht. Ich neige dazu, kleine, in sich geschlossene Elementfunktionen in diese Quelldatei einzufügen. Funktionen, die unweigerlich in eine Menge anderer Dinge hineingezogen werden, sollten nicht dorthin gehen.

Ein weiteres Problem mit der vtable ist, dass sie Zeiger auf alle virtuellen Funktionen einer Klasse enthält. Diese Zeiger müssen auf etwas Reales verweisen. Ihre ausführbare Datei enthält die Objektdateien, die jede virtuelle Funktion definieren, die für eine Klasse definiert ist, einschließlich derjenigen, die Sie nie aufrufen. Und du wirst alles bekommen, was diese virtuellen Funktionen mit sich ziehen.

Eine Lösung für dieses Problem besteht darin, große große Klassen zu vermeiden. Sie neigen dazu, alles zu ziehen. Vor allem Gottesklassen sind in dieser Hinsicht problematisch. Eine andere Lösung besteht darin, darüber nachzudenken, ob eine Funktion wirklich virtuell sein muss. Machen Sie eine Funktion nicht nur virtuell, weil Sie denken, dass jemand sie irgendwann überlasten muss. Das ist spekulative Allgemeinheit, und bei virtuellen Funktionen ist die spekulative Allgemeinheit mit hohen Kosten verbunden.

    
David Hammen 29.09.2012 13:41
quelle