Forum: Compiler & IDEs AVR-GCC Kompiliert nicht benutzte Funktionen mit ein


von Stephan P. (sapeterich)


Lesenswert?

Hallo,

ich programmiere schon etwas länger mit C und Atmel. Nun habe ich bei 
einem neuen Projekt für das ich die Sourcen eines alten Projektes 
zusammengestrichen (auskommentiert) habe, festgestellt, das die 
auskommentierten Header-Dateien und deren Funktionen trotzdem weiterhin 
im Programm bleiben.

Erst als ich die c und h Files aus meinem AVR-Studio Projekt gelöst habe 
wurde das Ergebniss kleiner. Es kann doch nicht sein, das unnötige mit 
einkompiliert werden.

In der Suche habe ich folgendes gefunden, dort wird die Frage aber nicht 
beantwortet:

Beitrag "Re: avr-gcc linker Problem"

An compiler Optinen verwende ich den AVR-Studio Standard: -Os -Wall 
-gdwarf-2 -fsigned-char

Gibt es eine Option die dem GCC diese Unart abzugewöhnen, die dem 
widerspricht was ich zu c gelernt  habe.

mfg und Dank im voraus

Stephan

von Johannes M. (johnny-m)


Lesenswert?

Was widerspricht dem denn? Alle C-Files, die zum Projekt gehören, werden 
nunmal compiliert, und da der Compiler alle Sourcen separat übersetzt, 
ist es ihm auch egal, ob der Inhalt des C-Files gar nicht benötigt wird.

Wenn Du nur die Header auskommentierst, die C-Files aber im Projekt 
belässt, dann werden die selbstverständlich mitübersetzt und erzeugen 
Code.

von Dieter (Gast)


Lesenswert?

hm, im Compiler wird ne ganze Menge Aufwand getrieben, um den Code zu 
optimieren. Aber eine so einfache Möglichkeit, einfach nicht benutzte 
Codeteile nicht mit zu linken wird nicht ausgenutzt?
Das versteh ich nicht, aus welchen Grund macht man das nicht?

von Philipp B. (philipp_burch)


Lesenswert?

Dieter wrote:
> hm, im Compiler wird ne ganze Menge Aufwand getrieben, um den Code zu
> optimieren. Aber eine so einfache Möglichkeit, einfach nicht benutzte
> Codeteile nicht mit zu linken wird nicht ausgenutzt?
> Das versteh ich nicht, aus welchen Grund macht man das nicht?

Ganz einfach: Normalerweise hat man keinen unbenutzten Code im Programm. 
Die Funktionen aus den Libraries sind davon ja nicht betroffen, die 
werden nur dazugelinkt wenn sie wirklich verwendet werden. Wenn du 
einfach testweise eine ganze Datei von der Kompilierung ausschliessen 
willst, kannst du ja den ganzen Inhalt in
1
#if 0
2
//...
3
#endif
einpacken.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Dieter wrote:

> hm, im Compiler wird ne ganze Menge Aufwand getrieben, um den Code zu
> optimieren. Aber eine so einfache Möglichkeit, einfach nicht benutzte
> Codeteile nicht mit zu linken wird nicht ausgenutzt?
> Das versteh ich nicht, aus welchen Grund macht man das nicht?

Woher soll denn der COMPILER das wissen?

Er sieht nur
1
void foo()
2
{
3
   machwas;
4
}

Woher soll er bitte wissen, dass die Funktion nicht in einem anderen 
Modul verwendet wird?

Wenn Du sowas haben willst, dann

1) Übersetzte jede Funktion in ein separates Objekt
2) Mach aus den Objekten ne Lib
3) Linke gegen diese Lib

4) Du kannst aber auch sagen
1
static void foo()
2
{
3
   machwas;
4
}

Dann ist die Funktion jedoch nicht global und nicht in anderen Modulen 
verwendbar.

von yalu (Gast)


Lesenswert?

Der GCC wäre nicht der GCC, wenn es keine Möglichkeit gäbe, unbenutzte
Funktionen wegzuoptimieren ;-). Einfach beim Compiler

  -ffunction-sections

und beim Linker

  --gq-sections

angeben. Damit bereitet der GCC die Objektfiles so auf, dass der
Linker Ungenutztes wegoptimieren kann. Evtl. noch das GCC- und
Binutils-Manual lesen.

von Stephan P. (sapeterich)


Lesenswert?

1
#if 0
2
//...
3
#endif
ist doch auch keine Lösung, ich programmiere extra mit vielen .h damit 
ich einfach Sachen wiederverwenden kann. zum Beispiel bei einer 
"Treiber" Bilbiothek für den UART braucht mann doch nicht immer alle 
Funktionen. Und das ganze als 20 .h Dateien definieren, z.B. als 
Uart_Init.h Uart_Senden.h etc. ist doch ... .
Und wenn ich diese alle dann auch extra in einem Lib umwandeln muss, 
obwohl ich noch mitten am Programmieren bin.

Mal am Rande gefragt: Wenn ich bei folgendem Code die uart.h nicht im 
Project des AVR Studios habe, meckert er "undefindef reference to 
uart_init" obwohl die Dateien im gleichen Verzeichnis ist und das 
Verzeichnis auch im Suchpfad ist.
1
#include "uart.h"
2
void main(void)
3
{
4
 uart_init();
5
}

Und die Compiler Optionen helfen leider auch nicht, aber nach dem Mittag 
lese ich mir mal die GCC / Binutils Doku durch.

Macht einer der käuflichen "Konkurrenz" Compiler das besser?

von yalu (Gast)


Lesenswert?

> Und die Compiler Optionen helfen leider auch nicht, aber nach dem
> Mittag

Mein Fehler: Die Linkeroption muss

  --gc-sections

heißen. Bei mir funktioniert das wie erwartet. In folgendem Programm
wird sub2() entfernt, sub1() bleibt drin:
1
int a;
2
sub1(void) {
3
  a=1;
4
}
5
  
6
sub2(void) {
7
  a=2;
8
}
9
  
10
int main(void) {
11
  sub1();
12
  return 0;
13
}

von ANdreas Paulin (Gast)


Lesenswert?

Hochinteressant, endlich sagt einem das mal jemand
:-D Danke für die Info.
Hab gleich mal mit dem aktuellen Projekt einen Test gemacht.
Optimierer -O0 und dann build.
Ergebnis:

Ohne diese Optionen:
1
Program:   81362 bytes (62.1% Full)
2
(.text + .data + .bootloader)


Mit diesen Optionen:
1
Program:   66264 bytes (50.6% Full)
2
(.text + .data + .bootloader)

Ja, super, das lassen wir dann mal so drin. Wenn sich die Objectfiles 
dadurch ein wenig aufblähen ist doch wurscht, wenn das Endergebnis 
stimmt.

Hab jetzt nur die Frage: WO im gcc-Manual finde ich Info über die
--gc(-functions) Option? Habs nirgends gefunden.....

von Stephan P. (sapeterich)


Lesenswert?

??? Bin ich zu blöd oder was ???

Also ich habs im AVR Studio bei den Project Options für [All files] das 
-ffunction-sections
und bei [Linker Options] --gc-sections eingefügt.
Und genau das Beispiel von yalu kopiert.
Und nichts ändert sich, das sub2 bleibt sogar im Map File.

Ich verwende AVRStudio 4.14 und WinAVR 20080610
das ganze soll auf einem AT90PWM3B laufen.

Die restlichen Optionen sind:
-Os
-gdwarf2
-std=gnu99
-funsigned-char
-funsigned-bitfields
-fpack-struct
-fshort-enums

Die habe ich aber auf Voreistellung gelassen.

Ähm aber auf jeden Fall schon einmal vielen Dank für die Hilfe, 
wenigstens hab ich jetzt den Weg gefunden ;-) Nur liegt da halt noch ein 
Stein rum ^^

von ANdreas Paulin (Gast)


Lesenswert?

Erledigt, ist im gesonderten -ld-Handbuch :)

von Andreas Paulin (Gast)


Lesenswert?

@Stephan:
Vielleicht hast Du ja einfach keinen unbenutzten Code?
Das wäre aber rauszufinden, wenn Du eine selten benutzte Funktion und 
ihren Aufruf mal auskommentierst....

von Andreas Paulin (Gast)


Lesenswert?

@STephan:
Linker-Optionen:
-Wl,--gc-sections

also... MIT dem -Wl

Bringts das vielleicht?

von Stephan P. (sapeterich)


Lesenswert?

Hab ein neues Projekt angefangen und yalu's Code reinkopiert.
1
int a;
2
sub1(void) {
3
  a=1;
4
}
5
  
6
sub2(void) {
7
  a=2;
8
}
9
  
10
int main(void) {
11
  sub1();
12
  return 0;
13
}
Und da ist definitv die sub2 "unnütz".

Und in meinem eigenen Programm hab ich alles auskommentiert außer der 
while schleife die einen Port verändert.
Wenn ich die ganzen .c und .h aus dem Projekt im AVRStudio lösche bricht 
mein Programm  von 4968 auf 680 byte ein ohne auch nur eine 
Programmzeile zu verändern.

von Stephan P. (sapeterich)


Lesenswert?

@ Andreas
Danke für den versuch, aber leider auch nicht :-(

Aber ich gebe das doch an der richtigen Stellen ein?

von yalu (Gast)


Lesenswert?

Wie Andreas Paulin oben geschrieben hat:

Wenn die Linkeroption nicht direkt, sondern über den gcc an den ld
übergeben wird, muss die Option

  -Wl,--gc-sections

heißen (-Wl,<opt1>,<opt2>... reicht <opt1>, <opt2> usw. an den Linker
weiter). Interessanterweise scheint der gcc --gc-sections auch selbst
zu akzeptieren, aber da wird sie anscheinend ignoriert.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Stephan Peterich wrote:

> Und das ganze als 20 .h Dateien definieren, z.B. als
> Uart_Init.h Uart_Senden.h etc. ist doch ... .

Die Headerfiles enthalten doch nur die Deklarationen, nicht die
Implementierung.  Üblicher Ansatz ist halt bspw. eine Headerdatei
für die ganze Bibliothek.  Die Bibliothek aber besteht aus einzelnen
Modulen, die für sich compiliert und in ein Archiv gesteckt werden,
das dann dem Linker mit auf die Reise gegeben wird.  Der Linker pickt
sich daraus dann nur die Module, die er braucht.

Nein, mit AVR-Studio-Bordmitteln kannste sowas knicken.  Dessen
Makefile-Generator ist nur für sehr einfache Probleme gewappnet,
Bibliotheken sind außerhalb seines Radars (und auch außerhalb der
Idee hinter Mfile).  Dafür sollte man schon wissen, wie man die
Bibliothek baut und wie man ein Makefile dafür zimmert -- ist ja
keine Atomphysik, sowas zu lernen.

von Andreas Paulin (Gast)


Lesenswert?

@Stephan:
Sorry, ich meinte natürlich: Nur den Aufruf auskommentieren, nicht die 
Funktion selber. Genau diesen Rausschmiss soll der Linker ja für uns 
erledigen..

Und, ja, wie yalu auch sagte: Das "Wl," ist unabdingbar.

von Andreas Paulin (Gast)


Lesenswert?

@Jörg:
Hei, Jörg, ich weiß, Du HASST AVRStudio ;-)
Aber ich arbeite mit der Kiste, und Du kannst dort tatsächlich ohne 
großen Aufwand zusätzliche Optionen
für
- Compiler allgemein
- Compiler filespezifisch
- Linker allgemein
eingeben.
Und des dudd.. ;)

Der Knacksus bei Stephan ist afaik, dass er das '-Wl,' vergessen hat...

von Stephan P. (sapeterich)


Lesenswert?

Danke vielmals.
Ich dachte ich müsste das W1 als einzelnen Parameter eingeben:

Also nochmal als Anleitung für alle die das Problem auch mal haben.
Bei
AVR-Studio unter
Project -> Configuration Options
Im Reiter Custom Options .
[All files] auswählen dann die Option
1
-ffunctions-sections
 adden
dann [Linker Options] auswählen und die Option
1
-W1,--gc-sections
 adden.

@ Jörg: Danke für die Korrektur, du hast recht das in den Headern nur 
die Definitionen gehören, mein Problem war ja, das reines hinzufügen zum 
Project ohne include usw. schon den Speicherverbrauch erhöht hat und da 
ging halt nur ganze Header Datei oder garnicht. Das zu einer .h mehrer 
.c gehören hatte ich mir schon beim Einsatz von Subversion angewöhnt, 
damit die Änderungen übersichtlicher bleiben.

Also nochmal Vielen Dank. Eventuell könnte das doch wer mal ins Wiki 
schreiben. Ich finde das schon ein sehr wichtiges Feature und das 
grösste Platzeinspaarpotenzial für den Compiler überhaupt. Ich hab 
während der Entwicklung immer ein paar Funktionsleichen :-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Andreas Paulin wrote:

> Hei, Jörg, ich weiß, Du HASST AVRStudio ;-)

Sagen wir so: ich bin zu blöd, es zu benutzen. ;-)  Das Teil
entspricht absolut nicht dem, was ich mir als intuitive Bedienung
vorstelle, da es immer gerade Dinge tut, die nicht meinen
Intentionen entsprechen...  Außerdem läuft es nun mal nur auf
Windows, was ich weder habe noch haben möchte.  (Aber ich würde
es vermutlich selbst dann nicht benutzen wollen, wenn es
multiplattformfähig wäre, zumindest nicht mit dem jetzigen
Bedienkonzept.)

> Aber ich arbeite mit der Kiste, und Du kannst dort tatsächlich ohne
> großen Aufwand zusätzliche Optionen [...] eingeben.

Klar, das geht.  Echte Bibliotheken kann man damit aber eben nicht
bauen, das und nur das war mein Punkt.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Hi, ich hab das mal ausgetestet.

Bis zu den o-Files ist alles klar, die Funktionen liegen brav in eigenen 
Sections.

Aber wenn ich linke mit
1
avr-gcc -mmcu=*** -Wl,-Map,***.map -Wl,--gc-sections  -o ***.elf <o-files>

Ist das elf leer (bzw ist nur .stab und .stabstr drin). Müssen da noch 
weitere Optionen an den Linker? Linkerskript oder so?

von Εrnst B. (ernst)


Lesenswert?

main() Vergessen?
dann sind alle anderen funktionen unbenutzt und werden rausoptimiert.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ernst Bachmann wrote:
> main() Vergessen?
> dann sind alle anderen funktionen unbenutzt und werden rausoptimiert.

Nein. Ist ein ganz normales Projekt, das ohne die --gc-sections normal 
bis zum hex ausgeneriert wird. Und enthält dann auch eine main.

von No N. (birger)


Lesenswert?

Ein interessanter Beitrag, auch für mich.

Ich versuche momentan einen tiny2313 mit seinen dürftigen 2KB Flash noch 
etwas auszureizen. Mit -Wl,--gc-sections erreiche ich aber leider 
nichts. Nehme ich allerdings einen 3.x GCC dann ist das Ergebnis ein 
leeres Hex-File. Scheinbar kennt der 3.x GCC diese Option nicht oder 
versteht sie anders.

Lassse ich -Wl,--gc-sections wie vorher fort, so ist das Hexfile 
deutlich kleiner als bei einem 4.x GCC. Da frag ich mich, wieso mit 
jeder neuen GCC bzw. AVR-LIBC die Hexfiles immer größer werden. Hab ich 
da was übersehen?

In die Zukunft geschaut, bedeutet das ja bald das Aus für die kleineren 
Controller, weil da mit neueren Compilern nichts mehr reinpasst. Was für 
Abspeckmöglichkeiten gibt's denn noch?

von Andreas K. (a-k)


Lesenswert?

Birger Z. wrote:

> Scheinbar kennt der 3.x GCC diese Option nicht oder
> versteht sie anders.

Da wird das Linker-Script den Trick noch nicht vorgesehen haben, und die 
als lauter eigene Sections erzeugten Funktionen gehen folglich nicht ins 
ROM sondern direkt ins Nirvana ein.

Der Tiny2313 ist allerding auch ein krasser Fall, weil so ziemlich der 
einzige Bursche ohne Luft nach oben. Ist zwar ein nettes Teil, aber eben 
deshalb sehr beschränkt. Der Tiny861 beispielsweise hat auch 20 Pins und 
weit mehr Luft.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Birger Z. wrote:
> Ein interessanter Beitrag, auch für mich.
>
> Ich versuche momentan einen tiny2313 mit seinen dürftigen 2KB Flash noch
> etwas auszureizen. Mit -Wl,--gc-sections erreiche ich aber leider
> nichts. Nehme ich allerdings einen 3.x GCC dann ist das Ergebnis ein
> leeres Hex-File. Scheinbar kennt der 3.x GCC diese Option nicht oder
> versteht sie anders.

Ok, dann liegt's bei mir daran, hab ja noch die alten avr-binutils.

> Lassse ich -Wl,--gc-sections wie vorher fort, so ist das Hexfile
> deutlich kleiner als bei einem 4.x GCC. Da frag ich mich, wieso mit
> jeder neuen GCC bzw. AVR-LIBC die Hexfiles immer größer werden. Hab ich
> da was übersehen?

Aus dem Grund bin ich auch noch nicht auf avr-gcc 4.x umgestiegen. Bei 
mir ist quer über alle Projekte der Flash-Verbrauch um 5-10% größer als 
mit avr-gcc 3.4.6

GCC 4.2.2 und GCC 4.3.0 hatte ich mal angetestet.

Beitrag "avr-gcc: 3.4.6 contra 4.3.0"

von Daniel N. (Gast)


Lesenswert?

>>Danke vielmals.
>>Ich dachte ich müsste das W1 als einzelnen Parameter eingeben:
Die Option heisst aber -Wl(ell) nicht -W1(eins).

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
Noch kein Account? Hier anmelden.