在运行时动态加载库时出现错误 "unresolved external symbol"
Error "unresolved external symbol" when library is dynamically loaded at runtime
我有一个大项目,其中生成了一个可执行文件 A.exe
(使用 cmake 工具链)以在 运行-time[=51] 动态加载 B.dll
=].但是没有编译时链接 B.dll
,我在构建可执行文件时得到了 "unresolved external symbol"。
项目组织如下:
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
为什么会出现此错误以及如何消除它?
从 link 用户的角度来看,non-virtual 方法 (Machine::answer
) 与全局函数相同(例如,GetMach()
).
也就是说,为了能够使用此方法,A
应该:
- link (
target_link_libraries
) 与定义方法的库或
- 在运行时(
GetProcAddress()
)请求方法。
如果这两种方法都不方便,您可以将方法声明为 virtual:
virtual int answer();
所有虚拟 方法都在运行时 解析。 linker 不关心虚拟方法的使用。
我有一个大项目,其中生成了一个可执行文件 A.exe
(使用 cmake 工具链)以在 运行-time[=51] 动态加载 B.dll
=].但是没有编译时链接 B.dll
,我在构建可执行文件时得到了 "unresolved external symbol"。
项目组织如下:
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
为什么会出现此错误以及如何消除它?
从 link 用户的角度来看,non-virtual 方法 (Machine::answer
) 与全局函数相同(例如,GetMach()
).
也就是说,为了能够使用此方法,A
应该:
- link (
target_link_libraries
) 与定义方法的库或 - 在运行时(
GetProcAddress()
)请求方法。
如果这两种方法都不方便,您可以将方法声明为 virtual:
virtual int answer();
所有虚拟 方法都在运行时 解析。 linker 不关心虚拟方法的使用。