Экспорт статических данных в DLL
У меня есть DLL, которая содержит класс со статическими членами. Я использую __declspec(dllexport)
для использования этого класса методов. Но когда я связываю его с другим проектом и пытаюсь его скомпилировать, я получаю ошибки "неразрешенных внешних символов" для статических данных.
например.
В DLL Test.h
class __declspec(dllexport) Test{
protected:
static int d;
public:
static void m(){int x = a;}
}
В DLL, Test.cpp
#include "Test.h"
int Test::d;
В приложении, использующем Test, я вызываю m().
Я также пытался использовать __declspec (dllexport) для каждого метода отдельно, но я все равно получаю те же ошибки ссылок для статических членов.
Если я проверяю DLL (.lib) с помощью dumpbin, я вижу, что символы были экспортированы.
Например, приложение дает следующую ошибку во время соединения:
1>Main.obj : error LNK2001: unresolved external symbol "protected: static int CalcEngine::i_MatrixRow" ([email protected]@@1HA)
Но в dumpbin файла .lib содержится:
Version : 0
Machine : 14C (x86)
TimeDateStamp: 4BA3611A Fri Mar 19 17:03:46 2010
SizeOfData : 0000002C
DLL name : CalcEngine.dll
Symbol name : [email protected]@@1HA (protected: static int CalcEngine::i_MatrixRow)
Type : data
Name type : name
Hint : 31
Name : [email protected]@@1HA
Я не могу понять, как это решить. Что я делаю не так? Как я могу преодолеть эти ошибки?
P.S. Код был первоначально разработан для Linux, а .so/двоичная комбинация работает без проблем
EDIT: в данном случае статические переменные напрямую не передаются приложением, но метод встроен, так как он в заголовке. Я смог разрешить ошибки ссылок, перемещая методы в файл .cpp.
Ответы
Ответ 1
В этот поток на cprogramming.com предлагается, чтобы статическая переменная была локальной для dll и не экспортировалась.
Резюме нижеприведенного обсуждения
Статический член не получает доступ непосредственно по коду вызывающего приложения, только через функции-члены класса в dll. Однако есть несколько встроенных функций, обращающихся к статическому члену. Эти функции будут встроены в код вызывающих приложений, чтобы приложение вызывало доступ к статическому элементу напрямую. Это будет нарушать найденный выше вывод о том, что статические переменные являются локальными для dll и не могут ссылаться на вызывающее приложение.
Ответ 2
Я предполагаю, что класс, который использует DLL, должен видеть dllimport вместо dllexport в заголовке. Если я прав, это обычно может быть достигнуто путем определения макроса препроцессора, например:
#ifdef EXPORTING
#define DECLSPEC __declspec(dllexport)
#else
#define DECLSPEC __declspec(dllimport)
#endif
а затем используйте его в объявлении класса:
class DECLSPEC Test{
protected:
static int d;
public:
static void m(){}
}
Так что в Test.cpp(или везде, где это имеет смысл в вашем проекте DLL) вы можете указать, что экспортируете, чтобы он экспортировался с помощью dllexport:
#define EXPORTING
#include "Test.h"
int Test::d;
в то время как другой проект, который не определяет EXPORTING, увидит dllimport.
Имеет ли смысл?
Ответ 3
При использовании DLL Windows существует специальное различие между __declspec(dllexport)
vs __declspec(dllimport)
, dllexport
должно использоваться при компиляции DLL, dllimport
должно использоваться при компиляции программ, которые ссылаются на эту DLL. Стандартный способ определить это будет с помощью макроса.
Ниже приведен пример визуальной студии:
// 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