【问题标题】:Exposing .lib methods through another DLL通过另一个 DLL 公开 .lib 方法
【发布时间】:2014-03-14 14:47:48
【问题描述】:

我的解决方案中有以下设置(所有 C++):

  1. Project1,编译为静态库 (.lib)。
  2. Project2 编译为 DLL,包含 1 中生成的 .lib。
  3. Project3,包含2中生成的DLL。

现在我想将 project1 的功能公开给 project3,而不直接包含项目 1 的 .lib。我一直遇到链接器错误。

error LNK2001: unresolved external symbol

项目 1 设置为通过以下方式使用 dllexport 和 dllimport(当然,FOO_API 在要公开的类/方法之前):

#if defined(FOO_STATIC)
    #define FOO_API
    #define FOO_TEMPLATE(type) template class type
#else
    #ifdef FOO_EXPORTS
    #define FOO_API __declspec(dllexport)
    #define FOO_TEMPLATE(type) template class FOO_API type
    #else
    #define FOO_API __declspec(dllimport)
    #define FOO_TEMPLATE(type) extern template class FOO_API type
    #endif
#endif

由于我们将 Project1 编译为静态库,因此不会采用 dllexport 路径(我们定义 FOO_STATIC)。然而,通过 Project2 的 DLL,我想公开 Project1 的方法。我尝试在 Project2 中创建一个定义 FOO_EXPORTS 的 .cpp 文件,然后包含包含我要导出的方法的文件的标题。所以:

// somefile_that_will_be_built.cpp
#define FOO_EXPORTS
#include "a.h"
#include "b.h"
#include "c.h"

我希望这会触发 Project1 中的 dllexport 代码,以便将其包含在 Project2 的 DLL 中。我希望当 Project3 包含 Project1 标头时,它会进入 dllimport 路径,并且链接器会找到所需的方法。所以:

#include "a.h"
class WrapThis:    
    public:
        SomeMethodInA();

Project3 编译,但在链接过程中未找到 SomeMethodA()。我的方法不可能吗?我是否需要改为在 Project2 中编写模块定义文件?我希望防止这种情况发生,因为我们有一些名称歧义,并且名称修改也无济于事(我知道可以关闭它,但出于其他原因我不想这样做)。

任何帮助将不胜感激,因为我在这部分开发方面的经验有限。

更新

剩余错误(以4个为例):

2>Stdafx.obj : error LNK2028: unresolved token (0A000683) "public: void __cdecl    fooEx::Load(char const * const)" (?   Load@fooEx@Namespace4@Namespace1@Namespace2@Namespace3@@$$FQEAAXQEBD@Z) referenced in function "public: void __clrcall Namespace1::Namespace2::Namespace3::Namespace4::FooEx::Load(class System::String ^)" (?Load@FooEx@Namespace4@Namespace1@Namespace2@Namespace3@@$$FQE$AAMXPE$AAVString@System@@@Z)
2>Stdafx.obj : error LNK2028: unresolved token (0A000684) "public: void __cdecl fooEx::LoadHeader(char const * const)" (?LoadHeader@fooEx@Namespace4@Namespace1@Namespace2@Namespace3@@$$FQEAAXQEBD@Z) referenced in function "public: void __clrcall Namespace1::Namespace2::Namespace3::Namespace4::FooEx::LoadHeader(class System::String ^)" (?LoadHeader@FooEx@Namespace4@Namespace1@Namespace2@Namespace3@@$$FQE$AAMXPE$AAVString@System@@@Z)
2>Stdafx.obj : error LNK2028: unresolved token (0A000686) "public: void __cdecl fooEx::Save(char const * const,double,double)" (?Save@fooEx@Namespace4@Namespace1@Namespace2@Namespace3@@$$FQEAAXQEBDNN@Z) referenced in function "public: void __clrcall Namespace1::Namespace2::Namespace3::Namespace4::FooEx::Save(class System::String ^,double,double)" (?Save@FooEx@Namespace4@Namespace1@Namespace2@Namespace3@@$$FQE$AAMXPE$AAVString@System@@NN@Z)
2>Stdafx.obj : error LNK2028: unresolved token (0A000687) "public: void __cdecl fooEx::Save(char const * const)" (?Save@fooEx@Namespace4@Namespace1@Namespace2@Namespace3@@$$FQEAAXQEBD@Z) referenced in function "public: void __clrcall Namespace1::Namespace2::Namespace3::Namespace4::FooEx::Save(class System::String ^)" (?Save@FooEx@Namespace4@Namespace1@Namespace2@Namespace3@@$$FQE$AAMXPE$AAVString@System@@@Z)

Project1 - classA(使用 FOO_EXPORT 编译)到静态库中。

class FOO_API fooEx : public foo 
{
    public:
         fooEx();
         virtual void Free();
         void Load(const char filename[]);
         void LoadHeader(const char filename[]);
         virtual void LoadRawData();
         void Save(const char filename[]);
}

可能很重要:

  • Project1 使用预编译的头文件。

  • Load & LoadHeader 在多个文件中以完全相同的方式定义(foo 类的其他扩展名)。

  • 虚拟方法在基类以及该基类的其他实现中定义。

Project2 - 编译为 DLL。通过链接器输入包括 Project1.lib,其他依赖项。

Project3 - 编译为 DLL。具有无法链接的方法的示例类。

【问题讨论】:

    标签: c++ linker linker-errors dllimport dllexport


    【解决方案1】:

    这当然行不通,.lib 代码编译时使用了错误的#define。所以它的功能不会被导出。

    您要么必须重建定义了 FOO_EXPORTS 的 .lib,要么重建列出必须导出的函数的 write a .def file。重建当然是迄今为止最不痛苦的解决方案,您可以简单地向 lib 项目添加另一个配置并将该项目包含在您的 DLL 解决方案中。或者总是构建定义了 FOO_EXPORTS 的库,它仍然是一个可以链接到非 DLL 项目的静态库。

    【讨论】:

    • 这有帮助,我为什么不早点尝试:)。从 500 个错误到 90 个错误。然而,我的重载方法似乎仍然存在一些问题。
    • -edit:我已经将 dllexport 放在了类的前面,暴露了整个类。然而,链接器似乎找不到这些类的某些方法。
    • 没人能看到你在做什么。您必须使用显示类声明和链接器错误消息的短代码 sn-p 更新您的问题。
    • 你说得对,对不起。已编辑,我目前开会迟到了,但如果需要,我会看看我是否可以稍后发布项目设置(命令概述)。可能需要说明的是:项目使用嵌套的命名空间,而 project1 使用预编译的标头。
    • 命名空间名称非常奇怪。为什么在地球上你会嵌套“Namespace1”inside“Namespace2”?名为 Namespace3::Namespace2::Namespace1::Namespace4::fooEx 的类型不属于程序。
    【解决方案2】:

    project1 的所有编译二进制代码都包含在 .lib 文件中。 如果在编译时不包含它,则不能从另一个项目中使用它。

    您可以将 project1 中您希望在运行时共享的部分重新定义为共享库(即 DLL)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-25
      • 2011-02-15
      • 2018-05-20
      相关资源
      最近更新 更多