'How to have CMake export symbols automatically on Windows?
According to my experience, though it may be incorrect, on Windows if no translation unit exports any symbol then all symbols are implicitly exported when building a DLL with GNU C++ compiler. In contrast, if there is any translation unit exports any symbol, then all others symbols in the DLL are NOT implicitly exported.
In other words, if there is a header we #include
declares a symbol with __declspec(dllexport)
, then we have to manually insert __declspec(dllexport)
to every single declarations of other symbols. Otherwise, those symbols will not get exported.
Is there a convenient way in CMake world that we don't have to add __declspec(dllexport)
ourselves? I've tried
set_target_properties(foo PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
but it doesn't work. Any suggestion? Thanks.
Reedit: (2021-09-03 8:34:40 UTC)
Below is an example to recreate the problem.
example/CMakeLists.txt:
cmake_minimum_required(VERSION 3.21)
project(example VERSION 1.0)
add_executable(myapp main.cpp)
add_subdirectory(foo)
add_subdirectory(bar)
target_link_libraries(myapp PRIVATE foo)
example/main.cpp:
#include "foo.hpp" // for function foo_func
int main(int argc, char *argv[])
{
foo_func();
return 0;
}
example/foo/CMakeLists.txt:
add_library(foo SHARED foo.cpp)
target_include_directories(foo INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}")
target_link_libraries(foo PRIVATE bar)
example/foo/foo.hpp:
#ifndef FOO_HPP
#define FOO_HPP
void foo_func(void);
#endif
example/foo/foo.cpp:
#include "bar.hpp" // for function bar_funcA
void foo_func(void)
{
bar_funcA();
}
example/bar/CMakeLists.txt
add_library(bar SHARED bar.cpp)
target_include_directories(bar INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
set_target_properties(bar PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
example/bar/bar.hpp:
#ifndef BAR_HPP
#define BAR_HPP
void bar_funcA(void);
void bar_funcB(void);
#endif
example/bar/bar.cpp:
#include <cstdio> // for function printf
void bar_funcA(void)
{
std::printf("%s\n", __func__);
}
__declspec(dllexport) void bar_funcB(void)
{
std::printf("%s\n", __func__);
}
My environment:
Windows 10
MSYS2
CMake 3.21.2
Result:
$ cmake -G 'Unix Makefiles' -S example/ -B build/
$ cmake --build build/
[ 16%] Building CXX object bar/CMakeFiles/bar.dir/bar.cpp.obj
[ 33%] Linking CXX shared library libbar.dll
[ 33%] Built target bar
Consolidate compiler generated dependencies of target foo
[ 50%] Building CXX object foo/CMakeFiles/foo.dir/foo.cpp.obj
[ 66%] Linking CXX shared library libfoo.dll
C:/msys64/mingw64/x86_64-w64-mingw32/bin/ld.exe: CMakeFiles/foo.dir/objects.a(foo.cpp.obj):foo.cpp:(.text+0x9): undefined reference to `bar_funcA()'
collect2.exe: error: ld returned 1 exit status
make[2]: *** [foo/CMakeFiles/foo.dir/build.make:102: foo/libfoo.dll] Error 1
make[1]: *** [CMakeFiles/Makefile2:144: foo/CMakeFiles/foo.dir/all] Error 2
make: *** [Makefile:91: all] Error 2
According to Dependency Walker, the only symbol that gets exported from libbar.dll is bar_funcB
.
Solution 1:[1]
According to WIN32 (LD):
… the default auto-export behavior will be disabled if either of the following are true:
A DEF file is used.
Any symbol in any object file was marked with the
__declspec(dllexport)
attribute.
In this case, the --export-all-symbols
linker option forces the auto-export functionality and exports all symbols, except some special ones. Therefore, to also export bar_funcA
without modifying C/C++ codes, add this line in src/bar/CMakeLists.txt:
target_link_options(bar PRIVATE "-Wl,--export-all-symbols")
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Community |