2009-11-05 15 views
9

Ich entwickle eine gemeinsame Bibliothek mit C++ unter Linux, und ich möchte diese Bibliothek log4cxx für Protokollierungszwecke verwenden. Ich bin mir jedoch nicht sicher, wie ich das einrichten soll. Damit log4cxx funktioniert, muss ich ein Logger-Objekt erstellen. Wie kann ich sicherstellen, dass dieses Objekt erstellt wird, wenn meine Bibliothek geladen wird?Wie initialisiert man eine gemeinsame Bibliothek unter Linux

Ich vermute, dass es am einfachsten sein wird, das Logger-Objekt als globale Variable zu erstellen und es dann aus einer der Quelldateien meiner Bibliothek zu verwenden, indem es es als extern in den Headern deklariert. Aber wie kann ich den Logger automatisch erstellen lassen, sobald eine Anwendung eine Verbindung zur Bibliothek herstellt?

Ich weiß, dass in DLLs für Windows, gibt es eine Sache wie REASON_FOR_CALL == PROCESS_ATTACH; Gibt es eine ähnliche Sache unter Linux?

Antwort

16

In C++ unter Linux werden globale Variablen automatisch erstellt, sobald die Bibliothek geladen wird. Das ist wahrscheinlich der einfachste Weg.

Wenn Sie eine beliebige Funktion müssen aufgerufen werden, wenn die Bibliothek geladen wird, für GCC das Konstruktor Attribut verwenden:

__attribute__((constructor)) void foo(void) { 
    printf("library loaded!\n"); 
} 

Konstruktorfunktionen durch den dynamischen Linker aufgerufen werden, wenn eine Bibliothek geladen wird. Dies ist tatsächlich, wie C++ globale Initialisierung implementiert wird.

+0

Dies gilt auch für C-Bibliotheken. Es gibt auch das '__attribute __ ((destructor))' für eine Funktion, die aufgerufen wird, wenn die Bibliothek entladen wird –

+0

... und dieses Attribut hat nichts mit der Objektkonstruktion zu tun? – einpoklum

+0

@einpoklum, Recht, das hat meistens nichts mit der Objektkonstruktion zu tun. Sie können es in C verwenden, das keine Objekte enthält. Das heißt, C++ verwendet dies intern, um Konstruktoren und Destruktoren von globalen Objekten aufzurufen. –

10

Wenn Sie Ihren Code portabel zu sein, das Sie wahrscheinlich so etwas wie dies versuchen sollte:

namespace { 
    struct initializer { 
    initializer() { 
     std::cout << "Loading the library" << std::endl; 
    } 

    ~initializer() { 
     std::cout << "Unloading the library" << std::endl; 
    } 
    }; 
    static initializer i; 
} 
+1

Können Sie erklären, warum Ihre Antwort besser ist, nur Globals zu verwenden und nichts Besonderes zu tun? – einpoklum

+0

Es gibt Ihnen einen Destruktor zu bereinigen. Außerdem wird der Destruktor immer bei Programm-Exits aufgerufen, auch wenn es sich um eine Ausnahme oder einen normalen geplanten Exit handelt. –

3

eine globale (oder eine lokale statisch in einer Funktion verpackt) ist schön ... aber dann Sie Geben Sie das Land der statischen Initialisierung Fiasko (und die tatsächliche Zerstörung ist auch nicht schön).

Ich würde empfehlen, einen Blick auf die Singleton Implementierung von Loki zu werfen.

Es gibt verschiedene lebenslange Richtlinien, von denen eine Phoenix ist und Ihnen helfen wird, dieses Fiasko zu vermeiden.

Wenn Sie gerade dabei sind, lesen Sie Modern C++ Design, in dem die von Singleton aufgetretenen Probleme sowie die Verwendung der verschiedenen Richtlinien erläutert werden.

+1

+1 für die Verwendung des Wortes "Fiasko", um zu beschreiben, was andere "Hölle" nennen könnten. :) – unwind

+2

Fiasco ist ein blödes Konzept, das von der schrecklichen C++ - FAQ der Website angesprochen wurde. Es ist kein Fiasko und der Kommentar ist in diesem Bereich nicht einmal relevant, da es keine Kopplung zwischen globalen Variablen zu geben scheint. –

+2

Erlauben Sie mir, Martin zu widersprechen, aber die Versuchung, die Konstruktion oder Zerstörung von Globals zu protokollieren, ist real. –

Verwandte Themen