Content

Zweites Mini-Beispiel zur Verwendung einer Shared-Library

Wir machen eine scheinbar kleiner Änderung:

Dazu sind zwei Dinge notwendig:

Die abstrakte Klasse Foo

Die abstrakte Klasse Foo bleibt unverändert.

#ifndef FOO_HPP
#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 "foo.hpp"
#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 "foo.hpp"
#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 "foo.hpp"
#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>