【问题标题】:How to have CMake export symbols automatically on Windows?如何在 Windows 上自动让 CMake 导出符号?
【发布时间】:2021-09-03 07:07:39
【问题描述】:

根据我的经验,虽然它可能不正确,但在 Windows 上,如果没有翻译单元导出任何符号,那么在使用 GNU C++ 编译器构建 DLL 时,所有符号都会隐式导出。相反,如果有任何翻译单元导出任何符号,则 DLL 中的所有其他符号都不会隐式导出。

换句话说,如果有一个标题,我们#include__declspec(dllexport) 声明了一个符号,那么我们必须手动将__declspec(dllexport) 插入到其他符号的每个声明中。否则,这些符号将不会被导出。

在 CMake 世界中是否有一种方便的方式,我们不必自己添加__declspec(dllexport)?我试过了

set_target_properties(foo PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)

但它不起作用。有什么建议吗?谢谢。

重新编辑:(2021-09-03 8:34:40 UTC)

以下是重现问题的示例。

示例/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)

示例/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)

例子/foo/foo.hpp:

#ifndef FOO_HPP
#define FOO_HPP

void foo_func(void);

#endif

示例/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)

例子/bar/bar.hpp:

#ifndef BAR_HPP
#define BAR_HPP

void bar_funcA(void);
void bar_funcB(void);

#endif

例子/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__);
}

我的环境:

Windows 10
MSYS2
CMake 3.21.2

结果:

$ 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

根据 Dependency Walker 的说法,从 libbar.dll 导出的唯一符号是 bar_funcB

【问题讨论】:

  • @Tsyvarev 感谢您的回复。问题已更新。谢谢。
  • @Tsyvarev 对不起。重新编辑。谢谢。 :)
  • 好吧,WINDOWS_EXPORT_ALL_SYMBOLS 似乎在 MSys 下不起作用,因为 CMake 不会将“Unix Makefiles”生成器视为“Windows 上的 MS 兼容工具”。另请参阅有关 MinGW 的问题:stackoverflow.com/questions/59838565/…
  • @Tsyvarev 你好,我在sourceware.org/binutils/docs/ld/WIN32.html找到了解决方法,如果你对这个问题仍然感兴趣,请看上面的内容。已经重新编辑了。谢谢。
  • 请不要将解决方案放到问题帖中。相反,写一个答案并在那里描述解决方案。在 Stack Overflow 上完全允许自我回答:stackoverflow.com/help/self-answer.

标签: cmake


【解决方案1】:

根据WIN32 (LD),链接器选项--export-all-symbols 关闭自动导出功能并导出所有符号,除了一些特殊符号。因此,要在不修改 C/C++ 代码的情况下也导出bar_funcA,请在 src/bar/CMakeLists.txt 中添加此行:

target_link_options(bar PRIVATE "-Wl,--export-all-symbols")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多