2012-04-09 8 views
7

He estado trabajando con y probar un auto-registro, la fábrica abstracta basa en el descrito aquí:la vinculación de un auto-registro, la fábrica abstracta

https://stackoverflow.com/a/582456

En todos los casos de prueba, funciona como un amuleto, y proporciona las características y la reutilización que quería.

Enlazar en esta fábrica en mi proyecto utilizando cmake ha sido bastante complicado (aunque parece ser más un problema ar).

Tengo el base.hpp idéntico, derivedb.hpp/cpp, y un deriveda.hpp/cpp equivalente al ejemplo vinculado. En general, simplemente instanciamos la fábrica y llamamos a createInstance() dos veces, una vez cada una con "DerivedA" y "DerivedB".

El ejecutable creado por la línea:

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

funciona como se espera. Moviendo mis clases derivadas en una biblioteca (con cmake, pero he probado esto con AR, individual) y después se une falla:

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

sólo llama la primera instanciación estática (de derivedA.cpp) y nunca la segunda instanciación estática, es decir,

// 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"); 

Tenga en cuenta que el canje de los dos en la línea ar Sólo llamadas de la creación de instancias estática derivedb.cpp, y no la creación de instancias deriveda.cpp.

¿Me falta algo con ar o bibliotecas estáticas que de alguna manera no funcionan bien con variables estáticas en C++?

Respuesta

10

Al contrario de la intuición, incluir un archivo en un comando de enlace no es lo mismo que incluir todos los archivos de objetos que están en el archivo. Solo se incluyen aquellos archivos objeto dentro del archivo necesarios para resolver los símbolos no definidos. Esto es bueno si se tiene en cuenta que una vez que no existía una vinculación dinámica y de otro modo la totalidad de las bibliotecas (creo que la biblioteca C) se duplicaría en cada ejecutable. Esto es lo que la página de manual ld (1) (GNU ld en linux) tiene que decir:

El enlazador buscará un archivo solo una vez, en la ubicación especificada en la línea de comando. Si el archivo define un símbolo que no estaba definido en algún objeto que apareció antes del archivo en la línea de comando, el vinculador incluirá los archivos correspondientes del archivo. Sin embargo, un símbolo indefinido en un objeto que aparece más adelante en la línea de comando no hará que el vinculador busque nuevamente en el archivo.

Desafortunadamente no hay una forma estándar de incluir cada miembro de un archivo en el archivo ejecutable vinculado. En Linux puede usar g++ -Wl,-whole-archive y en Mac OS X puede usar g++ -all_load.

Así que con binutils de GNU ld, el comando de enlace debe ser

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

la -Wl,-no-whole-archive asegura que cualquier archivo que aparece más adelante en el último comando enlace generado por g ++ se vinculará de manera normal.

+0

Muchas gracias, esto me puso en el camino correcto. Para referencia futura, esto ayudó también (¡gracias a la búsqueda mejorada en todo el archivo!) http://stackoverflow.com/a/842770/1322752 –

Cuestiones relacionadas