1

I'm trying to create a really simple DLL using Visual Studio 2015 and CMake.

To avoid possible DLL symbol export complications, CMake has the export of symbols enabled for Windows:

set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS on)

My DLL contains a single pair of files (header and cpp):

file.h

#include <array>
#include <string>

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

file.cpp

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

But this always leads to LNK2001 Unresolved external symbol for MyDLL::MY_ARRAY

I've read

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

but AFAIK, all those weird MS macros (dllexport/dllimport) are already covered by the CMake settings. Actually, dllimport doesn't seem to be a required feature, but a helper for the compiler instead.

These look pretty similar, but with no answer so far:

Use both CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS and GENERATE_EXPORT_HEADER of CMake with both MSVC and GCC

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

In fact, the own MS documentation suggests:

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

"Attempting to reference functions or data that don't have external linkage can cause LNK2001. In C++, inline functions and const data have internal linkage unless explicitly specified as extern."

but modifying the header to:

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

leads to a whole new plethora of issues :-)

I also tried the inline definition of MyDLL::MY_ARRAY in the header:

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

But then it triggers a C2864 error: a static data member with an in-class initializer must have non-volatile const integral type (in my case, a std::array).

Any idea of what I'm missing?

Thanks a lot in advance.

Side note: This works fine without modification in both Linux + gcc 4.8 and MacOSX + AppleClang 9.1.0.9020039

  • 1
    See https://stackoverflow.com/questions/39358641/linking-with-a-dll-compiles-but-causes-a-segfault/39368782#39368782 In GCC, everything is exported by default, which is why it's working for you on Linux. – stanthomas May 23 '18 at 21:21
  • @stanthomas, but that's what CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS equivalently does in Windows, isn't? Also, I'm almost certain I read somewhere (can't find where) that dllimport is not mandatory, but helpful instead. – Alvaro Palma Aste May 23 '18 at 21:31
  • 1
    if you read this article on `CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS` https://blog.kitware.com/create-dlls-on-windows-without-declspec-using-new-cmake-export-all-feature/ it appears you have to add __declspec(dllimport) anyway : "For global data symbols, __declspec(dllimport) must still be used when compiling against the code in the DLL." . Suggest you try adding __declspec(dllimport) as per the blog. It seems to me you might as well just use the MS method anyway, then you know where youi are. – stanthomas May 23 '18 at 23:01
  • Nice catch, @stanthomas!!!, thanks a lot, I'll try that. Though it's still weird to me why Windows requires that explicit dllimport() for data symbols, but not for functions. – Alvaro Palma Aste May 24 '18 at 02:04
  • The Kitware blog post explains that CMake is able to generate export/imports for functions but not global data. So it's CMake that doesn't completely reproduce the default behavior of GCC, not Windows or Visual Studio. I think it's unwise to export everything in a shared library and I adopt the MS approach of explicitly exporting only the required externals on Linux too. – stanthomas May 25 '18 at 10:57

0 Answers0