2010-12-08 11 views
9

Mi pregunta es similar a estos, pero no parece que se correlaciona exactamente:Cómo forzar la inclusión de definiciones de objetos "no utilizados" en una biblioteca

How to force inclusion of an object file in a static library when linking into executable?

Forcing symbol export with MSVC

Lo que tengo es algo así:

struct thingy; 
struct container 
{ 
    static container& instance(); // singleton 

    int register_thingy(thingy*); 
}; 

struct thingy 
{ 
    virtual ~thingy() {} 
    virtual int id() const = 0; 
}; 

//template trick to force registration. 
template < typename Derived > 
struct registered_thingy : thingy 
{ 
    registered_thingy() : my_id(my_static_id) {} 

    int id() const { return my_id; } 
private: 
    int my_id; 
    static int my_static_id; 
} 
template < typename Derived > 
int registered_thingy<Derived>::my_static_id = 
    container::instance().register_thingy(new Derived); 

Ahora, en un archivo concrete_thingy.cpp tengo:

struct my_concrete_thingy : registered_thingy<my_concrete_thingy> 
{ 
    my_concrete_thingy() {} // registered_thingy's constructor not called otherwise 
}; 

Por supuesto, lo anterior es totalmente inútil, pero aquí se abstrae el comportamiento real.

Esto funciona maravillosamente cuando se utiliza en una aplicación que se compila en su conjunto. El problema ahora es que no puedo, hasta ahora, usar esta técnica mientras embotello el comportamiento detrás de collection en una biblioteca. En otras palabras, tengo un archivo thingys.lib que contiene concrete_thingy.cpp pero el registro no se produce cuando está vinculado a un ejecutable. El collection termina existiendo y funciona bien, pero está vacío.

Ahora, esta es una biblioteca STATIC, no una DLL. Eso puede cambiar un poco el problema y las técnicas habladas en los enlaces de arriba no parecen aplicarse. Por supuesto, se trata de funciones y no veo cómo podría aplicarlo a estas estructuras de C++.

He tratado de utilizar el método #pragma comment con las tres líneas siguientes (de forma individual por supuesto) en concrete_thingy.cpp, ninguno de los cuales trabajó:

#pragma comment (linker, "/export:concrete_thingy") 
#pragma comment (linker, "/export:concrete_thingy::my_static_id") 
#pragma comment (linker, "/export:registered_thingy<concrete_thingy>::my_static_id") 

Si concrete_thingy.cpp es ejecutable en el lugar de las obras de la biblioteca de muebles multa.

Así pues, aquí está mi pregunta:

1) ¿Es posible hacer lo que estoy tratando de hacer? Supongo que sí, pero no sé cómo.

2) Si es posible, ¿cómo podría obtener MSVC++ 2010 para hacerlo?

3) Si es posible, ¿cómo podría hacerlo de forma portátil?

En resumen, lo que estoy tratando de hacer sería similar a crear una fábrica abstracta que crea implementaciones de una abstracción. No sabe nada acerca de estas implementaciones, que se registran utilizando trucos de inicialización global. Todo esto debería estar en una biblioteca estática a la que pueda conectarse una aplicación y estas implementaciones deberían estar disponibles a través de esa fábrica. Nadie sabe nada sobre estas implementaciones, excepto ellos mismos y, por lo tanto, los enlaces normales los están haciendo desaparecer, y sus globales de registro.

No es exactamente lo que estoy haciendo, pero está lo suficientemente cerca.

Editar: ============================================ ========

Parece que este comportamiento es "por diseño".EM reconoce que la construcción del objeto que causan efectos secundarios deben ocurrir si su usado, que utilizan un vacío en la norma que les permite no incluyen unidades de traducción en los que se utiliza nada: \

https://connect.microsoft.com/feedback/viewfeedback.aspx?FeedbackID=244410&wa=wsignin1.0&siteid=210

La/OPT: la opción NOREF está diseñada para no hacer nada en este caso aparentemente.

+0

"el constructor de registered_thingy no se llama de otra manera" -> hay otra manera de resolver el problema. Necesita una 'plantilla struct refit;' y luego puede decir, en lugar de definir un constructor, 'typedef refit user;' después de la declaración estática int. Esto forzará la creación de instancias de la estática también. Ver [esta respuesta] (http://stackoverflow.com/questions/401621/best-way-to-build-a-list-of-per-type-data/401801#401801) para una mayor elaboración. –

+0

Al parecer, una vez más se ha demostrado que la diferencia entre un error y una característica es que la función está documentada. Por cierto ... ¿es realmente el truco de la plantilla necesaria? ¿No funcionaría mejor lo siguiente? 'struct concrete: abstract {concrete (...) {}} concrete_instance (...);' – 6502

Respuesta

4

Bueno, la otra responde a los buenos intentos, pero en última instancia infructuosos. Voy a utilizar el truco de reacondicionamiento, pero el resto parece haber sido una pista falsa. tiene sentido, ya que la plantilla en cuestión no se usa en ningún otro lugar, por lo que el hecho de que no se haya instanciado explícitamente no debería marcar la diferencia ... la declaración de lo global aún ocurre en la unidad de traducción A, tiene efectos secundarios ... No creo que el estándar permita que se optimice.

La cuestión desafortunada acerca de que la norma no dice si se requiere o no incluir una unidad de traducción es el problema final. Creo que C++ 0x está haciendo algo al respecto, pero tal vez no ... En cualquier caso, MS se siente libre de no incluir la unidad en absoluto, y como no lo hace, el global no se incluye finalmente en el ejecutable y, por lo tanto, ninguna otra mierda sucede.

Lo que he decidido hacer, y por supuesto hay muchas otras formas, es crear una variable de 'etiqueta' de archivo. A esa etiqueta luego se le asigna una función que es accesible globalmente (TIENE que asignar o asignar, o la referencia se optimiza). Entonces esa función tiene que ser llamada desde el ejecutable.

Decidí hacerlo de esta manera porque el resto sigue funcionando igual que siempre. No termino cambiando el comportamiento como podría si simplemente escribiera una función de registro que registrara manualmente los tipos. Además, puedo hacer otras cosas de esta manera ... Solo tengo que asegurarme de que cualquier cosa que pueda caer en esta clasificación de fucktardery tenga una etiqueta y se acceda a esa etiqueta.

Voy a escribir un montón de macros de ayuda para que esto sea casi indoloro.

1

Existe la opción del vinculador/OPT: REF y/OPT: NOREF, a la que se accede mediante el enlazador-> optimización-> referencias.

+0

@Noah: estoy usando 2010. Editaré en un screenie si no puede encontrarlo. – Puppy

+0

Veo, usted estaba hablando en el EXE, no en la biblioteca. Ajustado el argumento, fue aceptado, pero no solucionó el problema :(Dudo que hubiera querido hacer esto de todos modos porque hay otras bibliotecas a las que enlazaré que no querría extraer en su totalidad. –

Cuestiones relacionadas