错误"未解析的外部符号"当库在运行时动态加载时

时间:2018-04-03 12:00:21

标签: c++ windows dll cmake loading

我有一个大型项目,其中生成了可执行文件A.exe(使用cmake工具链),以便在运行时动态加载B.dll 。但是如果没有与B.dll的编译时链接,我得到了#34;未解析的外部符号"在构建可执行文件时。

项目组织如下:

superproject | |--- build/ |----CMakeLists.txt |--- src/ | |---a : a1.cpp, CMakeLists.txt |---b : b.h, b.cpp, export.def, CMakeLists.txt

文件 src / b / b.h

class Machine
{
    int u;
    static Machine* sing;
public:
    Machine();
    static Machine* GetInstance();
    int answer();
};

文件 src / b / b.cpp

#include "b.h"

Machine* Machine::sing;

Machine::Machine() : u(1) {}

Machine* Machine::GetInstance()
{
   if (!sing)
      sing = new Machine();
   return sing;
}

int Machine::answer(){ return u + 33; }

Machine* GetMach()
{
   return Machine::GetInstance();
}

文件 src / a / a1.cpp

#include <windows.h>
#include <iostream>

#include "b.h"

using namespace std;
typedef Machine* (*func_t)();
int main(int argc, char* argv[])
{
   cout << "hello\n";
   HMODULE lib = LoadLibrary("b.dll");
   if (lib)
   {
      void* rawfunc = GetProcAddress(lib, "GetMach");
      if (rawfunc)
      {
         func_t func = (func_t)(rawfunc);
         Machine* m = func();
         cout << "The exported number is " << m->answer();
      }
      else
      {
         cout << "Failed to get the symbol";
      }
   }
   else
   {
      cout << "Failed to load library";
   }
   getchar();
   return 0;
}

文件 src / b / export.def

EXPORTS
    GetMach

文件 src / b / CMakeLists.txt

file(GLOB_RECURSE SRC_FILES *.cpp)
file(GLOB_RECURSE DEF_FILES *.def)
add_library(b MODULE ${SRC_FILES} ${DEF_FILES})

文件 src / a / CMakeLists.txt

file(GLOB_RECURSE SRC_FILES *)
include_directories(../b)
add_executable(A ${SRC_FILES})

Visual Studio抱怨:

error LNK2019: unresolved external symbol "public: int __cdecl Machine::answer(void)" (?answer@Machine@@QEAAHXZ) referenced in function main    C:\....\superproj\build\a\a1.obj    A

为什么我会收到此错误以及如何消除它?

1 个答案:

答案 0 :(得分:1)

从链接器的角度来看,非虚拟方法(Machine::answer)与全局函数(例如GetMach())相同。

也就是说,为了能够使用此方法,A应该:

  • 链接(target_link_libraries)与定义方法的库或
  • 运行时GetProcAddress())请求方法。

如果这两种方法看起来都不相似,您可以将方法声明为 virtual

virtual int answer();

所有虚拟方法在运行时解析。链接器不会打扰使用虚方法。