DSO库符号似乎具有DEFAULT可见性,尽管应该是HIDDEN

时间:2016-06-23 09:25:24

标签: c++11 gcc shared-libraries visibility

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

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

+Base
|_Parameter
| |_Parameter.h
| |_Parameter_Exception.h
| |_Parameter_Exception.cpp
|_Data
| |_DataInput.h
| |_DataInput_Exception.h
| |_DataInput_Exception.cpp
...

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

我正在使用CMake来构建这个SHARED库。这是我的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 )

此安装程序构建libBase.so共享库没有任何问题。值得一提的是,我在链接过程中设置了一些与可见性相关的标志:

set( CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined -fvisibility=hidden -fvisibility-inlines-hidden" )

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

  1. Base_Export.h标头包含GCC可见性属性宏 由CMake生成。它然后包含在我列出的来源中 树在那里。
  2. 默认情况下,所有符号都应按照设置隐藏 链接器标志(-fvisibility=hidden
  3. 例如一个Parameter_Exception.h:

    #include "Base_Export.h"
    
    class SomeException : public std::exception
    {
    public:
        SomeException( void ) {}
    ...
    };
    

    请注意我这里没有设置任何可见性属性(通过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 )
    {
        ...
    }
    

    我还尝试使用以下命令在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 
    ....
    

    但我在这里注意到的是,在“Vis”栏中,总是有DEFAULT,这意味着默认的可见性(__attribute__((visibility("default"))))给我,但我希望看到HIDDEN在那里({{1} })

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

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

    __attribute__((visibility("hidden")))

    非常感谢任何愿意帮助我的人,也可能感谢其他人和我一样的麻烦。

    再次感谢,马丁

2 个答案:

答案 0 :(得分:2)

-fvisibility=hidden-fvisibility-inlines-hidden是编译器选项, 不是链接器选项。在CMAKE_CXX_FLAGS

中设置它们

答案 1 :(得分:0)

CMake直接支持符号可见性处理,因此您完全不需要触摸CMAKE_SHARED_LINKER_FLAGSCMAKE_CXX_FLAGS。您可以按每个目标设置可见性,如下所示:

set_target_properties(Base PROPERTIES
    C_VISIBILITY_PRESET       hidden
    CXX_VISIBILITY_PRESET     hidden
    VISIBILITY_INLINES_HIDDEN YES
)

然后,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 ...)

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