Statische Elemente einer Klasse innerhalb einer Bibilothek



  • hi,
    ich hab jetzt mal ein ... komisches Problem...
    Ich habe eine Bibilothek geschrieben, die aus einer Loader- und beliebig vielen API-Verwaltungs-Klassen besteht. Der Loader verwaltet diese API-Klassen, so dass über den Loader neue Elemente der API Verwaltungs Klassen erstellt werden können und ausgelesen werden kann, auf welche dieser APIs überhaupt zugegriffen werden kann, etc.

    Jetzt muss die Loader-Klasse ohne direkt Aufruf einer Funktion (d.h. vor start der Main) über die existenz aller API-Verwaltungs-Klassen Bescheit wissen, dies bedeutet, dass jede Klasse ein statisches Element besitzt, bei dessen Deklaration (die id der API) eine statische Funktion der LoaderKlasse aufgerufen wird, mit der sich die API "einträgt".
    Soweit so gut, so tuend. Das Problem kommt jetzt, wenn ich das ganze in eine Bibilothek verschiebe, dann werden die statischen Variablen (ids) der API-Verwaltungs-Klassen nicht mehr deklariert... kann mir das einer erklären?

    Christopher Nerz

    P.S.: Wozu das Ganze? Die hier verwalteten APIs sind Brenner-APIs, die je nach System zu Verfügung stehen oder nicht. Um die Verwendung der Gesamtstruktur möglichst einfach zu halten existiert die Loader Klasse durch die ein Bibilotheks-Anwender (Programmierer) abfragen kann, welche APIs existieren (programmiert sind), welche verfügbar sind (auf dem aktuellen System), etc. Außerdem kann er einfach eine "beliebige" API verangen, so dass er einfachst Dateien brennen kann, so dass "Anwender" der Bibilothek (Programmierer) sich nicht mit den unterschiedlichen Brenner-APIs - nicht mal mit deren Anzahl oä - rumschlagen müssen.



  • Hallo,
    wenn du Bibliothek schreibst, meinst du dann eine statische Lib? Unter Windows oder unter Unix/Linux?



  • in diesem Fall eine statische lib unter win



  • Esleborn schrieb:

    Jetzt muss die Loader-Klasse ohne direkt Aufruf einer Funktion (d.h. vor start der Main) über die existenz aller API-Verwaltungs-Klassen Bescheit wissen, dies bedeutet, dass jede Klasse ein statisches Element besitzt, bei dessen Deklaration (die id der API) eine statische Funktion der LoaderKlasse aufgerufen wird, mit der sich die API "einträgt".
    Soweit so gut, so tuend. Das Problem kommt jetzt, wenn ich das ganze in eine Bibilothek verschiebe, dann werden die statischen Variablen (ids) der API-Verwaltungs-Klassen nicht mehr deklariert... kann mir das einer erklären?

    Das hängt mit der Semantik von statischen Bibliotheken zusammen. Eine statische Bibliothek ist keine Einheit, die irgendwie zu deinem Programm dazugelinkt wird. Vielmehr besteht eine statische Bibliothek einfach aus einer Sammlung von obj-Dateien. Linkst du gegen eine solche Bibliothek, so werden nur genau die obj-Dateien zu deinem Programm gelinkt, die mindestens ein externes Symbol deiner Anwendung auflösen, dass ohne die obj-Datei nicht aufgelöst worden wäre.

    Angenommen du hast die Dateien a.cpp, b.cpp und c.cpp, welche jeweils eine konkrete API-Verwaltungsklasse definieren. Dazu loader.cpp (definiert die Loader -Klasse) und api.cpp (definiert die Basisklasse für alle Api-Verwaltungsklassen) . Weiterhin nehmen wir an, dass du alle aus den oben genannten Dateien resultierenden Objektdateien in eine statische Lib packst.

    Was dann am Ende Teil deiner Anwendung ist, hängt einzig vom Anwendungscode ab, nicht vom Inhalt der Bibliothek. Sollte deine Anwendung z.B. ausschließlich die Loader-Klasse, sowie die Api-Basisklasse verwenden aber niemals konkrete API-Klassen referenzieren, dann werden a.obj, b.obj und c.obj auch niemals zu deiner Anwendung gelinkt.
    Wenn diese Obj-Dateien aber nicht mitgelinkt werden, wird natürlich auch keine statische Initialisierung in den entsprechenden cpp-Dateien ausgeführt. Ergebnis: deine konkreten API-Klassen werden nicht beim Loader angemeldet.

    Es prinzipiell zwei Lösungswege für dein Problem:
    a) Du verzichtest auf die statische Bibliothek und linkst einfach explizit gegen alle Obj-Dateien.

    b) Du sorgst dafür, dass deine Anwendung pasende externe Symbole referenziert.

    Variante b) lässt sich auf verschiedene Art und Weisen realisieren.
    Hier mal zwei Möglichkeiten:
    1. Compiler-spezifische Pragmas:
    Viele Compiler/Linker bieten Schalter bzw. Pragmas um bestimmte Symbolreferenzen zu erzwingen. Beim VC kann man z.B. folgendes schreiben:

    // erzwingt eine Symbolreferenz für meinSymbol.
    // Nachteil: meinSymbol muss ein "gemangelter" Name sein. Hier hilft die Map-Datei des Compilers
    #pragma comment(linker, "/include:__meinSymbol")
    

    Wenn man jetzt ein kleines Skript baut, dass für jede konkrete API-Klasse eine solche Pragma-Direktive in eine Datei schreibt, muss die Anwendung am Ende nur noch diese Datei inkludieren.

    2. Zentrale Registrierung:
    Man verzichtet auf die dezentrale Registrierung. Stattdessen werden alle API-Klassen zentral in der loader.cpp registriert.
    Nachteil: loader.cpp ist abhängig von *allen* konkreten API-Klassen.

    Variante 1 kann man mit Hilfe von Templates auch portabel realisieren (ohne Pragmas). In diesem Fall bleibt die Registrierung selbst dezentral, dazu kommt aber eine spezielle Header-Datei, die *Vorwärtsdeklarationen* aller konkreten API-Klassen enthält.

    Falls dich die konkrete Implementation dieser Variante interessiert, sag bescheid.


Anmelden zum Antworten