2012-04-09 12 views
7

ho lavorato con e testare un auto-registrazione, Abstract Factory basa su quello descritto qui:collegando un auto-registrazione, fabbrica astratto

https://stackoverflow.com/a/582456

In tutti i miei casi di test, funziona come un fascino, e fornisce le caratteristiche e il riutilizzo che volevo.

Il collegamento in questa fabbrica nel mio progetto utilizzando cmake è stato piuttosto complicato (anche se sembra essere più un problema di ar).

Ho identico base.hpp, derivedb.hpp/cpp e un equivalente deriveda.hpp/cpp all'esempio collegato. In generale, ho semplicemente creato un'istanza della factory e chiamato createInstance() due volte, una volta ciascuna con "DerivedA" e "DerivedB".

L'eseguibile creato dalla linea:

g++ -o testFactory main.cpp derivedb.o deriveda.o 

funziona come previsto. Spostare le mie classi derivate in una libreria (usando CMake, ma ho provato questo con ar solo come bene) e poi il collegamento fallisce:

ar cr libbase.a deriveda.o derivedb.o 
g++ -o testFactory libbase.a main.cpp 

chiama solo il primo di un'istanza statica (da derivedA.cpp) e mai il secondo istanziazione statico, ossia

// deriveda.cpp (if listed first in the "ar" line, this gets called) 
DerivedRegister<DerivedA> DerivedA::reg("DerivedA"); 

// derivedb.cpp (if listed second in the "ar" line, this does not get called) 
DerivedRegister<DerivedB> DerivedB::reg("DerivedB"); 

noti che scambiando i due nella linea ar solo chiamate l'istanza statica derivedb.cpp, e non l'istanziazione deriveda.cpp.

Mi manca qualcosa con ar o librerie statiche che in qualche modo non funzionano con le variabili statiche in C++?

risposta

10

Contrariamente all'intuizione, l'inclusione di un archivio in un comando di collegamento non equivale a includere tutti i file di oggetti presenti nell'archivio. Sono inclusi solo i file oggetto all'interno dell'archivio necessari per risolvere i simboli non definiti. Questa è una buona cosa se si considera che una volta non c'era alcun collegamento dinamico e in caso contrario la totalità delle librerie (si pensi alla libreria C) verrebbe duplicata in ogni eseguibile. Ecco cosa dice la manpage ld (1) (GNU ld on linux):

Il linker cercherà un archivio solo una volta, nel punto in cui è specificato sulla riga di comando. Se l'archivio definisce un simbolo che non era definito in qualche oggetto che appariva prima dell'archivio sulla riga di comando, il linker includerà i file appropriati dall'archivio. Tuttavia, un simbolo indefinito in un oggetto che appare in seguito sulla riga di comando non farà in modo che il linker cerchi di nuovo nell'archivio.

Sfortunatamente non esiste un modo standard per includere tutti i membri di un archivio nell'eseguibile collegato. Su linux puoi usare g++ -Wl,-whole-archive e su Mac OS X puoi usare g++ -all_load.

Quindi, con binutils GNU ld, il comando di collegamento dovrebbe essere

g++ -o testFactory -Wl,-whole-archive libbase.a -Wl,-no-whole-archive main.cpp 

la -Wl,-no-whole-archive assicura che qualsiasi archivio che appare più avanti nel comando finale link generato da g ++ sarà collegato in modo normale.

+0

Grazie mille, questo mi ha messo sulla strada giusta. Per riferimento futuro, questo ha aiutato anche (grazie a migliorata ricerca-foo su tutto l'archivio!) http://stackoverflow.com/a/842770/1322752 –