Экспорт статических данных в DLL - PullRequest
29 голосов
/ 19 марта 2010

У меня есть 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" (?i_MatrixRow@CalcEngine@@1HA)

Но в хранилище .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.

Ответы [ 3 ]

17 голосов
/ 19 марта 2010

В этом потоке на cprogramming.com предполагается, что статическая переменная является локальной для dll и не экспортируется.

Краткое изложение обсуждения ниже

Статический член не доступен напрямую через код в вызывающем приложении, только через функции-члены класса в dll. Однако есть несколько встроенных функций, обращающихся к статическому члену. Эти функции будут встроены в код вызывающих приложений, благодаря чему вызывающее приложение получит прямой доступ к статическому члену. Это нарушит приведенный выше вывод о том, что статические переменные являются локальными для DLL и на них нельзя ссылаться из вызывающего приложения.

11 голосов
/ 19 марта 2010

Я предполагаю, что класс, который использует 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 голосов
/ 19 марта 2010

В библиотеках Windows существует определенное различие между __declspec(dllexport) против __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
...