У меня есть 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;
В приложении, которое использует Тест, я называю m ().
Я также пытался использовать __ declspec (dllexport) для каждого метода отдельно, но я все еще получаю те же ошибки ссылки для статических участников.
Если я проверяю DLL (.lib) использующий dumpbin, я видел, что символы были экспортированы.
Например, приложение дает следующую ошибку во время ссылки:
1>Main.obj : error LNK2001: unresolved external symbol "protected: static int CalcEngine::i_MatrixRow" (?i_MatrixRow@CalcEngine@@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 : ?i_MatrixRow@CalcEngine@@1HA (protected: static int CalcEngine::i_MatrixRow)
Type : data
Name type : name
Hint : 31
Name : ?i_MatrixRow@CalcEngine@@1HA
Я не могу выяснить, как решить это. Что я делаю неправильно? Как я могу преобладать над этими ошибками?
P.S. Код был первоначально разработан для Linux и .so/binary работ комбинации без проблемы
Править: В данном случае статические переменные непосредственно не отнесены приложением, но метод встраивается, так как это находится в заголовке. Я смог разрешить ошибки ссылки путем перемещения методов в .cpp файл.
В этой теме на cprogramming.com предлагается, чтобы статическая переменная была локальной для dll и не экспортировалась.
К статическому члену нет прямого доступа у кода в вызывающем приложении, только через функции-члены класса в dll. Однако существует несколько inline функций, обращающихся к статическому члену. Эти функции будут встроены в код вызывающего приложения, в результате чего вызывающее приложение получит прямой доступ к статическому члену. Это нарушит упомянутый выше вывод о том, что статические переменные являются локальными для dll и на них нельзя ссылаться из вызывающего приложения.
В случае с библиотеками DLL Windows существует особое различие между __declspec(dllexport)
и __declspec(dllimport)
, dllexport
должен использоваться при компиляции DLL, dllimport
должен использоваться при компиляции программ, которые ссылаются на эту DLL. Стандартный способ определения этого - макрос.
Ниже приведен пример visual studio:
// 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
Я предполагаю, что класс, использующий 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;
, в то время как другой проект, который не определяет ЭКСПОРТ, будет видеть dllimport .
Есть ли в этом смысл?