Name Mangling-Problem (dlopen, g++)



  • Hallo,

    Habe das Problem, daß eine Klasse aufgelöst wird, obwohl ich das nicht brauche. Genauer gesagt möchte ich:

    * Funktionen exportieren, damit ich sie via dlopen, dlsym, dlclose verwenden kann.
    * in diesen Funktionen Klassen verwenden, die aber nicht exportiert werden sollen.

    also eine Frage wäre, wie kann ich eine Klasse "verstecken"?

    Hier mein Testprogramm:

    Bibliothek verwendet:

    //Test.h:
    class Test
    {
      private:
    
      public:
        Test();
        ~Test();
    
    };
    
    //Test.cpp
    
    Test::Test()
    {
      printf("constr\n");
    }
    
    Test::~Test()
    {
    }
    
    //hello.cpp
    #include <iostream>
    #include "Test.h"
    
    extern "C"
    {
     void hello() {
        std::cout << "hello" << '\n';
        Test x=Test();
     }
    }
    

    Hauptprogramm:

    //main.cpp
    #include <iostream>
    #include <dlfcn.h>
    
    int main() {
        using std::cout;
        using std::cerr;
    
        cout << "C++ dlopen demo\n\n";
    
        // open the library
        cout << "Opening hello.so...\n";
        void* handle = dlopen("./hello.so", RTLD_LAZY);
    
        if (!handle) {
            cerr << "Cannot open library: " << dlerror() << '\n';
            return 1;
        }
    
        // load the symbol
        cout << "Loading symbol hello...\n";
        typedef void (*hello_t)();
    
        // reset errors
        dlerror();
        hello_t hello = (hello_t) dlsym(handle, "hello");
        const char *dlsym_error = dlerror();
        if (dlsym_error) {
            cerr << "Cannot load symbol 'hello': " << dlsym_error <<
                '\n';
            dlclose(handle);
            return 1;
        }
    
        // use it to do the calculation
        cout << "Calling hello...\n";
        hello();
    
        // close the library
        cout << "Closing library...\n";
        dlclose(handle);
    }
    

    Compileraufruf:
    * g++ -shared -rdynamic hello.cpp -o hello.so
    * g++ -ldl -lpthread main.cpp -o main

    Programmaufruf:
    ./main

    Als Fehler erhalte ich:
    Cannot open library: ./hello.so: undefined symbol: _ZN4TestC1Ev

    Diese Klasse sollte eigentlich nicht öffentlich sein, ich möchte sie lediglich innerhalb der Bibliothek verwenden.

    Wenn ich

    Test x=Test();
    

    auskommentiere, läuft das Programm durch

    Kann mir da jemand helfen?
    Gruß
    Joe



  • g++ -shared -rdynamic hello.cpp -o hello.so
    

    Ich glaube Du hast Test.cpp in der .so vergessen.



  • Hallo,
    da fehlt irgendwie der Header der das gemeinsame Interface festlegt:

    // hello.h
    #ifndef HELLO_H_INCLUDED
    #define HELLO_H_INCLUDED
    
    #ifdef _cplusplus
    extern "C" {
    #endif
    void hello();
    #ifdef _cplusplus
    }
    #endif
    
    #endif
    
    // hello.cpp
    #include "hello.h"
    #include "test.h"
    #include <iostream>
    
    #ifdef _cplusplus
    extern "C" {
    #endif
    void hello() {
      std::cout << "hello" << '\n';
      Test x=Test();
    }
    #ifdef _cplusplus
    }
    #endif
    
    //main.cpp
    #include <iostream>
    #include <dlfcn.h>
    #include "hello.h"
    int main() {
      ...
    }
    

    Das Ganze ist aber kein Standard-C++ Problem, deshalb geht's jetzt nach Linux/Unix.



  • Dieser Thread wurde von Moderator/in HumeSikkins aus dem Forum C++ in das Forum Linux/Unix verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Hallo,
    danke mal für eure Antworten

    ich habs mal so probiert, leider ohne Erfolg:
    Wenn man Test x=Test(); auskommentiert, funktioniert es.

    // hello.h
    #ifndef HELLO_H_INCLUDED
    #define HELLO_H_INCLUDED
    
    //#ifdef _cplusplus
    extern "C" {
    //#endif
    void hello();
    //#ifdef _cplusplus
    }
    //#endif
    
    #endif
    
    // hello.cpp
    #include "hello.h"
    #include "test.h"
    #include <iostream>
    
    //#ifdef _cplusplus
    //extern "C" {
    //#endif
    void hello() {
      std::cout << "hello" << '\n';
      Test x=Test();
    }
    //#ifdef _cplusplus
    //}
    //#endif
    
    //main.cpp
    #include <iostream>
    #include <dlfcn.h>
    //#include "hello.h"
    int main() {
      ...
    }
    

    Diese Modifikationen sollen garantieren, dass die Funktionen über dlsym geladen werden können, ohne dass eine Klasse bekannt sein muss.
    In main.cpp war ein include "hello.h", was ich genau nicht will. Leider macht der Compiler wieder dieselben Schwierigkeiten. Nach außen sollen die Bibliothek nur C-Funktionen zur Verfügung stellen, intern möchte ich aber Klassen verwenden.

    Hintergrund:
    ich durchsuche einen Pfad nach plugins, die dieselbe Schnittstelle aufweisen. Dort weiß ich ja nicht zur Kompilierzeit, welche Bibliotheken später geladen werden.

    Gruß,
    Joe



  • Hast Du Test.cpp denn jetzt mit in die .so gepackt?

    EDIT:
    Wenn ich die Test.cpp mitkompiliere funktioniert das Beispiel natürlich einwandfrei, dass die Klasse Test erstmal noch mit exportiert wird steht auf einem anderen Blatt...

    Nochmal EDIT:

    Erstelle eine Datei retainsym mit einer Zeile, in der "hello" steht (das Symbol was exportiert werden soll). Dann:

    g++ -shared -rdynamic hello.cpp test.cpp -Wl,--retain-symbols-file -Wl,retainsym -o hello.so



  • http://herbert.the-little-red-haired-girl.org/c-tips/unix/index.html

    Schau dir mal diesen Link an.
    Dort wird schön beschrieben, wie man unter Linux/Unix zu Libraries kommt.
    Vll. waren deine Compilerparameter "falsch".



  • Danke euch,
    es funktioniert jetzt.

    Habe in der Testklasse vergessen, den Header einzubinden und nicht mitkompiliert.
    🙄

    zum Tutorial: hab ich nicht ausprobiert, da dort gcc anstelle von g++ verwendet wird.

    und zum "retainsym": beide Varianten funktionieren. (mir ist es egal, ob die Klasse mitkommt, solange sie keinen Fehler verursacht.

    Soviel zur Vollständigkeit (damit der Nächste auch weiß, worum es geht)

    Gruß,
    Joe


Anmelden zum Antworten