2009-11-05 16 views
9

Pracuję nad biblioteką współdzieloną przy użyciu C++ pod Linuksem i chciałbym, aby ta biblioteka używała log4cxx do celów rejestrowania. Jednak nie jestem pewien, jak to ustawić. Aby log4cxx działał, muszę utworzyć obiekt rejestratora. Jak mogę się upewnić, że ten obiekt zostanie utworzony po załadowaniu mojej biblioteki?Jak zainicjować bibliotekę współdzieloną pod Linuksem

Podejrzewam, że najłatwiej będzie utworzyć obiekt rejestratora jako zmienną globalną, a następnie użyć go z dowolnego pliku źródłowego mojej biblioteki, deklarując go jako zewnętrzny w nagłówkach. Ale w jaki sposób mogę utworzyć program rejestrujący automatycznie, gdy aplikacja połączy się z biblioteką?

Wiem, że w bibliotekach DLL dla systemu Windows jest coś takiego jak REASON_FOR_CALL == PROCESS_ATTACH; czy pod Linuksem jest coś podobnego?

Odpowiedz

16

W C++ pod Linuksem zmienne globalne zostaną skonstruowane automatycznie, gdy tylko biblioteka zostanie załadowana. To prawdopodobnie najłatwiejszy sposób.

Jeśli potrzebujesz dowolną funkcję, która będzie wywoływana, gdy biblioteka jest załadowany, użyć atrybutu konstruktora dla GCC: Funkcje

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

Konstruktor sprawdzony przez dynamiczny linker, gdy biblioteka jest załadowana. Tak właśnie zaimplementowano globalną inicjalizację C++.

+0

Dotyczy to również bibliotek C. Istnieje również "__attribute __ ((destruktor))" dla funkcji, która ma zostać wywołana, gdy biblioteka jest rozładowywana –

+0

... a ten atrybut nie ma nic wspólnego z konstrukcją obiektu? – einpoklum

+0

@einpoklum, prawda, jest to w większości niezwiązane z budową obiektu. Możesz go użyć w C, który nie ma obiektów. To powiedziawszy, C++ używa tego wewnętrznie do wywoływania konstruktorów i destruktorów obiektów globalnych. –

10

Jeśli chcesz, aby Twój kod będzie przenośny powinieneś spróbować czegoś takiego:

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

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

Czy możesz wyjaśnić, dlaczego twoja odpowiedź lepiej jest używać globali i nie robić nic specjalnego? – einpoklum

+0

Daje ci destruktor do czyszczenia. Dodatkowo destruktor będzie zawsze wywoływany przy wyjściach programu, nawet jeśli jest to wyjątek lub normalnie zaplanowane wyjście. –

3

Korzystanie globalny (lub local-statyczne zawinięte w funkcji) jest ładny ... ale wtedy wejdź do krainy statycznego inicjowania fiasko (a faktyczna destrukcja też nie jest ładna).

Polecam rzucić okiem na implementację Lokiego w wersji Singleton.

Istnieją różne zasady dotyczące okresu użytkowania, z których jedna to Phoenix i pomoże uniknąć tego fiaska.

Podczas pracy przeczytaj Modern C++ Design, który wyjaśnia problemy napotkane przez Singleton w stopniu dogłębnym, a także zastosowania różnych zasad.

+1

+1 za użycie słowa "fiasko" w celu opisania tego, co inni mogliby nazwać "piekłem". :) – unwind

+2

Fiasco to głupi pomysł przywoływany przez tę straszną stronę C++ FAQ. To nie jest fiasko, a komentarz nie jest nawet istotny w tym zakresie, ponieważ nie wydaje się, aby istniało sprzężenie między zmiennymi globalnymi. –

+2

Pozwól mi się nie zgodzić z Martinem, ale pokusa, by rejestrować budowę lub zniszczenie globaliów, jest prawdziwa. –

Powiązane problemy