使用 dllimport/dllexport 宏在多个项目中包含标头时出现 VC++ 链接器错误

VC++ linker error when using dllimport/dllexport macro to include headers in multiple projects

提问人:Claudiu Apostol 提问时间:3/28/2018 更新时间:4/2/2018 访问量:531

问:

我有一个使用 Visual Studio 2017 的 Visual C++ 解决方案,其中包含 5 个项目:

  • 斯派克配置
  • 斯派克引擎
  • SpikeRenderer(斯派克渲染器)
  • SpikeUI的
  • 斯派克实用工具

在 SpikeUtils 中,我有一个标头 _SpikeEngineObject.h:

#pragma once

#ifdef DLL_SPIKEUTILS
#define SPIKEUTILS_EXPORT __declspec(dllexport)
#else
#define SPIKEUTILS_EXPORT __declspec(dllimport)
#endif

#include "GUID.h"

namespace SpikeUtils
{
    class SPIKEUTILS_EXPORT _SpikeEngineObject
    {
    public:
        const std::string & _SpikeEngineId()
        {
            return _SpikeRef.Value();
        }
    private:
        SpikeUtils::GUID _SpikeRef = SpikeUtils::GUID::Generate();
    };
}

包含的文件 GUID.h 如下所示:

#pragma once

#include <iostream>

#ifdef DLL_SPIKEUTILS
#define SPIKEUTILS_EXPORT __declspec(dllexport)
#else
#define SPIKEUTILS_EXPORT __declspec(dllimport)
#endif

namespace SpikeUtils
{
    class SPIKEUTILS_EXPORT GUID final
    {
    public:
        GUID(GUID const & other) = default;
        GUID& operator=(GUID& other) = default;

        static GUID Generate();
        std::string const & Value();
    private:
        GUID(std::string const & value) : value(value)
        {}
        std::string value;
    };
}

我省略了 GUID.cpp 的实现,因为我认为它不相关。

现在,在 SpikeUI 中,我有一个类 Drawable,它继承自 _SpikeEngineObject.h

 #pragma once

 #include "_SpikeEngineObject.h"

 #ifdef DLL_SPIKEUI
 #define SPIKEUI_EXPORT __declspec(dllexport)
 #else
 #define SPIKEUI_EXPORT __declspec(dllimport)
 #endif

 namespace SpikeUI
 {
     namespace UI
     {
         struct SPIKEUI_EXPORT Drawable : SpikeUtils::_SpikeEngineObject
         {
             ....
         };
     }
 }

显然,所有相应的DLL_定义都已放在每个项目的 C/C++ -> Preprocessor -> Preprocessor 定义中,因此项目应使用适当的 dllimport / dllexport 宏进行构建。

但是当我尝试构建 SpikeUI 时,我收到链接器错误,例如:

LNK2019 unresolved external symbol "__declspec(dllimport) public: __cdecl 
SpikeUtils::_SpikeEngineObject::_SpikeEngineObject(void)" (__imp_?? 
0_SpikeEngineObject@SpikeUtils@@QEAA@XZ) referenced in function "public: 
__cdecl SpikeUI::UI::Drawable::Drawable(enum SpikeUI::UI::DrawableType)" (?? 
0Drawable@UI@SpikeUI@@QEAA@W4DrawableType@12@@Z)

LNK2019 unresolved external symbol "__declspec(dllimport) public: __cdecl 
SpikeUtils::_SpikeEngineObject::~_SpikeEngineObject(void)" (__imp_?? 
1_SpikeEngineObject@SpikeUtils@@QEAA@XZ) referenced in function "int 
`public: __cdecl SpikeUI::UI::Drawable::Drawable(struct UI::Drawable::dtor$0 
const &)'::`1'::dtor$0" (?dtor$0@?0???0Drawable@UI@SpikeUI@@QEAA@AEBU012@@Z@4HA)

一个有趣的事实是,Visual Studio 甚至突出显示将使用的宏,例如 GUID.h 确实突出显示了 dllexport 宏,但 _SpikeEngineObject.h 出于某种原因突出显示了 dllimport 宏。

通过搜索 SO 和 MSDN,看起来这种宏模式应该有效,但由于某种原因,它在我的项目中不一致。

如何解决链接器错误?

C++ 链接器 DLLIMPORT DLLEXPORT unresolved-external

评论

0赞 Hans Passant 3/28/2018
宏汤似乎确实得到了尊重,链接器错误显示“dllimport”。显然,您忘记告诉链接器,当它链接 spikeui 项目时,它需要链接 spikeutils.lib。将其添加到 spikeui 项目的 References 节点。
0赞 Claudiu Apostol 3/28/2018
@HansPassant 它也与 .lib 链接。如果我没有使用其中的宏,而是直接在任何地方使用 __declspec(dllexport),那么程序构建和运行就很好了。
0赞 CristiFati 3/31/2018
是否确定已为正确的平台/配置元组(要为其构建的元组)设置了宏定义(在项目设置中)?stackoverflow.com/questions/44124452/......
0赞 Claudiu Apostol 4/1/2018
@CristiFati是的。我已经为所有配置设置了宏。所以包括调试和发布以及 x64,这就是我构建的基础

答:

1赞 Claudiu Apostol 4/2/2018 #1

在这里回答我自己的问题:

SpikeUI 项目依赖于 SpikeUtils 项目,它与通过生成 SpikeUtils 项目输出的 .lib 和 .dll 项目相关联。

现在,问题是类_SpikeEngineObject是一个仅标头的类(即该类没有.cpp)。因此,我假设 SpikeUtils.lib 不包含_SpikeEngineObject的构造函数/析构函数等的任何符号,因此链接器在链接它时遇到问题。

我通过为类添加一个.cpp文件并实现哑构造函数/析构函数来解决这个问题,以便编译器生成这些符号,一切都很好。