Forum: Compiler & IDEs Problem mit printf_flt library beim linken


von Ha Jo (Gast)


Lesenswert?

Hallo,

ich nutze WINAVR, Version: WINAVR20071221.
Der verwendete Controller ist ein MEGA32.

Ich wollte mal zum ausprobieren die "Luxus"-printf Variante verwenden, 
also die auch die Fließkommaausgaben verarbeiten kann.

Nun habe ich in der Doku der AVR-LIBC nachgelesen, wie man die Libray 
dazu linkt. Geschrieben steht dort folgendes:

If the full functionality including the floating point conversions is 
required, the following options should be used:
-Wl,-u,vfprintf -lprintf_flt -lm

Das habe ich gemacht, wie man unten sieht. Leider gibt es auch 
Fehlermeldungen, so dass da linken nicht funktioniert.

Building target: Loetst.elf
Invoking: winAVR Linker
avr-gcc -Wl,-u,vfprintf -lprintf_flt -lm -mmcu=atmega32 -o"Loetst.elf" 
./trunk/cmdline.o ./trunk/drveeprom.o ./trunk/drvheat.o 
./trunk/drvtemp.o ./trunk/drvtimer.o ./trunk/drvuart.o ./trunk/ioadc.o 
./trunk/iotimer.o ./trunk/lcd_driver.o ./trunk/main.o ./trunk/pid.o 
./trunk/regulator.o
c:/programme/winavr/bin/../lib/gcc/avr/4.1.2/../../../../avr/lib/avr5\li 
bc.a(floatsisf.o):  In function `__floatsisf':
(.text.fplib+0x4): multiple definition of `__floatsisf'
c:/programme/winavr/bin/../lib/gcc/avr/4.1.2/avr5\libgcc.a(_si_to_sf.o): 
(.text+0x0):  first defined here
c:/programme/winavr/bin/../lib/gcc/avr/4.1.2/../../../../avr/lib/avr5\li 
bc.a(fp_cmp.o):  In function `__lesf2':
(.text.fplib+0x0): multiple definition of `__ltsf2'
c:/programme/winavr/bin/../lib/gcc/avr/4.1.2/avr5\libgcc.a(_lt_sf.o):(.t 
ext+0x0):  first defined here
c:/programme/winavr/bin/../lib/gcc/avr/4.1.2/../../../../avr/lib/avr5\li 
bc.a(fp_cmp.o):  In function `__gesf2':
(.text.fplib+0x8): multiple definition of `__gtsf2'
c:/programme/winavr/bin/../lib/gcc/avr/4.1.2/avr5\libgcc.a(_gt_sf.o):(.t 
ext+0x0):  first defined here
make: *** [Loetst.elf] Error 1

Wenn ich folgenden mache funktioniert es. Wo ist denn da der 
Unterschied ? -lm am Ende der Befehlszeile, klar! Aber warum geht es 
dann? Wenn ich -lm weglasse, sind die Fehlermeldungen wie oben und dass 
ich -lm brauche ist mir schon klar. Es schent, dass bei dem ersten 
Linkeraufruf das -lm nicht gesehen wird?
Building target: Loetst.elf
Invoking: winAVR Linker
avr-gcc -Wl,-u,vfprintf -lprintf_flt -mmcu=atmega32 -o"Loetst.elf" 
./trunk/cmdline.o ./trunk/drveeprom.o ./trunk/drvheat.o 
./trunk/drvtemp.o ./trunk/drvtimer.o ./trunk/drvuart.o ./trunk/ioadc.o 
./trunk/iotimer.o ./trunk/lcd_driver.o ./trunk/main.o ./trunk/pid.o 
./trunk/regulator.o   -lm
Finished building target: Loetst.elf

Eine weitere Frage noch noch zu -lm. Wenn ich nur Fließkommarechnungen 
verwende, ohne printf dazu und die Option -lm weglasse, funktioniert 
das linken. Die erzeugte Datei ist allerdings größer als mit der Option. 
Was wird denn dazugelinkt, wenn ich -lm weglasse?

Danke für Hinweise.

Hajo

von Ha Jo (Gast)


Lesenswert?

Haaaallooooooo.....

Keiner zu Haus?
Hat da keiner eine Idee zu?
Echt bitter. :-(

drängel ;-)

Hajo

von Andreas K. (a-k)


Lesenswert?


von Ha Jo (Gast)


Lesenswert?

Das erklärt meine zweite Frage, also daß eine Standard-Lib vom GCC dazu 
gelinkt wird, wenn man -lm wegläßt. Ist jedenfalls mein Verständnis.

Meine eigentliche Frage, warum z.B. __floatsisf sogar multiple ist 
anstatt zu fehlen, dass begreife ich nicht. Passiert mit folgender 
Anweisung:
avr-gcc -Wl,-u,vfprintf -lprintf_flt -lm -mmcu=atmega32... object files

Wenn ich folgende mache, dann geht es (-lm jetzt am Ende):
avr-gcc -Wl,-u,vfprintf -lprintf_flt -mmcu=atmega32... object files  -lm

Das begreife ich nicht.
Dein Patch für __floatunsisf u.s.w. den habe ich begriffen. Aber mein 
Problem hängt doch nicht damit zusammen?!

Danke
Hajo

von Andreas K. (a-k)


Lesenswert?

Ich denke schon - sobald der Floating-Point-Code aus der libgcc kommt, 
hast du verloren.

von Ha Jo (Gast)


Lesenswert?

Und warum unterscheiden sich die beiden Aufrufe für den Linker?
Das kapiere ich nicht. In beiden steht doch -lm drin.

Und außerdem ist es doch so, wenn ich die GCC-Lib nehme, fällt der 
Standard-Krams vom GCC weg? Verstehe echt nix mehr.

Hajo

von Andreas K. (a-k)


Lesenswert?

Probier mal die Vorversion vom WinAVR.

von Ha Jo (Gast)


Lesenswert?

Hatte ich schon wolte ich gerade schreiben. Da viel mir ein, dass ich 
die Vorversion von WINAVR mit der AVR-LIBC 1.5.1 "gepatcht" hatte. Darum 
war das Verhalten gleich. Jetzt habe ich die alte Version mit der 
ausgelieferten AVR-LIBC probiert und dann funktionieren beiden 
Befehlszeilen für den Linkeraufruf. Nur die Codegröße ist bei -lm am 
Ende der Befehlszeile kleiner. Wieso wird denn schenbar das .lm hier 
nicht genutzt?
avr-gcc -Wl,-u,vfprintf -lprintf_flt -lm -mmcu=atmega32... object files

Klingelingeling
Und ich glaube jetzt begreife ich langsam, was da passiert. Wenn er -lm 
nicht erkennt, nimmt er seine Standardlib. Die wiederum kollidiert mit 
der dazugelinkten printf_flt. Man muß -lm nutzen, damit auch printf_flt 
funktioniert. Und das passiert bei der alten WINAVR nicht. Da kollidiert 
es auch nicht.

Kannst Du das so bestätigen?

Das muß ich in meinem Alter erstmal begriefen ;-)

Hajo

von Ha Jo (Gast)


Lesenswert?

Wieso wird denn scheinbar das -lm hier nicht genutzt?
avr-gcc -Wl,-u,vfprintf -lprintf_flt -lm -mmcu=atmega32... object files

Habe schon im GCC-Manual nachgelesen aber ich kapiere es nicht.

Hajo

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


Lesenswert?

Das -lm sollte nach all deinen Objektdateien stehen, nicht davor.

von Andreas K. (a-k)


Lesenswert?

Ha Jo wrote:

> *Klingelingeling*

Yep.

von Ha Jo (Gast)


Lesenswert?

Danke Jörg. Habe ich jetzt verstanden. Mich hat interessiert warum das 
so ist. Ich bin dann doch fündig geworden in der AVR-LIBC Doku unter 
"Using the GNU Tools". -lm am Ende, damit der Linker die noch nicht 
aufgelösten Symbole dann aus libm holt. Ich hoffe ich habe das richtig 
verstanden.

Aber warum wird dann bei der "alten" (Vorgänger) Version von WINAVR der 
Code größer, wenn ich -lm so angebe wie hier, also nicht am Ende:
avr-gcc -Wl,-u,vfprintf -lprintf_flt -lm -mmcu=atmega32... object files

Also das -lm wird auch dann "verstanden", führt aber zu größerem Code. 
Der Linker packt Code dazu, der unnötig ist!? Würde gerne den 
Linkvorgang genauer verstehen. Wo gibt es Infos? Habe gerade im LD 
Manual nachgesehen. Da steht es nicht.

Danke
Hajo.

Edit: Habe zu lange "woanders" gelesen und nach Infos gegraben. Da habe 
ich Andreas sein yep übersehen. Auch Dir natürlich ein "danke schön".

von Andreas K. (a-k)


Lesenswert?

Es gibt zwei Floating-Point-Libs. Eine kleine in der libm und eine 
erheblich grössere und unerwünschte in der libgcc. Das gilt soweit für 
beide Versionen von WinAVR.

Ohne libm oder mit libm vorneweg erwischst du die Version aus der 
libgcc, was erstens Platz kostet, zweitens in Verbindung mit printf zu 
Konflikten führen kann.

In der aktuellen Version besteht das Risiko, dass man auch bei korrekter 
Plazierung von -lm Teile aus der libgcc erwischt, weil in der libm etwas 
fehlt. Das kann dann auch zu Fehlermeldungen bzgl. Doppeldefinition 
führen. In der Vorversion passiert das nicht, da fehlt nichts.

von Ha Jo (Gast)


Lesenswert?

Oh man, ich werd doch noch schlau ;-) Danke nochmal für die ausführliche 
Erklärung Andreas. Das habe ich verstanden, soweit hatte ich dann auch 
schon vermutet. Wenn mir das aber einer bestätigt, dann freue ich mich.

Was mir aber noch nicht klar ist, warum erwischt man bei einem -lm 
vorweg die libgcc? Ich meine -lprintf_flt steht ja auch vorneweg. Das 
ist dann wieder richtig.

Sorry wenn es nervt. Aber ich möchte das einfach verstehen.
Eben hat mir Tante Google schon einen schönen Link gegeben:
"Beginner's Guide to Linkers".
Und es wird der LD behandelt. Da werde ich dann mal lesen.

Aber vielleicht hat ja noch einer Lust mir meine Frage oben noch zu 
beantworten.

Danke

Hajo

von Andreas K. (a-k)


Lesenswert?

Ha Jo wrote:

> Was mir aber noch nicht klar ist, warum erwischt man bei einem -lm
> vorweg die libgcc?

Weil der Linker hübsch der Reihe nach vorgeht. Wenn -lm vor der 
Verwendung von Fliesskommafunktionen angegeben wird, dann wird von der 
libm zu diesem Zeitpunkts nichts benötigt, folglich nicht eingebunden, 
sie also effektiv ignoriert. Ganz hinten folgt dann (versteckt) die 
libgcc...

von Ha Jo (Gast)


Lesenswert?

Andreas Kaiser wrote:
> Weil der Linker hübsch der Reihe nach vorgeht.

Stur wie ein Beamter. Oh je!

> Wenn -lm vor der
> Verwendung von Fliesskommafunktionen angegeben wird, dann wird von der
> libm zu diesem Zeitpunkts nichts benötigt, folglich nicht eingebunden,
> sie also effektiv ignoriert.

Ja das leuchtet mir dann ein. Davon wäre ich jetzt nicht ausgegangen. 
Ich hätte vermutet, er macht sich von den angegeben Files, egal ob .a 
oder .o ein "Gesamtbild" und bindet dann die benötigten Teile zusammen.

Aber..... so ganz erklärt es nicht, warum -lprintf_flt vorneweg dann 
richtig ist. libprintf_flt wird zu dem Zeitpunkt wahrschienlich schon 
benötigt, da irgendjemand verstecktes danach verlangt?! Das hängt evtl. 
mit dem -u vfprintf zusammen??

Ich danke Dir schon wieder. Ich weiß Du hast schon mehrere Schubkarren 
"Danke chön" im Garten stehen ;-)

Erstmal gute Nacht jetzt.

Hajo

PS. Ich träume bestimmt von undefined symbols und suche wie verrückt 
danach ;-)

von Andreas K. (a-k)


Lesenswert?

In avr-libc 1.6.1 ist die Fliesskomma/String-Konvertierung, die von 
libprintf_flt verwendet wird, völlig autark und verwendet keine Funktion 
der Floating-Point-Lib. In avr-libc-1.4.5 jedoch sehr wohl.

Der Schlüssel zum Verhalten der Linkers ist "-u vprintf" in dessen 
Zeile. Damit wird das frühzeitige Laden von vprintf aus der nächsten 
passenden Lib erzwungen. Das ist hier die libprintf_flt.

Ohne -u entstünde das Problem, dass deine Objektfiles möglicherweise nur 
printf() verwenden, kein vprintf(). printf() ist jedoch nur in der libc 
drin, verwendet aber seinerseits vprintf(). Das in diesem Fall 
unweigerlich auch aus der libc käme. Das ist nur zu verhinden, indem 
vprintf() schon definiert ist.

von Ha Jo (Gast)


Lesenswert?

Hallo Andreas,

danke nochmal für die Erklärung. Das hilft dann doch, es zu verstehen.
Sind diese Abhängigkeiten eigentlich dokumentiert? Oder muß man, um
das herauszufinden, sich den Inhalt der Libs ansehen oder sich sogar den 
Sourcecode anschauen?

Hajo

von Andreas K. (a-k)


Lesenswert?

Ha Jo wrote:

> Sind diese Abhängigkeiten eigentlich dokumentiert?

Nein.

> Oder muß man, um das herauszufinden, sich den Inhalt der Libs ansehen

Die Symbolliste. Beispielsweise:
  avr-nm libprintf_flt.a

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


Lesenswert?

Dass man alle printf-Mitglieder auf eine zentrale Funktion
(in der Regel eben vfprintf) zurückführt, ist gängige Praxis.

Wenn ich mal dazu komme, werde ich mal in die weiteren
Bibliotheken die anderen Mitglieder der Familie mit aufnehmen.
Dann braucht man den Hack mit -Wl,-uvfprintf nicht mehr.

Da Bibliotheken der Auflösung bis dato unbekannter Symbole dienen
sollen, gibt man sie immer am Ende auf der Linkerkommadozeile an.

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.