DSO 库符号似乎具有默认可见性,但应该是隐藏的

Mar*_*cký 3 gcc visibility shared-libraries c++11

我在设置共享库的可见性时遇到问题。我想寻求帮助以解决我的问题,如下所述:

我有一堆源文件,我想将它们构建为共享库:

+Base
|_Parameter
| |_Parameter.h
| |_Parameter_Exception.h
| |_Parameter_Exception.cpp
|_Data
| |_DataInput.h
| |_DataInput_Exception.h
| |_DataInput_Exception.cpp
...
Run Code Online (Sandbox Code Playgroud)

那里还有一些文件,但我认为它不会影响我的问题描述。

我正在使用 CMake 来构建这个共享库。这是我处理构建库的 CMakeLists.txt 的一部分。

project( Base )
cmake_minimum_required(VERSION 3.5

set( Base_HEADERS
    Parameter/Parameter.h
    Parameter/Parameter_Exception.h
    Data/DataInput.h
    Data/DataInput_Exception.h
)
set( Base_SOURCES
    Parameter/Parameter_Exception.cpp
    Data/DataInput_Exception.cpp
)
set( LIBRARY_OUTPUT_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} )

add_library( Base SHARED ${Base_SOURCES} ${Base_HEADERS} )

generate_export_header( ${PROJECT_NAME} EXPORT_FILE_NAME ${PROJECT_NAME}_Export.h )
Run Code Online (Sandbox Code Playgroud)

此设置构建 libBase.so 共享库没有任何问题。值得一提的是,我已经设置了一些在链接期间使用的可见性相关标志:

set( CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined -fvisibility=hidden -fvisibility-inlines-hidden" )
Run Code Online (Sandbox Code Playgroud)

如上面部分列出的基本库 CMakeLists.txt 中的配置:

  1. Base_Export.h 头文件包含 GCC 可见性属性宏是由 CMake 生成的。然后它被包含在我在树上列出的来源中。
  2. 默认情况下,所有符号都应按照链接器标志 ( -fvisibility=hidden) 中的设置隐藏

例如一块 Parameter_Exception.h:

#include "Base_Export.h"

class SomeException : public std::exception
{
public:
    SomeException( void ) {}
...
};
Run Code Online (Sandbox Code Playgroud)

请注意我没有在这里设置任何可见性属性(通过 Base_Export 中定义的宏)。所以我假设,SomeException 类的符号应该对所有 DSO“用户”隐藏(由于-fvisibility=hidden

但似乎并非如此。很遗憾:

一旦我使用了该库,它就可以使用该异常,尽管该符号应该被隐藏。我希望此代码片段“在库外”导致链接失败:

#include "Parameter/Parameter_Exception.h"
...
try
{
    ...
}
/* THIS SHOULD FAIL IN LINKING DUE TO UNDEFINED SYMBOL, RIGHT? */
catch( const SomeException & e )
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

我还尝试使用以下命令在 libBase.so 中查找符号:readelf -Ws libBase.so

它列出了非常长的文本:

Num:    Value          Size Type    Bind   Vis      Ndx Name
  0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
  1: 000000000008b7e0     0 SECTION LOCAL  DEFAULT    9 
....
Run Code Online (Sandbox Code Playgroud)

但我在这里注意到的是,在上面的“Vis”列中,总是有 DEFAULT 这意味着__attribute__((visibility("default")))对我来说默认可见性 ( ) 但我希望在那里看到 HIDDEN ( __attribute__((visibility("hidden"))))

那么我做错了什么?还是我的理解不正确?我知道所有链接的标志都正确传播,但似乎没有效果。

我的工具链配置由 CMake 配置脚本(支持可见性属性的 GCC 版本)列出:

...
-- The CXX compiler identification is GNU 5.3.1
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
...
-- Performing Test COMPILER_HAS_HIDDEN_VISIBILITY
-- Performing Test COMPILER_HAS_HIDDEN_VISIBILITY - Success
-- Performing Test COMPILER_HAS_HIDDEN_INLINE_VISIBILITY
-- Performing Test COMPILER_HAS_HIDDEN_INLINE_VISIBILITY - Success
-- Performing Test COMPILER_HAS_DEPRECATED_ATTR
-- Performing Test COMPILER_HAS_DEPRECATED_ATTR - Success
-- Configuring done
-- Generating done
Run Code Online (Sandbox Code Playgroud)

非常感谢任何愿意帮助我的人以及可能与我遇到同样麻烦的其他人。

再次感谢,马丁

Cra*_*ott 5

CMake 直接支持符号可见性处理,因此您不需要触摸CMAKE_SHARED_LINKER_FLAGS或根本不需要触摸CMAKE_CXX_FLAGS。您可以像这样在每个目标的基础上设置可见性:

set_target_properties(Base PROPERTIES
    C_VISIBILITY_PRESET       hidden
    CXX_VISIBILITY_PRESET     hidden
    VISIBILITY_INLINES_HIDDEN YES
)
Run Code Online (Sandbox Code Playgroud)

然后 CMake 将确保为您添加相关标志。不必为每个目标设置这些属性,通常更方便的是设置关联变量来为所有随后创建的目标设置默认值(这是我通常在我从事的项目中推荐和使用的):

cmake_minimum_required(VERSION 3.5)
project(Base)

set(CMAKE_C_VISIBILITY_PRESET       hidden)
set(CMAKE_CXX_VISIBILITY_PRESET     hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN YES)

add_library(Base SHARED ...)
Run Code Online (Sandbox Code Playgroud)

当与GenerateExportHeader模块(您似乎已经在使用)结合使用时,您不仅可以获得对 gcc/clang 的支持,还可以获得对 Visual Studio 的支持,使其成为控制符号可见性的一种很好的跨平台方式。您不需要知道相关的编译器标志或属性,CMake 会为您处理它们并在所有编译器中为您提供等效的行为。