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
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.
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?
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
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
voidfoo()
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
staticvoidfoo()
2
{
3
machwas;
4
}
Dann ist die Funktion jedoch nicht global und nicht in anderen Modulen
verwendbar.
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.
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
voidmain(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?
> 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:
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.....
??? 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 ^^
@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....
Hab ein neues Projekt angefangen und yalu's Code reinkopiert.
1
inta;
2
sub1(void){
3
a=1;
4
}
5
6
sub2(void){
7
a=2;
8
}
9
10
intmain(void){
11
sub1();
12
return0;
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.
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.
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.
@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.
@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...
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 :-)
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.
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.
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?
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.
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"