并非导出DLL导出类的所有符号(VS9)

时间:2010-06-10 12:54:23

标签: c++ windows visual-studio-2008 dll

我正在从一组静态库中构建一个DLL,而我遇到的问题是只导出了部分类。

我正在做的是使用预处理器定义声明我想要导出的所有符号,如:

#if defined(MYPROJ_BUILD_DLL)
//Build as a DLL
#   define MY_API __declspec(dllexport)
#elif defined(MYPROJ_USE_DLL)
//Use as a DLL
#   define MY_API __declspec(dllimport)
#else
//Build or use as a static lib
#   define MY_API
#endif

例如:

class MY_API Foo{ 
   ...
}

然后我使用MYPROJ_BUILD_DLL和&构建静态库MYPROJ_USE_DLL未定义导致构建静态库。

在另一个版本中,我从这些静态库中创建了一个DLL。所以我定义MYPROJ_BUILD_DLL导致我要导出的所有符号都归结为__declspec(dllexport)(这是通过在DLL项目源文件中包含所有静态库头来完成的。)

修改 关于未加密符号的注意事项:链接器选项保留未引用数据(/OPT:NOREF)和不删除冗余COMDAT(/OPT:NOICF)已设置,以便不会删除未引用的符号。

好的,现在问题。当我使用这个新的DLL时,我会得到未解析的外部因素,因为不会导出类的所有符号。例如,在这样的类中:

class MY_API Foo{
public:
   Foo(char const* );
   int bar();
private:
   Foo( char const*, char const* );
};

仅导出Foo::Foo( char const*, char const*);int Foo::bar();。怎么可能?由于例如,我可以理解整个课程是否缺失我忘了在DLL-build中包含标题。但它只是部分缺失。

另外,假设Foo::Foo( char const*)未实施;然后DLL构建将有未解决的外部错误。但是构建很好(我还在没有实现的情况下仔细检查了声明)。

注意:我合并的静态库的组合大小在30MB的范围内,生成的DLL为1.2MB。

我正在使用Visual Studio 9.0(2008)来构建所有内容。 取决于以检查导出的符号。

修改 对于那些想知道为什么我不只是从每个静态库构建一个DLL的人:我不能因为它们相互交叉引用(这就是为什么我需要将它们组合在一个单独的DLL中)。我知道,这太可怕了,我无法理解它背后的逻辑。

3 个答案:

答案 0 :(得分:3)

请记住,当您链接到静态LIB时,默认情况下链接器只会提取客户端(在本例中是 DLL )实际引用的函数,类和数据。

所以会发生这样的事情:

  1. 你构建你的静态LIB,这没关系。此LIB 100%有效。
  2. 您现在围绕原始二进制LIB构建静态DLL。它仅在中引入它实际引用的内容。它没有引入整个类定义,这是它需要做的事情。尽管它构建了这个DLL,但它是无效的。
  3. 然后客户端使用DLL,并期望看到导出类的完整二进制定义,因为这是客户端在随附的头文件中看到的内容。
  4. 但是,该类只是部分导入,这就是您收到这些链接错误的原因。
  5. 修复:

    • 如果您能够,请不要在静态LIB上构建DLL。从原始源代码构建DLL。并从原始源代码构建静态LIB。
    • 否则你可能会使用链接器设置,但我强烈推荐上面的选项1。请注意,OPT:NOREF在OPT中不起作用:NOREF对静态LIB没有影响。

    什么不能解决它:

    • 高级链接器调整,如OPT:NOREF,任何涉及COMDAT的东西等。如果你想要这些函数,你必须确保它们被引用,或者通过引用它们,或通过明确地告诉链接器,“嘿,这个符号X被引用为“。

    作为旁注:

    • 无论何时我构建DLL或LIB,我都使用您正在使用的技术构建两个 DLL和LIB。拥有一个可以通过切换设置生成DLL或LIB的代码库是理想的。但是当你拥有两个源代码时,用(二进制)静态LIB构建DLL ...我很难想象什么时候需要这样的场景。

答案 1 :(得分:2)

问题肯定是你在DLL项目中使用已经构建的静态.lib。这不起作用,您必须重建 .lib,以便函数获取__declspec(dllexport)声明符,并由链接器导出。

此时,首先创建.lib的DLL兼容版本并不是那么有用。只需创建两个项目,一个创建静态.lib,另一个创建DLL。从技术上讲,仍然可以在DLL项目中使用静态.lib,但是您必须使用.def文件导出函数。如果图书馆有大量出口,这可能是高度维护。

答案 2 :(得分:1)

这可能已经太晚了,但OP的抱怨是私有方法(析构函数)没有从dllexport'd类导出。这不正常吗?不允许外部用户调用私有方法。