variable una tipo que puede programacion miembros metodo instancia estático estaticos declarar c++ windows linker-errors dllexport

c++ - una - static java



Exportando datos estáticos en una DLL (3)

Tengo una DLL que contiene una clase con miembros estáticos. Uso __declspec(dllexport) para hacer uso de los métodos de esta clase. Pero cuando lo vinculo a otro proyecto e intento compilarlo, obtengo errores de "símbolo externo no resuelto" para los datos estáticos.

Por ejemplo, en DLL, Test.h

class __declspec(dllexport) Test{ protected: static int d; public: static void m(){int x = a;} }

En DLL, Test.cpp

#include "Test.h" int Test::d;

En la aplicación que usa Test, llamo m ().

También intenté usar __declspec (dllexport) para cada método por separado, pero sigo recibiendo los mismos errores de enlace para los miembros estáticos.

Si reviso la DLL (la .lib) usando dumpbin, podría ver que los símbolos han sido exportados.

Por ejemplo, la aplicación da el siguiente error en el momento del enlace:

1>Main.obj : error LNK2001: unresolved external symbol "protected: static int CalcEngine::i_MatrixRow" (?i_MatrixRow@CalcEngine@@1HA)

Pero el basurero de la .lib contiene:

Version : 0 Machine : 14C (x86) TimeDateStamp: 4BA3611A Fri Mar 19 17:03:46 2010 SizeOfData : 0000002C DLL name : CalcEngine.dll Symbol name : ?i_MatrixRow@CalcEngine@@1HA (protected: static int CalcEngine::i_MatrixRow) Type : data Name type : name Hint : 31 Name : ?i_MatrixRow@CalcEngine@@1HA

No puedo averiguar cómo resolver esto. ¿Qué estoy haciendo mal? ¿Cómo puedo superar estos errores?

PS El código fue desarrollado originalmente para Linux y la combinación .so / binary funciona sin problemas

EDITAR: En el caso dado, las variables estáticas no son directamente referidas por la aplicación pero el método está en línea ya que está en el encabezado. Pude resolver los errores de enlace moviendo los métodos al archivo .cpp.


Con las DLL de Windows, hay una distinción específica entre __declspec(dllexport) vs __declspec(dllimport) , se debe usar dllexport al compilar la DLL, se debe usar dllimport al compilar los programas que enlazan con esta DLL. La forma estándar de definir esto sería con una macro.

El siguiente es el ejemplo de estudio visual:

// The following ifdef block is the standard way of creating macros which make exporting // from a DLL simpler. All files within this DLL are compiled with the DLL_EXPORTS // symbol defined on the command line. this symbol should not be defined on any project // that uses this DLL. This way any other project whose source files include this file see // DLL_API functions as being imported from a DLL, whereas this DLL sees symbols // defined with this macro as being exported. #ifdef DLL_EXPORTS #define DLL_API __declspec(dllexport) #else #define DLL_API __declspec(dllimport) #endif


En this hilo en cprogramming.com, se sugiere que una variable estática es local a la dll y no se exporta.

Resumen de la discusión a continuación

El miembro estático no es accedido directamente por código en la aplicación que llama, solo a través de las funciones miembro de la clase en la dll. Sin embargo, hay varias funciones en línea que acceden al miembro estático. Esas funciones se expandirán en línea en el código de las aplicaciones de llamada, lo que hará que la aplicación de llamada acceda directamente al miembro estático. Eso violará el hallazgo al que se hace referencia anteriormente de que las variables estáticas son locales a la dll y no pueden ser referenciadas desde la aplicación que llama.


Mi conjetura es que la clase que usa la DLL debería ver dllimport en lugar de dllexport en el encabezado. Si estoy en lo cierto, esto se puede lograr típicamente definiendo una macro de preprocesador como:

#ifdef EXPORTING #define DECLSPEC __declspec(dllexport) #else #define DECLSPEC __declspec(dllimport) #endif

y luego usarlo en la declaración de clase:

class DECLSPEC Test{ protected: static int d; public: static void m(){} }

De modo que en Test.cpp (o donde sea que tenga sentido en su proyecto DLL) puede especificar que está exportando para que se exporte con dllexport :

#define EXPORTING #include "Test.h" int Test::d;

mientras que el otro proyecto, que no define EXPORTAR, verá dllimport .

¿Tiene sentido?