Hallo GCC Freaks, ich bin gerade vom Glauben abgefallen: Habe in einer von mir erstellten Library eine neue Funktion implementiert und muss feststellen, dass die Codegröße um die Größe der Funktion anschwillt, obwohl ich die Funktion nirgendwo aufgerufen habe. Das Design ist klassisch: Prototyp in einer öffentliche Header-Datei und Implementierung in einer C-Datei, die nur der Library zugänglich ist. Habe dann ein bisschen rum gespielt: Erzeuge ich in der gleichen Library für die Funktion eine neue C-Datei, deren Inhalt nur die neue Funktion ist, wird wieder die Codegröße erzeugt, die ich ohne die Funktion hatte. Es scheint mir so, als ob der Linker nur vollständige Objektdateien verarbeiten kann. Ich arbeite mit WinAVR-20090313 (WinAVR-20081205 zeigt die gleichen Symptome) Eclipse Europa Version: 3.3.2 AVR Eclipse Plugin 2.3.1.20081204PRD Zum Erstellen der Library habe ich den Assistenten (AVR Cross Target Static Library) verwendet und dann für die verschiedenen Controllertypen, die ich gedenke zu verwenden, Debug bzw. Release Konfigurationen eingerichtet. Ist das eine Bug oder ein feature - oder wie bringe ich dem Linker bei, die Library C-Dateien nicht komplett zu linken?
Wenn der Linker aus der Library alles weg laesst, was nicht aufgerufen wird, ist sie leer...
Sorry: Beim Linker meine ich den, der mir die Applikation bindet (unter Einbeziehung der Library).
> Es scheint mir so, als ob der Linker nur vollständige Objektdateien > verarbeiten kann. Deine Analyse ist richtig.
meinst Du sowas: http://www.mikrocontroller.net/articles/GCC:_unbenutzte_Funktionen_entfernen Ich weiß aber nicht, ob WinAVR das auch kann. Habe es beim GCC noch nie benutzt. Nennt sich "selective linking" IIRC.
Das heißt also, dass ich mir bei der Dateistruktur Gedanken machen muss, was später möglicherweise nicht verwendet wird. Puh da muss ich mich erst mal sammeln: Das hätte ich nicht erwartet :-O Und noch ne Frage: Macht das nur der AVR-GCC so oder auch die für andere Plattformen (z.B. AVR32)?
Andreas Müller wrote: > Das heißt also, dass ich mir bei der Dateistruktur Gedanken machen muss, > was später möglicherweise nicht verwendet wird. Puh da muss ich mich > erst mal sammeln: Das hätte ich nicht erwartet :-O Normalerweise packt man bei Libraries einfach jede Funktion in eine separate C-Datei. Dazu noch eine weitere Header-Datei für alles Lib-interne, und gut is.
Mein letzter Post war für Karl Heinz Arne: Ich denke schon, dass ich so was gesucht habe das dumme ist nur, dass ich es nicht ans laufen bekomme.. Stefan: Sowas willst Du ernsthaft warten?
Andreas Müller wrote:
> Stefan: Sowas willst Du ernsthaft warten?
Warum nicht? Was ist daran tragisch? Alle gängigen Unix-Bibliotheken
sind in diesem Stil aufgebaut.
Jörg Wunsch wrote: > Warum nicht? Was ist daran tragisch? Ich finde die Übersichtlichkeit wird nicht unbedingt dadurch gesteigert, dass der Compiler mir vorschreibt, keine thematischen Gruppierungen vornehmen zu dürfen. > Alle gängigen Unix-Bibliotheken sind in diesem Stil aufgebaut. Die sind auch lange gewachsen und C++ gibt's da auch eher selten. Würde sich heute jemand daran machen, ist fraglich, ob die dann wieder so aussähen. Wahrscheinlich ist es auch nur Gewohnheit: Ich habe ne Menge Projekte unter C++ gemacht. Dort haben sich schon mal gerne einige hundert Klassen versammelt (immer brav *.h *.cpp). Hätte ich dort jede Funktion in eine eigen Datei räumen müssen (OK da war Speicherbelegung nicht wirklich ein Thema) hätte ich sicherlich keine Zeit hier zu posten... Nur damit ich nicht falsch verstanden werde: Der AVR-GCC ist sehr schön und ich versuche nicht, damit C++ Projekte durchzuführen. Ich hätte nur gerne die Dinge thematisch gruppiert, um auch morgen noch durch zu steigen. Ich werde mal weiter versuchen, die linker-garbage-collection ans laufen zu bringen...
Andreas Müller wrote: > Die sind auch lange gewachsen und C++ gibt's da auch eher selten. Würde > sich heute jemand daran machen, ist fraglich, ob die dann wieder so > aussähen. Möglicherweise doch, ja. Es wachsen ja auch nach wie vor welche nach. ;-) C++ ist meines Wissens der Hauptgrund, warum -gc-sections überhaupt voran getrieben worden ist: dort entstehen teilweise implizite Gebilde, die man sonst nicht vernünftig wieder los wird.
Wenn du mal genauer drüber nachdenkst, ist es für den Linker gar nicht so einfach festzustellen, ob eine Funktion benötigt wird oder nicht.
1 | typedef void (*func)(); |
2 | |
3 | void foo1() |
4 | {
|
5 | }
|
6 | |
7 | void foo2() |
8 | {
|
9 | }
|
10 | |
11 | int main() |
12 | {
|
13 | func ptr; |
14 | |
15 | ptr = foo1; |
16 | (*ptr)(); |
17 | }
|
Der Linker (nicht der Compiler) hat keine Chance rauszufinden, dass foo1
tatsächlich aufgerufen wird und foo2 nicht.
In C++ mit den virtuellen Funktionen wird das Ganze dann noch eine
Klasse schwieriger.
> Stefan: Sowas willst Du ernsthaft warten?
So schlimm ist es dann auch wieder nicht. Jede Funktion in eine eigene
*.c ist sicherlich ein Extremfall. Normalerweise hat man ja Funktionen
die auf jeden Fall zusammen benutzt werden. In einer Liste wird wohl die
Add, Traverse und Delete Funktion immer gemeinsam benutzt werden,
wohingegen die Sort Funktion anwendungsabhängig mal dazu kommt und mal
nicht.
Karl Heinz, mir scheint, das Beispiel hat nicht wirklich etwas mit dem Problem zu tun: Es geht doch darum, welche 'Granularität' der Linker bei seiner Entscheidung verwendet: Object-Datei oder Funktion. Im Falle der Object-Datei (default) scheint er dem ja auch ordentlich nachzukommen (wohl auch für Dein Beispiel, wenn foo1 und foo2 in unterschiedlichen C-Dateien implementiert werden). Oder liege ich falsch? Ich frage deshalb, weil ich angefangen habe, die Struktur den Compiler-Wünschen anzupassen...
Ein Objektmodul wird aus einer Bibliothek (also aus einer Datei mit der Endung .a!) dann und genau dann hinzu gezogen, wenn er (mindestens) ein Symbol definiert, das beim Linken derzeit `external undefined' ist. Ob das Symbol dabei eine Funktion (Codereferenz) oder Daten ist, das gerade nachgefragt wird, spielt keine Rolle. Damit zieht sich also letztlich der Modul auch ggf. ,,seine'' Daten noch mit ins Resultat hinein.
Einen hab ich noch: Ich habe meine Libraries umstrukturiert, so dass die Implementierungen feiner auf C-Dateien verteilt sind. Ich muss sagen: Mir fallen die Schuppen von den Haaren (oder wie heißt der Spruch): Da optimiere ich tagelang an meinem Code rum mit dem Erfolg, wenige Bytes einzusparen, um dann mit kleinem Aufwand bei einigen Projekten an die 1000 Bytes zu sparen. Fazit: Hat nicht weh getan und viel geholfen.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.