2009-11-05 2 views
9

Sto sviluppando una libreria condivisa usando C++ sotto Linux, e vorrei che questa libreria usasse log4cxx per scopi di registrazione. Tuttavia, non sono sicuro di come impostarlo. Perché log4cxx funzioni, ho bisogno di creare un oggetto logger. Come posso assicurarmi che questo oggetto venga creato quando viene caricata la mia libreria?Come inizializzare una libreria condivisa su Linux

Ho il sospetto che sia più semplice creare l'oggetto logger come variabile globale e quindi utilizzarlo da uno qualsiasi dei file sorgente della mia libreria, dichiarandolo come extern nelle intestazioni. Ma come posso creare automaticamente il logger una volta che un'applicazione si connette alla libreria?

So che in DLL per Windows, c'è una cosa come REASON_FOR_CALL == PROCESS_ATTACH; c'è una cosa simile sotto Linux?

risposta

16

In C++ sotto Linux, le variabili globali verranno create automaticamente non appena viene caricata la libreria. Quindi questo è probabilmente il modo più semplice per andare.

Se avete bisogno di una funzione arbitraria di essere chiamato quando la libreria viene caricata, utilizzare l'attributo costruttore per GCC: funzioni

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

Constructor vengono chiamati dal linker dinamico quando una libreria viene caricata. Questo è in realtà l'implementazione dell'inizializzazione globale di C++.

+0

Questo è valido anche per le librerie C. C'è anche il '__attribute __ ((destructor))' per chiamare una funzione quando la libreria viene scaricata –

+0

... e questo attributo non ha nulla a che fare con la costruzione di oggetti? – einpoklum

+0

@einpoklum, giusto, questo è per lo più non correlato alla costruzione di oggetti. Puoi usarlo in C, che non ha oggetti. Detto questo, C++ lo usa internamente per chiamare costruttori e distruttori di oggetti globali. –

10

Se volete che il vostro codice sia portabile probabilmente si dovrebbe provare qualcosa di simile:

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

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

Puoi spiegare perché la tua risposta è meglio semplicemente usando globals e non facendo nulla di speciale al riguardo? – einpoklum

+0

Ti dà un distruttore per la pulizia. Inoltre, il distruttore verrà sempre chiamato alle uscite del programma anche quando si tratta di un'eccezione o di un'uscita pianificata normale. –

3

Utilizzando un globale (o di un locale statica avvolto in una funzione) è bello ... ma poi si entra nella terra del fiasco di inizializzazione statica (e anche la distruzione effettiva non è carina).

Vorrei raccomandare di dare un'occhiata all'implementazione di Loki Singleton.

Ci sono varie politiche a vita, una delle quali è Phoenix e ti aiuterà a evitare questo fiasco.

Quando ci si trova, leggere Modern C++ Design che spiega i problemi incontrati dal Singleton in profondità, nonché gli usi per le varie politiche.

+1

+1 per usare la parola "fiasco" per descrivere quello che gli altri potrebbero chiamare "inferno". :) – unwind

+2

Fiasco è un concetto stupido inventato da quel terribile sito Web C++ FAQ. Non è un fiasco e il commento non è nemmeno rilevante in questo ambito in quanto non sembra che ci sarebbe alcun accoppiamento tra le variabili globali. –

+2

Permettetemi di non essere d'accordo con Martin, ma la tentazione di registrare la costruzione o la distruzione di globals è reale. –