C++ linking ...

rubricanis

Homo ludens
Ich habe jetzt eine Zeit lang cmake benutzt was auch ganz gut funktioniert hat. Allerdings bin ich an Windows nicht interessiert und so erscheint mir das als eine eigentlich überflüssige Komplikation. Zurück zu gmake stoße ich allerdings auf Link-Probleme:

Ich habe eine Biblothek libFoo.so. Beim Versuch die in main() statisch einzubinden bekomme ich folgenden Fehler: 'Shared object "libFoo.so" not found, required by "app"' den ich mir einfach nicht erklären kann. Die Pfade stimmmen definitiv (ich habe die sogar aus der shell herauskopiert um sicher zu sein). Hier das nur marginal veränderte Makefile (die genannten Variablen verstehe sich wohl von selbst):
Code:
target := app

depend := $(build)/$(target).d

obj :=    main.o

objects := $(patsubst %,$(build)/%,$(obj))
depend := $(objects:.o=.d)

# target 
$(target): $(objects)
   @echo "==> $(target)"
   @$(cxx)  $(objects) $(flags) \
       -L/home/peter/project/lib -lFoo \
       -o $(bin)/$(target) 
   
$(build)/%.o: $(src)/%.cpp
   @$(cxx) -c $(flags) -o $@ $<

-include $(depend)
An was könnte das liegen? Kann das auch mit der Lib etwas zu tun haben was ich mir eigentlich nicht forstellen kann.

Ich weiß das -L(Pfad) nicht der Weisheit letzter Schluss ist aber zumindest das sollte doch funktionieren.

Peter
 
Yep, das war es! Reihenfolgeabhängigkeit, so ein MIST!
Da rödelt man einen ganze Abend lang mit rum und dann sowas...:(

Ich danke dir! Jetzt sollte ich auch -rpath hinbekommen ...

Aber noch eine Nachfolgefrage: Wie ist das mit fooLib.a ? Mit -L und dan -lfooLib a funktioniert das nicht. Oder gilt -L nur für dynamische Libs und für Archive muss der Pfad direkt inach -l eingegeben werden?
 
Mit den .a weiß ich nicht, ich würde vermuten, dass Du die einfach wie die Object-Files mit angibst.
 
..., jetzt sollte ich auch -rpath hinbekommen ...
Das war wohl nichts! :(
Code:
$(target): $(objects)
     @echo "==> $(target)"
     @$(cxx) -Wl,-rpath/home/peter/project/lib/   -lFoo \
       -o $(bin)/$(target) $(flags) $(objects)
Jetzt bekomme ich die Fehlermeldung "bad -rpath option". Ich habe das mit und ohne Slash '/' hinter dem Pfad ausprobiert. Was ist da jetzt los? Was außer dem Pfad kann da falsch sein?

Meine Güte, ist das fragil...:mad:
 
-rpath=/home/peter/project/lib
Hmm, jetzt bekomme ich "cannot find -lFoo". Nach allem was ich bislang gehört und gelesen habe ist da kein '=' notwenig. Er sucht Foo wohl jetzt direkt auf $PWD und kann es natürlich nicht finden. Ich habe auch Wl,-R/home... ausprobiert aber das ändert nichts.
 
Ich denke gerade über folgendes nach: Ich verwende clang++36 unter DragonFlyBSD mit gmake. Ob da irgend etwas durcheinander kommen kann ? Was ich noch tun könnte ist ld direkt zu verwenden und nicht indirekt. Das werd ich heute abend mal ausprobieren. Aber für jetzt habe ich erst einmal die Sch... voll von dem Mist. Ich hoffe ich muss nicht auf cmake zurückgreifen ... :rolleyes:
 
Statische Libraries kann man wie Kamikaze schon schrieb als Objektdateien mitangeben, da sollten auch absolute Pfade funktionieren.
Den rpath gebe ich im Normalfall dem Compiler via -Wl,-rpath -Wl,/home/peter/project/lib mit. Details dazu solltest du aber in ld(1) finden, auf FreeBSD ist ein Leerzeichen zwischen -rpath und dem Pfad dokumentiert. -R ist IMHO gefährlich:
ld(1) said:
For compatibility with other ELF linkers, if the -R option is
followed by a directory name, rather than a file name, it is
treated as the -rpath option.

In deinem Auszug oben fehlt übrigens -L/home/peter/project/lib. -rpath ist für die Laufzeit relevant, -L für die Linkzeit. Das mag dir jetzt vielleicht umständlich und fragil erscheinen, ist aber beim Bauen für andere Maschinen/Architekturen wichtig.
 
In deinem Auszug oben fehlt übrigens -L/home/peter/project/lib. -rpath ist für die Laufzeit relevant, -L für die Linkzeit. Das mag dir jetzt vielleicht umständlich und fragil erscheinen, ist aber beim Bauen für andere Maschinen/Architekturen wichtig.
Hmm, wenn ich den gleichen Pfad für -L bei Wl,-rpath angebe denke ich dass im Falle von -L die Lib statisch gelinkt wird und im Falle von -rpath dass der loader das entsprechend dem angegebenen Path erledigt. Ich brauche also nicht beides oder liege ich da falsch ?

Ich habe alle genannten Varianten durchprobiert und keine funzt. Ich bekomme dann immer "cannot find -lFoo". Nur bei meiner o.g. Variante kommt "/usr/libexec/binutils224/elf/ld.bfd: bad -rpath option".
 
-L hat mit statischem oder dynamischem Linken nichts zu tun, damit wird lediglich der Suchpfad für Bibliotheken spezifiziert.
Dynamisches Linken besteht aus zwei Stufen: einmal gibt es die Linkzeit, zu der der Linker die Symbole auflöst und zuordnet und einmal die Ladezeit bevor das Programm ausgeführt wird, wo der Laufzeit-Linker oder Loader oder wie man es auch nennt die relocations vornimmt und sich um den Speicher kümmert. Ersterer nutzt -L, zweiterer nutzt -rpath, entsprechend brauchst du beides.
Wie man einen Compiler zum statischen Linken zwingt weiß ich gerade nicht auswendig, ich hab in dem Fall immer die Archivdateien (libFoo.a) wie Objektdateien angegeben und war zufrieden. clang -L/home/foo/bar -lFoo $(objs) linkt aber auf jeden Fall dynamisch.

Meines Erachtens müsste deine Kommandozeile für dynamisches Linken also so aussehen:
$(cxx) -Wl,-rpath -Wl,/home/peter/project/lib/ -L/home/peter/project/lib/ -lFoo -o $(bin)/$(target) $(flags) $(objects)
Und für statisches Linken (vermutlich) so:
$(cxx) $(flags) -o $(bin)/$(target) $(objects) /home/peter/project/libFoo.a

Sobald ich zuhause bin kann ich es nochmal genauer anschauen und ausprobieren.

Edit: Wie konnte ich das nur vergessen… mit
$(cxx) $(flags) -o $(bin)/$(target) -L/home/peter/project/lib -static $(objects) -lFoo
wird statisches linken erzwungen.
edit2: Reihenfolge im obigen Satz korrigiert, beim statischen Linken ist die Reihenfolge der Bibliotheken wichtig.
 
Ich denke ich verstehe langsam. Die -L option wir gebraucht um die benötigten Symbole der Lib in das binary der application zu schreiben. Gefunden und relokiert werden sie dann durch den loader mit -rpath oder - falls die Lib da nicht gefunden wird - eben die std pfade. Und LD_LIBRARY_PATH überschreibt alles.

Also dein Weg scheint soweit zu funktionieren. Allerdings bekomme ich jetzt den Fehler "undefined referenz to 'main'" was ich mir nicht erklären kann. Ich poste mal die aktuelle version:
Code:
target := app

depend := $(build)/$(target).d

obj :=    main.o

objects := $(patsubst %,$(build)/%,$(obj))
depend := $(objects:.o=.d)

libs:= \
   -lFoo
 
$(target): $(objects)
   @echo "==> $(target)"
   @$(cxx) -Wl,-rpath -Wl,/home/peter/project/lib \
       -L/home/peter/project/lib  $(libs) \
       $(flags) -o $(bin)/$(target) $(objects)
   
$(build)/%.o: $(src)/%.cpp
   @$(cxx) -c $(flags) -o $@ $<

-include $(depend)

Gehe ich richtig in der Annahme dass ich weitere -rpath Pfade mit -Wl, einfach dranhängen kann, z.B.
-Wl,/usr/local/lib/ und/oder -Wl,/usr/local/myapp/lib
 
Ich kenne mich mit gmake nicht sonderlich gut aus, was macht der pathsubst-Aufruf?
Funktioniert der Befehl manuell von der Kommandozeile, wenn alle Variablen durch die tatsächlichen Werte ersetzt werden?
Ansonsten lass halt mal das @ vom aktuellen Compileraufruf weg und schau ob alle Variablen in der Kommandozeile richtig gesetzt sind.
Wie es scheint fehlt da die Objektdatei, in der main definiert ist.
 
OK, alles gut! :) Ich hatte da einen minimalen Schreibfehler mit drin. :( Zumindest scheint der Linker zu funktionieren, jetzt muss ich nur noch die Funktionen der Lib überprüfen. Dann muss ich noch die -soname Geschichte in den Griff bekommen...

Kamikaze, Goblin, ich bin euch zutiefst dankbar! Ich war nahe daran aufzugeben...:rolleyes:

Peter

PS: Es ist erstaunlich dass man über Schreibfehler immer wieder drüberliest, auch wenn man das 20x durchgegangen ist.
 
Back
Top