Craig Scott 在 cppconf 2019 的演讲:
CppCon 2019: Deep CMake For Library Authors
This talk highlights key CMake features relevant to C++ cross-platform library authors, digging deeper into platform-specific quirks and conventions.
https://crascit.com/2019/10/16/cppcon-2019-deep-cmake-for-library-authors/
文档:
要点:
-
API Control 可见性
# generate_export_header command 介绍:https://www.cnblogs.com/fortunely/p/16297277.html set(CMAKE_CXX_VISIBILITY_PRESET hidden) set(CMAKE_VISIBILITY_INLINES_HIDDEN YES) add_library(MyTgt ...) include(GenerateExportHeader) generate_export_header(MyTgt) # 结果 # 1. 生成 mytgt_export.h 头文件 # 2. 文件中定义了几个宏用于控制 visibility deprecated 等 # 3. 宏举例:MYTGT_EXPORT, MYTGT_NO_EXPORT, MYTGT_DEPRECATED, MYTGT_DEPRECATED_EXPORT, MYTGT_DEPRECATED_NO_EXPOR -
API Compatibility

设置了 target 的属性
SOVERSION和VERSION之后,就会生成三个.so文件- 图中第三个时人类可读的,具体的库文件
- 图中第二个
SONAME是ldd会读取的,它用来判断API的兼容性。如果没设置SOVERSION,那么SOVERSION = VERSION。此时要求major.minor.patch全匹配才能被ldd加载
-
如何被打包
include(GNUInstallDirs) install(TARGETS Example RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT SomeProj_RunTime LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT SomeProj_RunTime NAMELINK_COMPONENT SomeProj_Development ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT SomeProj_Development ) # 要点: # 1. 使用 ${CMAKE_INSTALL_BINDIR} 等变量指定安装路径,避免绝对路径 # 2. COMPONENT 关键字组织产出物 # 3. 加上 project name 前缀避免和其他库 component 冲突 -
考虑用户使用
注意的点是在安装的时候会把 DT_RPATH 清空(默认情况下)

考虑下图所示情况,APP 间接依赖
Vendor库
DT_RUNPATH dynamic section attribute of the binary if present. Such directories are searched only to find those objects required by DT_NEEDED (direct dependencies) entries and do not apply to those objects' children, which must themselves have their own DT_RUNPATH entries. This is unlike DT_RPATH, which is applied to searches for all children in the dependency tree.
APP的DT_RUNPATH中记录的目录只用来寻找APP的直接依赖[libExample.so](http://libExample.so),找不到Vendor库。解决方法:
# insatll 后在 Example 的 DT_RPATH 存着 Example 依赖项的查找路径,这个路径就是 libExample.so 所在的路径。 set(CMAKE_INSTALL_RPATH $ORIGIN) add_library(Example ...)查看 DT_RPATH:
readelf -d <path/to/target>