2010-06-07 12 views
20

Ho un progetto C++ che a causa della sua struttura di directory è impostato come una libreria statica A, che è collegata alla libreria condivisa B, che è collegata nell'eseguibile C. (Questo è un progetto cross-platform usando CMake, quindi su Windows otteniamo A.lib, B.dll e C.exe, e su Linux otteniamo libA.a, libB.so, e C.) Libreria A ha una funzione init (A_init, definito in A/initA.cpp), viene chiamata dalla funzione di inizializzazione della libreria B (B_init, definita in B/initB.cpp), che viene chiamata dal menu principale di C. Pertanto, quando si collega B, A_init (e tutti i simboli definiti in initA.cpp) è collegato a B (che è il comportamento desiderato).Come forzare l'inclusione di un file oggetto in una libreria statica quando si collega in un file eseguibile?

Il problema nasce dal fatto che la libreria A definisce anche una funzione (Af, definito in A/Afort.f) che è destinato a venire caricata dinamicamente (cioè LoadLibrary/GetProcAddress su Windows e dlopen/dlsym su Linux). Poiché non vi sono riferimenti a Af dalla libreria B, i simboli da A/Afort.o non sono inclusi in B. Su Windows, possiamo artificialmente creare un riferimento utilizzando il pragma:

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

Poiché questo è un pragma, funziona solo su Windows (utilizzando Visual Studio 2008). Per farlo funzionare su Linux, abbiamo provato ad aggiungere quanto segue a A/initA.cpp:

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

Ciò non causa il simbolo Af da inserire nel l'ultimo anello di B. Come possiamo forzare il collegamento del simbolo Af a B?

risposta

12

Si scopre il mio tentativo originale era in gran parte lì. Le seguenti opere:

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

Per coloro che vogliono un preprocessore macro autonomo per incapsulare questo:

#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 

che viene utilizzato nel seguente modo:

FORCE_UNDEFINED_SYMBOL(Af) 
3

È possibile utilizzare l'opzione --undefined quando si genera B:

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

Prova a mettere quelle linee in B/initB.cpp in modo che siano (si spera) costretti in biblioteca libB.so in fase di collegamento.

Ma perché lo devi fare in questo modo? Non puoi configurarlo in modo tale che l'eseguibile faccia riferimento a quella funzione (oa un suo chiamante), facendo sì che il linker faccia la cosa giusta automaticamente?

+0

C è in realtà un frontend di linguaggio di script, B è il motore di linguaggio e A è un insieme di metodi di codice nativo per il motore da utilizzare. Stiamo implementando un linguaggio preesistente che ha un'interfaccia di funzione straniera ben definita. A e B sono prodotti da squadre separate; preferiremmo tenere tutto ciò che l'A-team scrive nella directory A. –

0

Se è possibile utilizzare C++ 0x caratteristiche di gcc (-std = C++ 0x), poi i funzione template di default argomenti può fare il trucco. A partire dall'attuale standard C++, gli argomenti predefiniti non sono consentiti per i modelli di funzione. Con questi abilitati in C++ 0x, si può fare qualcosa di simile: -

In alcuni file di intestazione di libreria statica ...

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

Poi, nel suo corrispondente utilizzo di file cpp esplicito modello di istanza ...

template void Af(); 

Questo genererà i simboli per la funzione Af anche se non è ancora stato chiamato/riferimento. Ciò non influirà sui chiamanti perché a causa dell'argomento modello predefinito, non è necessario specificare un tipo. Basta aggiungere lo template <class T = int > prima della dichiarazione della funzione e istanziarlo esplicitamente nel suo file di implementazione.

HTH,

+1

Sfortunatamente, questo non funzionerà perché Af è in realtà una procedura Fortran. –

+0

Bene, allora crea un wrapper 'C' che chiama Af _ (...) [puoi chiamare le funzioni fortran da 'C', ad esempio il nome della funzione aggiunto al trattino basso; google nitty grintosi dettagli per argomenti, non cedo a C++ chiamando fortran]. Chiama questo wrapper 'C' da C++. A proposito, questo è il modo in cui una delle principali società finanziarie per cui ho lavorato, ha gestito il suo codice antico/schifoso :-) – Abhay

+0

È un codice molto poco ovvio che verrà probabilmente rimosso da un manutentore, 2 anni dopo. Almeno la macro è abbastanza chiara per capire. – xryl669

5

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

gcc-u symbol

2

C'è un modo migliore per scrivere la macro FORCE_UNDEFINED_SYMBOL. Basta lanciare quel puntatore a una funzione *. Quindi funziona con qualsiasi funzione - o dati per quella materia. Inoltre, perché preoccuparsi dei pravmas MSVC quando la parte gcc della macro funzionerà anche per MSVC. Quindi la mia versione semplificata sarebbe:

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

che viene utilizzato nel seguente modo:

FORCE_UNDEFINED_SYMBOL(Af) 

Ma deve essere utilizzato nel programma che include la libreria che sta avendo i suoi simboli spogliato.

Problemi correlati