通过另一个DLL公开.lib方法

时间:2014-03-14 14:47:48

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

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

  1. Project1,编译为静态库(.lib)。
  2. Project2,编译为DLL,包含1中生成的.lib。
  3. Project3,包含在2中生成的DLL。
  4. 现在我想将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。具有无法链接的方法的示例类。

2 个答案:

答案 0 :(得分:3)

这当然无法工作,.lib代码编译错误的#define生效。因此它的功能不会被导出。

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

答案 1 :(得分:0)

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

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