1

考虑一个属于链接到动态库 (foo.dll) 的项目的类,同时生成 foo.lib:

class IMP_EXP_DIRECTIVE_MACRO Foo
{
     void bar()
     {
         // do something
     }
 };

然后还有另一个项目bar(生成静态库bar.lib)包含这个类。该项目不与 foo 链接。

最后有一个应用程序项目(生成 .exe),它与 foo.lib 和 bar.lib 链接。当它发生时,链接器会发出 LNK2005 错误,该错误Foo::bar已经在 foo.lib(这很好)和 bar.lib 中定义,这是出乎意料和奇怪的。

根据https://docs.microsoft.com/en-us/cpp/build/reference/symbols?view=vs-2017使用 dumpbin.exe /SYMBOLS 处理 bar.lib 时,输出显示Foo::bar确实在 foo.lib 中定义(!)。这很奇怪,因为根据这个出色的https://stackoverflow.com/a/4955288答案,在类的主体中声明和定义的任何成员函数都是隐式内联的,因此不会导致 ODR 问题。

最后,最有趣的部分。当将Foo::bar定义移动到 .cpp 文件并在类主体中只保留方法的声明时,问题就消失了。

为什么呢?知道做错了什么吗?我想我已经阅读了关于这个主题的整个互联网并尝试了所有各种 VS 配置开关,但只有将定义移动到 .cpp 有帮助。原则上我最终可以做到,但这似乎不是解决问题的正确方法。

环境是:Visual Studio 10。

编辑:
IMP_EXP_DIRECTIVE_MACRO 设置为:
“__declspec(dllexport)”,在构建 foo.dll 时
“”,在构建 bar 时

编辑 2:
问题也消失了,当在编译 bar.lib 时添加了一个预处理器标志,导致class __declspec(dllimport) Foo使用而不是class Foo.
这是正确的方法吗?

4

1 回答 1

2

该函数是可内联的

但是如果你取它的地址&Foo::bar,编译器仍然需要一个真实的地址。这实际上意味着在指向的地址处必须有非内联代码。结果是编译器必须在每个翻译单元中放置一个副本,并且链接器将选择其中一个 - 每个链接器输出一个。但是链接器Foo.lib无法预测其中也会有一个副本,Bar.lib反之亦然。

于 2018-10-10T12:56:34.657 回答