在 Visual Studio 2015 上使用静态 const 变量会产生未定义符号 (LNK2001)

Use of static const variable yields to undefined symbol (LNK2001) on Visual Studio 2015

提问人:Alvaro Palma Aste 提问时间:5/24/2018 更新时间:5/24/2018 访问量:1062

问:

我正在尝试使用 Visual Studio 2015 和 CMake 创建一个非常简单的 DLL。

为了避免可能的 DLL 符号导出复杂情况,CMake 为 Windows 启用了符号导出:

set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS on)

我的DLL包含一对文件(标头和cpp):

文件.h

#include <array>
#include <string>

class MyDLL
{
    static const std::array<std::string, 2> MY_ARRAY;
};

文件.cpp

const std::array<std::string, 2> MyDLL::MY_ARRAY =
{{
    "one",
    "two"
}};

但这始终会导致 MyDLL::LNK2001 的未解析外部符号MY_ARRAY

我读过

https://social.msdn.microsoft.com/Forums/vstudio/en-US/e6badd8c-434a-4c5b-b5c2-1d58f4b5dd81/exporting-const-static-data-members-to-dll?forum=vclanguage

但是 AFAIK,所有这些奇怪的 MS 宏 (dllexport/dllimport) 都已经包含在 CMake 设置中。实际上,dllimport 似乎不是必需的功能,而是编译器的帮助程序。

这些看起来很相似,但到目前为止还没有答案:

将 CMake 的 CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS 和 GENERATE_EXPORT_HEADER 与 MSVC 和 GCC 一起使用

http://www.cplusplus.com/forum/general/185807/

事实上,自己的 MS 文档建议:

https://msdn.microsoft.com/en-us/library/f6xx1b1z.aspx

“尝试引用没有外部链接的函数或数据可能会导致LNK2001。在 C++ 中,内联函数和常量数据具有内部链接,除非明确指定为 extern。

但将标头修改为:

class MyDLL
{
    extern static const std::array<std::string, 2> MY_ARRAY;
};

导致全新的大量问题:-)

我还尝试了标头中MyDLL::MY_ARRAY的内联定义:

class MyDLL
{
    static const std::array<std::string, 2> MY_ARRAY =
    {{
        "one",
        "two"
    }};
}

但随后它会触发 C2864 错误:具有类内初始值设定项的静态数据成员必须具有非易失性常量整型(在我的例子中为 std::array)。

知道我错过了什么吗?

提前非常感谢。

旁注:这在 Linux + gcc 4.8 和 MacOSX + AppleClang 9.1.0.9020039 中无需修改即可正常工作

visual-studio-2015 未解析的外部 lnk2001

评论

1赞 stanthomas 5/24/2018
查看 stackoverflow.com/questions/39358641/...在 GCC 中,默认情况下会导出所有内容,这就是它在 Linux 上适合您的原因。
0赞 Alvaro Palma Aste 5/24/2018
@stanthomas,但这就是CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS在 Windows 中等效的作用,不是吗?此外,我几乎可以肯定我在某处读到(找不到在哪里)dllimport 不是强制性的,而是有帮助的。
1赞 stanthomas 5/24/2018
如果你在 blog.kitware.com/ 上阅读这篇文章似乎你必须添加__declspec(dllimport):“对于全局数据符号,在针对DLL中的代码进行编译时,仍必须使用__declspec(dllimport)。建议您尝试根据博客添加__declspec(dllimport)。在我看来,无论如何,您还不如使用 MS 方法,然后您就知道您在哪里。CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS
0赞 Alvaro Palma Aste 5/24/2018
不错的收获,@stanthomas!!!,非常感谢,我会尝试的。虽然我仍然很奇怪,为什么 Windows 要求显式 dllimport() 用于数据符号,而不是用于函数。
0赞 stanthomas 5/25/2018
Kitware 博客文章解释说,CMake 能够为函数生成导出/导入,但不能生成全局数据。因此,CMake 不会完全重现 GCC 的默认行为,而不是 Windows 或 Visual Studio。我认为在共享库中导出所有内容是不明智的,我采用 MS 方法,在 Linux 上也只显式导出所需的外部内容。

答: 暂无答案