2009-11-05 27 views
9

Estoy desarrollando una biblioteca compartida usando C++ en Linux, y me gustaría que esta biblioteca use log4cxx para fines de registro. Sin embargo, no estoy seguro de cómo configurar esto. Para que Log4cxx funcione, necesito crear un objeto logger. ¿Cómo puedo asegurarme de que este objeto se crea cuando se carga mi biblioteca?Cómo inicializar una biblioteca compartida en Linux

sospecho que será más fácil de crear el objeto registrador como una variable global y luego usarlo en cualquiera de los archivos de origen de mi biblioteca, declarándolo como extern en las cabeceras. Pero, ¿cómo puedo hacer que el registrador se cree automáticamente una vez que una aplicación se conecta a la biblioteca?

sé que en DLL para Windows, hay una cosa como REASON_FOR_CALL == PROCESS_ATTACH; ¿Hay algo similar en Linux?

Respuesta

16

En C++ en Linux, las variables globales obtendrá construida automáticamente en cuanto se carga la biblioteca. Entonces esa es probablemente la forma más fácil de hacerlo.

Si necesita una función arbitraria que se llamará cuando se carga la biblioteca, utilice el atributo constructor para GCC: funciones

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

Constructor consiguen llamados por el enlazador dinámico cuando se carga una biblioteca. Así es como se implementa la inicialización global de C++.

+0

Esto también es válido para las bibliotecas C. También existe el '__ atributo __ ((destructor))' para que se invoque una función cuando la biblioteca está descargada –

+0

... ¿y este atributo no tiene nada que ver con la construcción del objeto? – einpoklum

+0

@einpoklum, a la derecha, esto en su mayoría no está relacionado con la construcción de objetos. Puedes usarlo en C, que no tiene objetos. Dicho esto, C++ usa esto internamente para llamar a constructores y destructores de objetos globales. –

10

si desea que su código sea portable probablemente debería intentar algo como esto:

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

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

¿Puede explicar por qué su respuesta es mejor simplemente usando globales y no haciendo nada especial al respecto? – einpoklum

+0

Le da un destructor para la limpieza. Además, siempre se llamará al destructor a las salidas del programa, incluso cuando sea una excepción o una salida planificada normal. –

3

El uso de un mundial (o un local estática envuelto en una función) es agradable ... pero entonces ingrese a la tierra del fiasco de inicialización estática (y la destrucción real tampoco es bonita).

recomendaría a echar un vistazo a la Singleton ejecución de Loki.

Hay diversas políticas de toda la vida, una de las cuales es Phoenix y le ayudarán a evitar este fiasco.

Cuando usted está en él, leer moderno diseño de C++ que explica los problemas encontrados por el Singleton en profundidad, así como los usos de las diferentes políticas.

+1

+1 por usar la palabra "fiasco" para describir lo que otros podrían llamar "infierno". :) – unwind

+2

Fiasco es un concepto estúpido planteado por ese terrible sitio web C++ FAQ. No es un fiasco y el comentario ni siquiera es relevante en este ámbito, ya que no parece que haya ningún acoplamiento entre las variables globales. –

+2

Permítanme estar en desacuerdo con Martin, pero la tentación de registrar la construcción o la destrucción de los globales es real. –

Cuestiones relacionadas