GCC-Problem beim Erstellen von Bibliothen in C++
-
Tach liebe Leute,
ich bekomme langsam die Krise und hoffe, dass ihr mir helfen könnt. Vorweg, ich arbeite unter Linux, deshalb weiß ich nicht, ob das Problem auch so unter Windows auftritt, ist aber auch gut möglich! Ich habe mein Problem etwas gekürzt in ein kleines Testprogramm implementiert, darum fragt bitte nicht nach dem Sinn des Programms. Aber vielleicht erst einmal etwas Code, bei dem es darum geht, eine dynamisch ladbare Bibliothek zu erstellen:
base.h
#ifndef BASE #define BASE class CBase { public: CBase(); virtual ~CBase(); }; #endif
base.cpp
#include "base.h" #include <iostream> CBase::CBase() { #ifdef LIBRARY std::cout << "Library" << std::endl; #else std::cout << "Test" << std::endl; #endif } CBase::~CBase() { }
library.cpp
#include <iostream> #include "base.h" class CFoo : public CBase { public: CFoo() : CBase() { } ~CFoo() { } }; extern "C" void test() { CFoo(); }
Das übersetze ich nun (unter Linux) mit den folgenden 2 Zeilen:
g++ -DLIBRARY -c library.cpp base.cpp gcc -shared -o liblibrary.so library.o base.o
und kopiere anschließend die erzeugte Datei "liblibrary.so" nach "/usr/lib"
Soweit, so gut. Die Bibliothek hat nun eine exportierte Funktion "test", bei dessen Aufruf der Text "Library" in der Konsole/Eingabeaufforderung erscheint (wegen dem beim übersetzen gesetzen define LIBRARY).
Das Tut's auch, aber nicht immer! Und zwar dann nicht, wenn ich nun folgendes Programm schreibe, welches die Bibliothek verwendet:test.cpp
#include "base.h" extern "C" void test(); int main(int, char**) { CBase() // Es erscheint "Test", da HIER beim übersetzen das Define "LIBRARY" nicht gesetzt wurde. test(); // Es sollte "Library" erscheinen, denn beim übersetzen war "LIBRARY" definiert. -> Es erscheint wieder "Test" return 0; }
Das wird abschliessend noch wie folgt übersetzt, was zum Executable "test" führt.
g++ -llibrary base.cpp test.cpp -o test
Ja, das Ergebnis ist die folgende Ausgabe:
Test Test
Wenn ich allerdings folgenden Code verwende
#include <iostream> extern "C" void test(); int main(int, char**) { std::cout << "Test" << std::endl; test(); // Es sollte "Library" erscheinen, denn beim übersetzen war "LIBRARY" definiert. -> Es erscheint wieder "Test" return 0; }
und dies ohne base.cpp übersetze, also so
g++ -llibrary base.cpp test.cpp -o test
erscheint, wie ich es auch gerne im ersten Fall hätte
Test Library
Der scheint also beim Laden der Bibliothek die Adressen irgend wie umzubiegen, so dass CFoo nicht mehr von der CBase-Version in der Klasse ableitet, sondern von der des ausführbaren Programms. Was soll der Müll? Ich weiss wohl, dass die Reihenfolge in der die Bibliotheken in einem solchen Fall geladen werden etwas zur Sache tun, und hier ist das Hauptprogramm halt die "Bibliothek", die als erstes kommt, aber das muss doch auch anders gehen.
Wenn ich eine fremde Bilbiothek verwende kann es ja nicht angehen, daß ich in meinem Hauptprogramm keine Klassennamen mehr verwenden kann, die ein mir unbekannter Entwickler bereits schon in eben diese Bibliothek verwendet hat.Das Problem muss beim Übersetzen der Bibliothek sein. Da muss es wahrscheinlich irgend welche Compilersettings geben, die ich nicht kenne. Als Ergebnis sollte eine Bibliothek heraus kommen, bei der alle Sprungadressen bereits festgelegt sind bzw. soll von außen nichts mehr davon zu sehen sein, daß da eine Klasse mit dem Namen "CBase" vorkommt.
Ich hoffe echt, daß mir hier jemand helfen kann!
Schon mal vielen Dank im Voraus!
(PS: Ich hätte dies imho zwar in Linux-Forum gepostet, aber da steht oben direkt, daß Fragen zum GCC hierhin gehören. Ich hoffe, daß ich hier richtig bin)
-
hi,
zuerst mal zu deinem problem:
du compilierst jedes mal 'base.cpp' neu mit ein (und zwar ohne -DLIBRARY), daher gibt es spaeter keine unresolved symbols die der linker aufloesen muesste und das statisch eincomplierte CBase ist ja ohne -DLIBRARY.das zweite:
wenn du libraries bastelst dann musst du deine libs nicht jedes mal nach /usr/lib (oder wo halt deine libs sind) kopieren.
du kannst sie in deinem working dir belassen und setzt stattdessen ein paar linker options und die env-variable LD_LIBRARY_PATH.
genau erklaeren moechte ich das jetzt hier nicht, ich kann dir nur empfehlen
dir ein howto fuer "elf linking" zu suchen und eventuell die man-pages von ld und gcc nochmals anzusehen.$ g++ -shared -DLIBRARY base.cpp library.cpp -o libfoo.so $ g++ test.cpp -L. -lfoo $ LD_LIBRARY_PATH=. ./a.out
das liefert dir dann den gewuenschten output von:
Library Library
(anm: ich hab die zuerst gepostete test.cpp mit CBase(); test(); genommen)
ich hoffe das hilft dir weiter
go on and hapyy hacking