Plugin-System Architektur - Symbol Sichtbarkeit



  • Moin!
    Ich erstelle gerade eine Anwendung bei der diverse Plugins geladen werden. Bisher habe ich lediglich von der Anwendung aus Funktionen der Module aufgerufen, was auch bestens funktioniert. Nun möchte ich den Modulen die Möglichkeit geben, Funktionen der Anwendung zu nutzen. Dazu habe ich eine interface-Klasse definiert, als wrapper für ausgewählte Methoden der Anwendung. Die Basisklasse der Module definiert einen pointer auf ein interface Objekt als Member, durch eine set-funktion der Basisklasse lässt sich der Pointer setzen. Zur laufzeit lege ich ein Interface-Objekt an und übergebe die Adresse des Objektes an die Set-Funktion. Lässt sich kompilieren, alles wunderbar.

    Wenn ich nun auf die Methoden des Interface-Pointers aus den Modulen heraus zugreife, krieg ich beim compilen Fehler, weil die Symbole nicht gefunden werden (undefined reference) (was ja logisch ist, weil ich nicht gegen das interface-Objektfile linke). Ich möchte dem compiler nun irgendwie in den Plugin-Modulen mitteilen, dass die implementierungen für die Symbole des interfaces nicht gesucht werden sollen, weil sie extern in der hosting Anwendung definiert sind. Ich habs mit der speicherklasse "extern" versucht und erhielt den Fehler "declaration of 'my_namespace::plugin_interface::print(std::string)' outside of class is not definition"

    definition im plugin-Modul:
    extern void my_namespace::plugin_interface::print(std::string);

    Meine Fragen:
    Ist mein Ansatz überhaupt sinnvoll? Gibt es andere/bessere Wege als einen Pointer auf ein interface-objekt aus dem hosting-process an die Plugins zu übergeben?
    Wie kann ich dem compiler beibringen dass die symbole der Methoden erst zur Laufzeit aufgelöst werden sollen?

    Info:
    cygwin, g++ 3.4.4, libs geladen mittels dlopen, plugin-symbole geladen mittels dlsym (kann ich vielleicht aus den plugins heraus dlsym benutzen um symbole des hosting-processes zu laden?)

    Mfg Leber



  • Wenn du dem Modul die Moeglichkeit geben willst, eine von aussen gegebene Aktion auszufuer=hren, dann muss das Modul auch irgendwie wissen, welche Schnittstelle diese Aktion hat. Deswegen kannst du
    a) Den Header deiner Interface-Basisklasse bei der Compilierung des Moduls mit einbinden.
    b) dem Modul einfach nur Funktionspointer uebergeben (dann kannst du allerdings keine komplizierten interface-klassen mehr uebergeben sondern nur funktionspointer, die der Schnittstelle genuegen, die du im Modul angegeben hast)
    c) Die Modulklasse mzu einem template machen, wo die Interfaceklasse ein template-parameter ist. Diese muss dann nur die operationen definieren, die das modul aufruft.



  • Danke schonmal für die Antwort 🙂

    Also ich wollte den weg über das einfache einbinden des Headers wählen. Ich hab mein Problem inzwischen etwas weiter erkundet: nur unter cygwin meckert der compiler bzw. der linker wegen den undefinierten Symbolen. Kompilier ich den ganzen Kram auf einem echten linux-system mit den gleichen optionen (-shared -fPIC -g), funktioniert es. 🙂

    Allerdings: Das plugin-Modul wird zwar problemlos kompiliert und gelinkt, allerdings entsteht zur Laufzeit ein Fehler, weil die plugin-Methode das Symbol der aufgerufenen interface-Methode nicht findet. Geladen hab ich das plugin mit den dlopen Optionen RTLD_LAZY | RTLD_GLOBAL, was sich ja aber nur auf die Symbole des plugin Moduls auswirkt, nicht umgekehrt. Ich hab jetzt gelesen dass mit dlopen(NULL,...) ein Handle zu den Symbolen des Haupt-Prozesses zur verfügung steht. Werd das gleich mal testen. Aber selbst dann müsste ich im Plugin für alle Symbole des Interfaces, die ich nutzen will dlsym aufrufen. Das könnte ich ja in der Basisklasse machen, aber ist das wirklich erforderlich? Sieht doch irgendwie doof aus..
    Ich werd heut abend mal das Problem in ein kleines Beispiel verpacken, damit ihr hier bischen anschaulichen code habt.

    P.S.: Den Weg über einen function-pointer bin ich schon gegangen, der funktionierte auch vollkommen problemlos. Nur hat dass halt den Nachteil, dass man für jede Funktion die man benutzen möchte halt einen function pointer setzen muss...was irgendwie...also neee...unschön.



  • Problem solved!

    Das Problem war, wie schon gesagt, dass die Symbole des hosting processes nicht gefunden wurden. Mein erster Ansatz war, vor dem laden der plugins mittels dlopen(NULL,RTLD_GLOBAL) die symbole für die plugins sichtbar zu machen, was aber nicht funktionierte. Nach etwas stöbern bin ich auf die linker-option -rdynamic gestoßen. Durch die Option wird erzwungen, dass beim starten alle symbole (nicht nur die verwendeten, und das scheint hier der Knackpunkt zu sein...obwohl ja im hosting process das Objekt der Interface-Klasse angelegt wird...o_O Irgendein Guru hier der das mal detailierter erläutern kann?) zum dynamischen symbol-table hinzugefügt werden.

    http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html

    btw: Das problem beim kompilieren der plugin-Module betraf nur
    gcc version 3.4.4 (cygmin special, gdc 0.12, using dmd 0.125)
    🙂


Anmelden zum Antworten