Visual c++ 如何正确地跨平台将静态类实例导入DLL?

Visual c++ 如何正确地跨平台将静态类实例导入DLL?,visual-c++,dll,cmake,Visual C++,Dll,Cmake,我有一个共享库(.so在Linux中,.dll在Windows中),它需要访问它加载的任何可执行文件中包含的静态变量。此变量恰好属于类模板类型,并且位于命名空间内。尽管将变量声明为“extern”(在Windows上为“\u declspec(dllimport)”),但当链接DLL时,VC10为该变量提供了一个“未解析的外部符号”错误。这对我来说似乎很奇怪,因为它确实不应该被解决,而是留给加载时间 标题: // a header demonstrating MSVC-compatible li

我有一个共享库(.so在Linux中,.dll在Windows中),它需要访问它加载的任何可执行文件中包含的静态变量。此变量恰好属于类模板类型,并且位于命名空间内。尽管将变量声明为“extern”(在Windows上为“\u declspec(dllimport)”),但当链接DLL时,VC10为该变量提供了一个“未解析的外部符号”错误。这对我来说似乎很奇怪,因为它确实不应该被解决,而是留给加载时间

标题:

// a header demonstrating MSVC-compatible linkage
#ifdef _MSC_VER

#ifdef I_AM_DLL
#define TO_DLL_LINKAGE __declspec( dllimport )
#else
#define TO_DLL_LINKAGE __declspec( dllexport )
#endif

#else  // not MSVC
#define TO_DLL_LINKAGE
#endif

template<class T>
class TheClass
{
public:
   TheClass(T t) : value_(t) {}

   T value() const
   {
      return value_;
   }
private:
   T value_;
};

typedef TheClass<int> MyClass;
//显示MSVC兼容链接的标头
#ifdef硕士学位
#ifdef I_AM_DLL
#定义到DLL链接declspec(dllimport)
#否则
#定义到DLL链接declspec(dllexport)
#恩迪夫
#否则//不是MSVC
#定义到\u DLL\u链接
#恩迪夫
模板
分类
{
公众:
类(T):值(T){
T值()常量
{
返回值;
}
私人:
T值;
};
typedef类MyClass;
以及DLL:

// a test library (DLL) for linkage experiment
#define I_AM_DLL
#include "theclass.hpp"

#include <iostream>

namespace foo {
extern TO_DLL_LINKAGE MyClass theObject;
}

void bar() {
   int i = foo::theObject.value();
   std::cout << "object value is " << i << std::endl;
}
//链接实验的测试库(DLL)
#定义I_AM_DLL
#包括“theclass.hpp”
#包括
名称空间foo{
外部链接到对象的链接MyClass;
}
空条(){
int i=foo::theObject.value();

std::cout这里有两个基本问题:

  • 在Windows上,符号解析在链接时执行,即使对于共享库也是如此
  • dllimport和dllexport是不对称的-必须解析所有dllimport
  • 在Linux下使用gcc运行时,我的程序可以工作,因为对对象的“extern”引用是在程序加载时解析的列出它正在导出和正在导入的符号,并且操作系统的程序加载器在启动程序时验证是否满足主程序和共享库的所有导入

    相比之下,在Windows/VC++环境中,满足导入符号的特定模块必须标识为共享库已链接-通常通过“导入库”或.lib文件进行链接。这不能延迟到程序加载时间。因此,链接步骤失败

    在我的特殊情况下,我有一个可执行模块,它既需要来自的符号,又提供(一个)symbol to,一个共享库。对于静态库和gcc/Linux,这不是问题,但对于Windows/VC++来说,这会创建一个循环依赖关系。有一个解决方案,但它需要一些额外的工作,在和中讨论过。要做到这一点,需要一个更复杂的链接步骤,其中从executa生成导入库ble在共享库的链接阶段使用。如果您的任何数据具有\uuu dllspec(dllexport)存储类,则会自动生成此类库。最后一步是将此导入库添加到共享库DLL的链接阶段


    如果您是CMake用户,就像我一样,这个过程会因为一个名为的特殊目标属性而变得更加容易,该属性允许库“链接”到可执行文件。

    这里有两个基本问题:

  • 在Windows上,符号解析在链接时执行,即使对于共享库也是如此
  • dllimport和dllexport是不对称的-必须解析所有dllimport
  • 在Linux下使用gcc运行时,我的程序可以工作,因为对对象的“extern”引用是在程序加载时解析的列出它正在导出和正在导入的符号,并且操作系统的程序加载器在启动程序时验证是否满足主程序和共享库的所有导入

    相比之下,在Windows/VC++环境中,满足导入符号的特定模块必须标识为共享库已链接-通常通过“导入库”或.lib文件进行链接。这不能延迟到程序加载时间。因此,链接步骤失败

    在我的特殊情况下,我有一个可执行模块,它既需要来自的符号,又提供(一个)symbol to,一个共享库。对于静态库和gcc/Linux,这不是问题,但对于Windows/VC++来说,这会创建一个循环依赖关系。有一个解决方案,但它需要一些额外的工作,在和中讨论过。要做到这一点,需要一个更复杂的链接步骤,其中从executa生成导入库ble在共享库的链接阶段使用。如果您的任何数据具有\uuu dllspec(dllexport)存储类,则会自动生成此类库。最后一步是将此导入库添加到共享库DLL的链接阶段


    如果您是CMake用户,就像我一样,这个过程会因为一个名为的特殊目标属性而变得更加容易,该属性允许库“链接到”可执行文件。

    有很多错误。您颠倒了dllexport和dllimport。从定义中删除extern。您没有提供默认构造函数。感谢您的评论。我打算将对象导入DLL。相应地,extern声明和“dllimport”。我是不是倒过来的?还有什么原因我需要一个默认构造函数吗?呃,很不清楚是谁导出的。你必须链接实际导出变量的DLL的导入库,以使链接器满意。我应该澄清,是在DLL的链接时间,而不是整个(exe+DLL)我得到了“未解析”的结果错误。DLL的“接口”中应包含导入符号或等效符号。注意,这在gcc中运行良好…我只需要知道如何在VC++中正确执行。有很多错误。您反转了dllexport和dllimport。从定义中删除extern。您没有提供默认构造函数。感谢您的评论。我打算将对象导入DLL。相应地,extern声明和“德林波特”,我是不是把它倒过来了