如果其中一个函数显式以 __declspec 为前缀,则 CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS 不会导出符号

问题描述 投票:0回答:1

我注意到 CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS CMake 变量有奇怪的不一致行为。考虑小型示例项目(Windows、MinGW):

cmake_minimum_required(VERSION 3.20 FATAL_ERROR)

project(Test VERSION 1.0.0)

option(BUILD_SHARED_LIBS "Build the project using shared libraries (Windows *.dll, or Linux *.so)" ON)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3")
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(CMAKE_CXX_STANDARD 17)

add_library(foobar foobar.cpp)
target_compile_definitions(foobar PRIVATE "FOOBAR_LIBRARY")
add_library(baz baz.cpp)
target_link_libraries(baz PUBLIC foobar)

以及来源:

/****** foobar.h ******/
#pragma once

#if defined(FOOBAR_LIBRARY)
#define FOOBAR_EXPORT __declspec(dllexport)
#else
#define FOOBAR_EXPORT __declspec(dllimport)
#endif

void foo();
FOOBAR_EXPORT void bar();
// void bar();  // removing explicit FOOBAR_EXPORT makes it work

/****** foobar.cpp ******/
#include "foobar.h"  // commenting-out the header include will make it work
void foo() {}
void bar() {}

/****** baz.cpp ******/
#include "foobar.h"

void baz() {
    foo();
    bar();
}

配置后

cmake -G "MinGW Makefiles" ../

并尝试使用

进行编译
cmake --build .

链接器失败并出现错误:

baz.cpp:5: undefined reference to `foo()'

我注意到:

  • FOOBAR_EXPORT
    中删除
    void bar
    可以使其正确链接
  • #include "foobar.h"
    中删除
    foobar.cpp
    可以使其正确链接
  • (显然)将
    FOOBAR_EXPORT
    添加到
    void foo
    可以使其正确链接

我可以在

CMakeLists.txt
FOOBAR_EXPORT
的定义中进行哪些更改,以始终导出所有符号,即使其中一些符号在声明前面有明确的
__declspec

应用上述 3 个解决方案中的任何一个对我来说都是维护地狱,因为问题出在大型自动生成的 OpenAPI 代码中。

c++ cmake mingw dllimport dllexport
1个回答
0
投票

在 Windows 上链接时,除非满足某些条件,否则默认行为是“自动导出 DLL 中的所有符号”。首要条件是:

如果未在命令行上显式给出
--export-all-symbols

,则如果满足以下任一条件,则默认自动导出行为将被禁用:


使用 DEF 文件。
  • 任何目标文件中的任何符号都标有
  • __declspec(dllexport)
  • 属性。
    
    
导出的整个符号集描述为:

当自动导出运行时,ld 将导出它在 DLL 中找到的所有非本地(全局和公共)符号,除了一些已知属于系统运行时和库的符号。由于通常不需要导出 DLL 的所有符号,其中可能包括不属于任何公共接口的私有函数,因此上面列出的命令行选项可用于从导出列表中过滤符号。可以使用
--output-def

选项查看导出符号的最终列表,其中所有排除均已生效。


因此,如果您发现自己想要重新启用“所有符号导出”行为;您可以将
--export-all-symbols

选项添加到链接器。

实现这一点的命令行方法是

-Wl,--export-all-symbols

实现此目的的 cmake 方法是将此选项添加到链接器的 

CMakeLists.txt

中;这可以通过将其添加到 CXX_FLAGS 来完成:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--export-all-symbols")

但是,cmake 表明在这种情况下,
CMAKE_SHARED_LINKER_FLAGS

是一个稍微更好的变量选择。

    

© www.soinside.com 2019 - 2024. All rights reserved.