提问人:Miguel P 提问时间:11/2/2012 最后编辑:KariMiguel P 更新时间:3/3/2019 访问量:9853
如何修复 C++ DLL 中未解析的外部符号错误?
How do I fix an Unresolved External Symbol error in my C++ DLL?
问:
我有一个dll,它可以访问其项目之外的一些类(我使用的是Visual Studio,所以我有两个项目)。问题是,在dll包含的标头中,在dll项目之外,只有函数体,如下所示:
x.h
class x
{
void myFunc();
}
在另一个 cpp 文件中,在 dll 文件之外:
#include "x.h"
x::myFunc()
{
//.....
}
dll 只获取函数的主体,所以当我编译时,我得到很多未解析的外部符号(我很确定这就是问题所在,因为我在另一个项目中使用另一个完全内置在 .h 文件中的类进行了测试,并且没有错误)。那么我该如何解开这个谜团呢?
答:
导入标头只有函数签名是正常的;实际的函数体已经编译到 DLL 二进制文件中,并在链接时通过链接到实际 DLL 进行解析。
首先要尝试的是确保您确实链接到所述 DLL。仅仅包含标头是不够的,您还需要链接到二进制文件。因此,在项目配置中,需要添加一个链接,指向(例如)在编译 DLL 时(如果在 MSVC 中)与 DLL 一起创建的 .lib 文件。此 lib 文件让链接器知道如何将通过导入标头包含的函数签名连接到 DLL 中包含的实际实现。如果您在不同的平台上,机制可能会略有不同,但概念会相似。
编辑: 下一步是确保二进制文件实际上正在导出您尝试链接的符号。确保所有接口签名都通过 __declspec(dll_export) 前缀导出。通常,这被包装在 IFDEF 中,以便在编译 DLL 时声明标头导出,但在该标头包含在客户端项目中时不声明导出。接下来,您可以使用 dumpbin 检查损坏的导出名称,看看是否有任何意外。
这是您的示例的修改版本,它说明了这种导出方式(注意,我还没有测试过这是否编译,对于任何拼写错误,我们深表歉意):
#ifdef BUILDING_MYDLL
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
class MYDLL_API x
{
void myFunc();
}
然后,将配置设置为在编译 dll 时定义 BUILDING_MYDLL,但在编译可执行文件时不定义。这样,函数仅在编译库 dll 时标记为导出。现在,您可以使用MYDLL_API标记公共 API 函数,并且它们应该在构建期间导出。
请注意,dll_export、dll_import 和 declspec 都是非常特定于 MSVC 的构造。其他编译器/运行时以不同的方式处理符号导出。
评论
有多种方法可以将 DLL 链接到 Windows 上的应用,请查看以下现有问题/答案:https://stackoverflow.com/a/2060508/1701823
评论