• CMake 导出库的头文件GenerateExportHeader


    generate_export_header简介

    generate_export_header()用于为library export宏定义。生成一个适用于预处理的文件,包含用在library中的EXPORT宏定义。

    适用场景:假设我们用了一个自定义library,为避免跟用到的其他库重名,但又不得不开放public接口,就可以应用到generate_export_header 导出library export宏定义,将非public接口隐藏,将public接口设置为可见(<base_name>_EXPORT)。

    CMake v3.12新增对C项目支持,老版本只支持C++项目。

    语法格式

    GENERATE_EXPORT_HEADER( LIBRARY_TARGET
              [BASE_NAME <base_name>]
              [EXPORT_MACRO_NAME <export_macro_name>]
              [EXPORT_FILE_NAME <export_file_name>]
              [DEPRECATED_MACRO_NAME <deprecated_macro_name>]
              [NO_EXPORT_MACRO_NAME <no_export_macro_name>]
              [STATIC_DEFINE <static_define>]
              [NO_DEPRECATED_MACRO_NAME <no_deprecated_macro_name>]
              [DEFINE_NO_DEPRECATED]
              [PREFIX_NAME <prefix_name>])
    

    目标属性 CXX_VISIBILITY_PRESET 和 VISIBILITY_INLINES_HIDDEN 能用于为目标添加合适的编译flags。

    场景

    默认情况下,generate_export_header() 在一个由library名称决定的文件中生成宏定义名称。意味着在最简单情况下,GenerateExportHeader的用户相当于:

    # CMake片段
    set(CMAKE_CXX_VISIBILITY_PRESET hidden) # 与generate_export_header搭配使用, 设置函数可见性
    set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) # 与generate_export_header搭配使用, 设置内联函数可见性
    add_library(somelib someclass.cpp) # 生成library somelib
    generate_export_header(somelib) # 为somelib export宏定义, 生成的文件名为somelib_export.h, 路径: ${CMAKE_CURRENT_BINARY_DIR}
    install(TARGEST somelib DESTINATION ${LIBRARY_INSTALL_DIR}) # 安装目标somelib(库文件)到目标目录 (拷贝)
    install(FILES
        someclass.h
        ${PROJECT_BINARY_DIR}/somelib_export.h DESTINATION ${INCLUDE_INSTALL_DIR}
    ) # 安装文件someclass.h, somelib_export.h 到指定目标目录 (拷贝)
    在ABI头文件:
    
    #include "somelib_export.h"
    class SOMELIB_EXPORT SomeClass { # public 类, 提供给用户使用, 使用SOMELIB_EXPORT声明, 避免重名
        ...
    };
    

    上面的CMake 片段将会在 ${CMAKE_CURRENT_BINARY_DIR}路径下生成名为somelib_export.h的文件,包含宏定义 SOMELIB_EXPORT, SOMELIB_NO_EXPORT, SOMELIB_DEPRECATED, SOMELIB_DEPRECATED_EXPORT 以及 SOMELIB_DEPRECATED_NO_EXPORT。生成的结果文件,应该和库中其他头文件一起安装。

    BASE_NAME

    BASE_NAME参数能用于重写(override)文件名和宏定义名称:

    add_library(somelib someclass.cpp)
    generate_export_header(somelib
        BASE_NAME other_name
    )
    

    生成一个名为other_name_export.h的文件,包含宏定义OTHER_NAME_EXPORT, OTHER_NAME_NO_EXPORT 和 OTHER_NAME_DEPRECATED等等。

    BASE_NAME也可能通过在函数中指定其他选项而被重写。例如:

    add_library(somelib someclass.cpp)
    generate_export_header(somelib
        EXPORT_MACRO_NAME OTHER_NAME_EXPORT
    )
    

    OTHER_NAME_EXPORT

    创建宏定义OTHER_NAME_EXPORT替换SOME_EXPORT,但其他宏定义和生成的文件名为默认值:

    add_library(somelib someclass.cpp)
    generate_export_header(somelib
        DEPRECATED_MACRO_NAME KDE_DEPRECATED
    )
    

    创建宏定义KDE_DEPRECATED替换SOMELIB_DEPRECATED。
    如果LIBRARY_TARGET是一个静态库,宏定义将被定义,但没有值。

    同源构建shared, static library

    如果同样的源被用于创建一个shared和static library,大写的${BASE_NAME}_STATIC_DEFIN 应该被用于构建该static library:

    add_library(shared_variant SHARED ${lib_SRCS}) # 创建shared库
    add_library(static_variant ${lib_SRCS}) # 用相同源文件创建static库
    generate_export_header(shared_variant BASE_NAME libshared_and_static) # 会导出名为libshared_and_static_export.h的头文件
    set_target_properties(static_variant PROPERTIES
      COMPILE_FLAGS -DLIBSHARED_AND_STATIC_STATIC_DEFINE)
    

    上述代码会导致export宏定义在构建static library时,扩展为空。

    DEFINE_NO_DEPRECATED

    如果指定了DEFINE_NO_DEPRECATED,那么一个宏${BASE_NAME}_NO_DEPRECATED 将会被定义。该宏能用于从预处理输出中移除deprecated code(不推荐使用的代码):

    option(EXCLUDE_DEPRECATED "Exclude depreacted parts of the library" FLASE)
    if (EXCLUDE_DEPRECATED)
        set(NO_BUILD_DEPRECATED DEFINE_NO_DEPRECATED)
    endif()
    generate_export_header(somelib ${NO_BUILD_DEPRECATED})
    

    接着,在somelib中:

    class SOMELIB_EXPORT SomeClass
    {
    public:
    #ifndef SOMELIB_NO_DEPRECATED
        SOMELIB_DEPRECATED void oldMethod();
    #endif
    };
    
    #ifndef SOMELIB_NO_DEPRECATED
    void SomeClass::oldMethod() { }
    #endif
    

    PREFIX_NAME

    如果指定了PREFIX_NAME,参数将用于所有生成的宏定义前缀:

    generate_export_header(somelib PREFIX_NAME VTK_)
    

    这样,会生成宏定义VTK_SOMELIB_EXPORT等

    ADD_COMPILER_EXPORT_FLAGS

    ADD_COMPILER_EXPORT_FLAGS( [<output_variable>] )
    

    如果支持的话,ADD_COMPILER_EXPORT_FLAGS函数添加 -fvisibility=hidden 到CMAKE_CXX_FLAGS,并且这将是一个Windows上的no-op(空操作),如果不需要用于exporting支持的额外的编译选项。你可能随意传递一个单一参数给ADD_COMPILER_EXPORT_FLAGS,将会用CXX_FLAGS填充,要求使能可见性支持使用中的编译器/体系。

    该函数(ADD_COMPILER_EXPORT_FLAGS)已经不推荐使用。参考 CXX_VISIBILITY_PRESET and VISIBILITY_INLINES_HIDDEN。

    其他细节

    CMAKE_CXX_VISIBILITY_PRESET 变量

    target创建时,target属性CXX_VISIBILITY_PRESET的默认值。CXX_VISIBILITY_PRESET属性值决定编译flags的符号可见性(symbol visibility),与编译选项有关,如-fvisibility=。该属性影响所有类型目标的源的编译。

    CXX_VISIBILITY_PRESET影响普通函数。

    -fvisibility=hidden 在解决多个动态库同名函数时,很有效。

    CMAKE_VISIBILITY_INLINES_HIDDEN 变量

    target创建时,target属性VISIBILITY_INLINES_HIDDEN的默认值。VISIBILITY_INLINES_HIDDEN属性值决定是否添加编译flag,以隐藏inline函数的符号,与编译选项-fvisibility-inlines-hidden有关。该属性影响所有类型目标的源的编译。

    VISIBILITY_INLINES_HIDDEN影响inline函数。

    参考

    https://cmake.org/cmake/help/v3.0/module/GenerateExportHeader.html

    https://blog.csdn.net/qq_37887537/article/details/89472705

    https://cmake.org/cmake/help/latest/command/install.html

  • 相关阅读:
    zabbix配合脚本监控Kafka
    用strings命令查看kafka-log内容 过滤二进制编码
    docker容器中搭建kafka集群环境
    Elasticsearch究竟要设置多少分片数?
    elasticsearch 基础知识汇总
    ES磁盘分配不均问题
    elasticsearch-5.1.1使用snapshot接口备份索引
    filebeat.yml(中文配置详解)
    elasticsearch分词器Jcseg安装手册
    开启了1000个线程并发去查询elasticsearch把es搞挂了
  • 原文地址:https://www.cnblogs.com/fortunely/p/16297277.html
Copyright © 2020-2023  润新知