【发布时间】:2020-06-15 17:14:24
【问题描述】:
我遇到了一些行为,据我了解,这些行为应该会导致链接器错误。
我有两个 C++ 项目 MyLib 和 MyLibTests。 MyLib 是一个 windows dll 项目。在那个项目中有一个头文件 Declspec.h
// Declspec.h
#pragma once
#define NATIVE_API __declspec(dllexport)
#define NATIVE_API_CALL __cdecl
用于注释必须导出的函数(以便测试它们)。
现在有几个头文件声明了函数,例如GUID.h(我去掉了不必要的部分):
// GUID.h
NATIVE_API GUID newGuid();
及其相关的源文件,例如GUID.cpp:
// GUID.cpp
GUID newGuid()
{
GUID g;
(void)CoCreateGuid(&g);
return g;
}
MyLib 构建 GUID.cpp,到目前为止一切都很好。现在 MyLibTests 引用 dll 并调用 newGuid() 函数。为此,MyLibTests 中包含了完全相同的 GUID.h。代码编译,看起来运行正常。这是我不明白的一点。通过包含 GUID.h,我们可传递地包含将 NATIVE_API 宏解析为 __declspec(dllexport) 的 Declspec.h,这意味着应该再次导出该函数(它本身就是已经错了)。我假设dllexport 需要在其中一个翻译单元(即 GUID.cpp 此处)中可用的定义才能允许导出。但由于 GUID.cpp 不是作为 MyLibTests 项目的一部分构建的,因此我预计会出现链接器错误,而不是成功构建。
据我所知,Declspec.h 看起来像这样:
// Declspec.h
#ifdef SOME_PROJECT_DEPENDEND_MACRO
# define NATIVE_API __declspec(dllexport)
#else
# define NATIVE_API __declspec(dllimport)
#endif
和SOME_PROJECT_DEPENDEND_MACRO 是在提供该功能的项目的项目文件中声明的宏。这样,定义项目中的所有包含都获得dllexport 签名,而所有引用项目都包含带有dllimport 签名的头文件(因此不要在自己的翻译单元中查找定义)。
为什么这两个项目都成功编译(并运行)了,尽管两个项目中的所有函数都总是dllexported?
【问题讨论】:
-
dllexport 向链接器提供了一个提示,告诉它需要将函数声明放入项目的导入库中。但是由于您实际上并没有构建一个库,所以它只是耸了耸肩。如果您忘记链接真正的导入库,即由 DLL 项目生成的导入库,那么您将收到链接器错误。
-
@HansPassant 所以因为 MyLibTests 是一个可执行文件,它只是丢弃了
__declspec(dllexport)部分并且我没有收到链接器错误,因为我正在链接导入库包含我的函数的定义(然后在运行时转发到 dll)?
标签: c++ visual-c++ dllimport dllexport