Content |
Zweites Mini-Beispiel zur Verwendung einer Shared-Library
Wir machen eine scheinbar kleiner Änderung:
-
Im Testprogramm testit wird nun eine Funktion testit_msg() definiert.
-
Es soll möglich sein, dass diese Funktion von den verwendeten Shared-Libraries aus aufgerufen wird.
Dazu sind zwei Dinge notwendig:
-
Bei den Implementierungen der Shared-Libraries fügen wir eine Forward-Declaration hinzu.
-
Beim Übersetzen des Testprogrammes muss die Option -rdynamic verwendet werden.
Die abstrakte Klasse Foo
Die abstrakte Klasse Foo bleibt unverändert.
#define FOO_HPP
class Foo
{
public:
virtual
void
msg() const = 0;
};
#endif
Foo-Implementierung FooHallo
Hier wurde die Forward-Declaration hinzugefügt. Zudem wird nun in der Methode msg zusätzlich die Funktion testit_msg() aufgerufen.
#include <iostream>
// forward declaration
void
testit_msg();
class FooHallo
: public Foo
{
public:
void
msg() const
{
std::cout << "Hallo!" << std::endl;
testit_msg();
}
};
// support dynamic loading
extern "C" {
Foo*
construct()
{
return new FooHallo();
}
} // extern "C"
Erzeugen von foo_hallo.so
$shell> g++ -shared -fPIC -Wall -std=c++11 -o foo_hallo.so foo_hallo.cpp $shell>
Foo-Implementierung FooWelt
Analog wird die Implementierung von FooWelt geändert:
#include <iostream>
// forward declaration
void
testit_msg();
void
main_msg();
class FooWelt
: public Foo
{
public:
void
msg() const
{
std::cout << "Welt!" << std::endl;
testit_msg();
}
};
// support dynamic loading
extern "C" {
Foo*
construct()
{
return new FooWelt();
}
} // extern "C"
Erzeugen von foo_welt.so
$shell> g++ -shared -fPIC -Wall -std=c++11 -o foo_welt.so foo_welt.cpp $shell>
Das Test-Programm
Hier wurde nur die Funktion testit_msg() hinzugefügt:
#include <iostream>
#include <link.h>
#include <string>
typedef Foo *FooConstructor();
void
testit_msg()
{
std::cout << "function testit_msg() called." << std::endl;
}
int
main(int argc, char **argv)
{
if (argc!=2) {
std::cerr << "usage: " << argv[0] << " <shared-lib>" << std::endl;
return 1;
}
void* handle = dlopen(argv[1], RTLD_LAZY | RTLD_LOCAL);
if (!handle) {
return 2;
}
FooConstructor *constructor = (FooConstructor*) dlsym(handle, "construct");
if (!constructor) {
dlclose(handle);
return 3;
}
Foo *foo = constructor();
foo->msg();
}
Ausführen und Übersetzen des Test-Programmes mit -rdynamic
$shell> g++ -Wall -rdynamic -std=c++11 -o testit testit.cpp $shell> ./testit ./foo_hallo.so Hallo! function testit_msg() called. $shell> ./testit ./foo_welt.so Welt! function testit_msg() called. $shell>
Fehlermeldung, wenn das Test-Programmes ohne -rdynamic übersetzt wird
Eine Fehlermeldung wird zur Laufzeit erzeugt, wenn aus einer Shared-Library heraus versucht wird, eine Funktion in testit aufzurufen:
$shell> g++ -Wall -std=c++11 -o testit testit.cpp $shell> ./testit ./foo_hallo.so Hallo! ld.so.1: testit: fatal: relocation error: file ./foo_hallo.so: symbol _Z10testit_msgv: referenced symbol not found Killed $shell> ./testit ./foo_welt.so Welt! ld.so.1: testit: fatal: relocation error: file ./foo_welt.so: symbol _Z10testit_msgv: referenced symbol not found Killed $shell>