Anfängerfrage: Linker...
-
hi!
vorab, das ganze spielt sich unter linux ab und da ich bisher nur vc++ nutzte, hab ich absolut keine ahnung, wie mir geschieht. in meinen büchern steht auch nur, wie es mit visual c++ geht... aber ich nutze doch gcc ...
habe mir in den kopf gesetzt, dass ich http://ndevilla.free.fr/iniparser/ nutzen möchte in meiner anwendung.
also lud ich mir die src dazu herunter. hab sie entpackt und fertig gemacht... nun würde ich sie also gerne nutzen. was ich habe sind *.h und .c dateien. müsste vermutlich erstmal .o dateien draus machen, wobei mir dabei schon die ahnung fehlt!
oder geht das mit gcc -c -o iniparser.o iniparser.c?
und selbst wenn ich das dann habe, weiß ich immer noch nicht, wie es (mit kdevelop) gelinkt wird bzw was ich als ldflags verwenden soll.
hab die header und c-dateien ins src verzeichnis meiner anwendung kopiert.->kann also #include "iniparser.h" einbinden. ist ja schonmal etwas, möchte man meinen... aber irgendwas scheint noch zu fehlen, denn sobald ich eine funktion von inparser aufrufe, gehts nicht mehr => undefined reference to ..function_name...(char) sagt mir kdevelop.wüsste also gerne folgendes:
-welche dateien brauche ich in welchem verzeichnis
-wie komm ich zu den dateien
-welchen ldflag habe ich zu setzen, damit das gelinkt wird?vielen dank im falle von hilfe
-
habe nun herausgefunden, wie ich an die objektdateien komme und wie ich sie in eine libiniparser.a zusammenbringe, dann versuchte ich
g++ -o hello_world_cpp hello_world_cpp.cpp -lcurl libiniparser.a
/tmp/ccphMj1g.o: In functionmain': hello\_world\_cpp.cpp:(.text+0x70e): undefined reference to
iniparser_load(char*)'
hello_world_cpp.cpp:(.text+0x724): undefined reference to `iniparser_getstr(_dictionary_, char)'
collect2: ld returned 1 exit statusalso hats letztendlich nichts gebracht
was nun?
-
Ich habe jetzt nicht den ganzen Quelltext, aber es riecht nach folgendem Problem:
Schreibt man in C eine Funktion, dann sieht der Linker den Namen
etwa so, wie man ihn im Quelltext hingeschrieben hat (evtl. mit einem Tiefstrich
davor, oder so ähnlich, aber sonst unverändert).In C++ dagegen kann man mehrere Funktionen mit demselben Namen
im Quelltext haben, die sich in der Parameterliste unterscheiden (und bei
Methoden noch in Attributen wie const).
Damit der Linker jetzt die Funktionen, die ja im Quelltext gleich heißen,
auseinanderhalten kann, manipuliert der Compiler die Namen, die er
in die Objektdatei schreibt.
Mein Compiler macht beispielsweise aus einem void up() im Quelltext
den Namen _Z2upv, aus void up( int i ) wird _Z2upi und aus:
typedef struct{ int i; double dabbl; char ch[8]; } stru;
void up( float fl, stru s, void p )...
wird der Name _Z2upf4struPv für den Linker (das heißt "name mangling").
Nur deshalb kann der Linker bei dir anmeckern, daß ihm die Funktion
iniparser_load(char) fehlt; in C würde er nur den Namen iniparser kennen.
(für die Fehlermeldung wurde der interne Name, zB. _Z15iniparser_loadpc,
wieder in eine lesbare Deklaration zurück übersetzt: "demangling").Dein Problem ist jetzt, daß du C und C++ mischst.
Das iniparser-Projekt ist in C geschrieben, dein aufrufendes Programm
in C++.
Irgendwo in deiner C++-Datei hast du also ein include stehen (zB.
#include<iniparser.h>), in dieser Headerdatei steht zB. eine Deklaration
void iniparser_load(char*);
oder so ähnlich.
Weil dein Hauptprogramm als C++ kompiliert wird, steht in der erzeugten
Objektdatei drin, daß der Linker doch bitte eine Funktion mit dem Namen
_Z15iniparser_loadpc (nur als fiktives Beispiel!) beschaffen möge.
Das kann er aber nicht, weil der Kram aus deiner Bibliothek als C kompiliert
wurde, und der Compiler dabei aus void iniparser_load(char*).. nicht die
Funktion _Z15iniparser_loadpc gemacht hat, sondern nur iniparser_load.
(Tip: Man kann mit 'nm irgendwas.o' anzeigen lassen, welche Namen in der
Objektdatei stehen; definierte Funktionen stehen hinter einem T und
undefinierte/referenzierte, also vom Linker zu beschaffende hinter einem U).Lösung:
Entweder schreibst du dein Hauptprogramm in C, dann entfällt das Problem.
Oder du sagst dem C++-Compiler, welche Deklarationen als C zu verstehen
sind.
In den C-Teilen ist dann nichts zu ändern, aber man muß im C++-Teil
die Deklarationen mit einem extern "C" garnieren:
Anstatt:void iniparser_load(char*); int iniparser_getstr(_dictionary_*, char*);
müsste man entweder schreiben:
extern "C" void iniparser_load(char*); extern "C" int iniparser_getstr(_dictionary_*, char*);
oder:
extern "C" { void iniparser_load(char*); int iniparser_getstr(_dictionary_*, char*); }
Glücklicherweise sind alle betroffenen Deklarationen wahrscheinlich in einer
oder wenigen *.h zusammengefaßt; dann reicht es, das extern "C" um
die entsprechenden #includes im C++-Quelltext zu schreiben.
Also anstatt#include <iniparser> #include <vielleichtnocheinehederdateimitckram.h>
schreibt man:
extern "C" { #include <iniparser> #include <vielleichtnocheinehederdateimitckram.h> }
HTH
mfgkw
-
boah danke!