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

原文链接: https://www.cnblogs.com/fortunely/p/16297277.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    CMake 导出库的头文件GenerateExportHeader

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/189184

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月12日 下午2:44
下一篇 2023年2月12日 下午2:44

相关推荐