2010-06-07 13 views
20

que tienen un proyecto de C++ que debido a su estructura de directorios se configura como una biblioteca estática A, que está vinculado a la biblioteca compartida B, que está vinculada al ejecutable C. (Este es un proyecto multiplataforma usando CMake, por lo que en Windows obtenemos A.lib, B.dll y C.exe, y en Linux obtenemos libA.a, libB.so y C.) Biblioteca A tiene una función init (A_init, definido en A/initA.cpp), que se llama desde 'función s init (B_init, definido en B/initB.cpp), que se llama a partir de C' B biblioteca s principal. Por lo tanto, cuando se enlaza B, A_init (y todos los símbolos definidos en initA.cpp) está vinculado en B (que es nuestro comportamiento deseado).Cómo forzar la inclusión de un archivo de objeto en una biblioteca estática cuando se establece un enlace en ejecutable?

El problema viene en que la biblioteca A también define una función (Af, definido en A/Afort.f) que está destinada a por dinámicamente cargado (es decir LoadLibrary/GetProcAddress en Windows y dlopen/dlsym en Linux). Dado que no existen referencias a Af de la biblioteca B, símbolos de A/Afort.o no están incluidos en B. En Windows, podemos crear artificialmente una referencia mediante el pragma:

#pragma comment (linker, "/export:_Af") 

Dado que este es un pragma, que sólo funciona en Windows (utilizando Visual Studio 2008). Para conseguir que funcione en Linux, hemos intentado añadir lo siguiente a A/initA.cpp:

extern void Af(void); 
static void (*Af_fp)(void) = &Af; 

Esto no causa el símbolo Af que se incluirán en el último eslabón de B. ¿Cómo podemos forzar el símbolo Af a estar vinculado en B?

Respuesta

12

Resulta que mi intento original mayoría allí. Las siguientes obras:

extern "C" void Af(void); 
void (*Af_fp)(void) = &Af; 

Para aquellos que quieren una macro preprocesador autónomo para encapsular esto:

#if defined(_WIN32) 
# if defined(_WIN64) 
# define FORCE_UNDEFINED_SYMBOL(x) __pragma(comment (linker, "/export:" #x)) 
# else 
# define FORCE_UNDEFINED_SYMBOL(x) __pragma(comment (linker, "/export:_" #x)) 
# endif 
#else 
# define FORCE_UNDEFINED_SYMBOL(x) extern "C" void x(void); void (*__ ## x ## _fp)(void)=&x; 
#endif 

que se utiliza de esta manera:

FORCE_UNDEFINED_SYMBOL(Af) 
3

Usted puede utilizar la opción --undefined cuando se genera B:

g++ -Wl,--undefined,Af -o libB.so ... 
0

Trate de poner esas líneas en B/initB.cpp para que estén (con suerte) obligaron a la biblioteca en tiempo de enlace libB.so.

Pero, ¿por qué tienes que hacerlo de esta manera en absoluto? ¿No puedes configurarlo para que el ejecutable haga referencia a esa función (o a quien llama), haciendo que el enlazador haga lo correcto automáticamente?

+0

C es en realidad una interfaz de lenguaje de scripting, B es el motor de lenguaje y A es un conjunto de métodos de código nativo para que el motor lo use. Estamos implementando un lenguaje preexistente que tiene una interfaz de función externa bien definida. A y B son producidos por equipos separados; preferiríamos mantener todo lo que el equipo A escribe en el directorio A. –

0

Si puede utilizar C++ 0x características de gcc (-std = C++ 0x), entonces los argumentos de plantilla de función por defecto puede hacer el truco. A partir del estándar actual de C++, los argumentos predeterminados no están permitidos para las plantillas de funciones. Con estos habilitadas en C++ 0x, se puede hacer algo como: -

En algún archivo de cabecera de la biblioteca estática ...

template< class T = int > 
void Af() 
{ 
} 

Luego, en su correspondiente uso cpp explícita de instancias de plantilla ...

template void Af(); 

Esto generará los símbolos de la función Af pesar de que aún no se llama/referencia. Esto no afectará a las personas que llaman debido a que debido al argumento de plantilla predeterminado, no necesita especificar un tipo. Simplemente agregue el template <class T = int > antes de la declaración de la función y ejemplifíquelo explícitamente en su archivo de implementación.

HTH,

+1

Desafortunadamente, esto no funcionará porque Af es en realidad un procedimiento de Fortran. –

+0

Bueno, entonces, cree un contenedor 'C' que llame Af _ (...) [puede llamar a las funciones fortran desde 'C', es decir, el nombre de la función adjuntado con un guión bajo; Detalles de Google Nitty Gritty para argumentos, no abt C++ llamando a Fortran]. Llame a este contenedor 'C' desde C++. Por cierto, así es como una de las principales compañías financieras para la que trabajé, administró su código antiguo/horrible :-) – Abhay

+0

Es un código muy poco obvio que probablemente será eliminado por un mantenedor novato, 2 años después. Al menos la macro es lo suficientemente clara como para entender. – xryl669

5

MSVC#pragma comment(linker, "/include:__mySymbol")

gcc-u symbol

2

Hay una forma mejor de escribir esa macro FORCE_UNDEFINED_SYMBOL. Simplemente echa ese puntero a un vacío *. Entonces funciona con cualquier función o datos para ese asunto. Además, ¿por qué molestarse con los pragmas de MSVC cuando la parte gcc de su macro también funcionará para MSVC? Así que mi versión simplificada sería:

#define FORCE_UNDEFINED_SYMBOL(x) void* __ ## x ## _fp =(void*)&x; 

que se utiliza de esta manera:

FORCE_UNDEFINED_SYMBOL(Af) 

Pero debe ser utilizado en el programa que incluye la biblioteca que está teniendo sus símbolos despojado.

Cuestiones relacionadas