【问题标题】:dllexport unexpectedly doesn't cause linker error in referencing projectdllexport 意外不会导致引用项目中的链接器错误
【发布时间】:2020-06-15 17:14:24
【问题描述】:

我遇到了一些行为,据我了解,这些行为应该会导致链接器错误。

我有两个 C++ 项目 MyLibMyLibTestsMyLib 是一个 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


【解决方案1】:

大多数编译器都可以选择只创建预处理文件,而不是实际编译和创建目标文件。

例如Visual Studio 编译器具有/E option。然后,您可以检查预处理文件以查看 NATIVE_API 在您的测试源文件中实际被预处理到的内容。与其他选项结合使用时,您可以将预处理器输出写入文件并检查它。与您期望的定义相比,该定义可能来自其他地方。

【讨论】:

  • 我刚刚验证了它,它确实解析为dllexport,因此没有隐藏的宏重新定义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-09
  • 2021-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-24
  • 1970-01-01
相关资源
最近更新 更多