共享公共包

用过 npm、pip 或是 go 等的包管理系统就知道,对于工程来说,除了工程目录下的依赖包,还可以有一些系统范围共享的依赖包,以便减少重复包所占用的空间。

CMake 也提供了这个功能,允许设置全局范围的默认包搜索路径。

在系统范围内设置 CMAKE_PREFIX_PATH 环境变量可以指定包管理的前缀路径。而 CMAKE_INSTALL_PREFIX 环境变量可以指定安装和搜索包的前缀路径,所以这里优先使用后者方便同时设置安装和搜索包路径。

安装一个包到公共目录

对于可执行文件,可以简单的统一安装到公共目录的 bin 文件夹下。

install(TARGETS base_test DESTINATION bin)

对于库文件,这里希望可以按工程区分不同的包,方便管理。

install(TARGETS libbase
  ARCHIVE DESTINATION "${PROJECT_NAME}/lib")

install(FILES ${public_headers}
  DESTINATION "${PROJECT_NAME}/include/libbase")

区分接口文件包含路径

如果需要安装的库包含接口目录,则有可能因为安装路径变化,导致头文件搜索错误。

这里需要区分构建和安装时的接口文件路径。

target_include_directories(libbase INTERFACE
  $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
  $<INSTALL_INTERFACE:${PROJECT_NAME}/include>)

安装时导出目标

为了方便其他工程引用安装到公共目录的包,可以使用 install 命令增加导出。

install(FILES ${public_headers}
  EXPORT "${PROJECT_NAME}Targets"
  DESTINATION "${PROJECT_NAME}/include/libbase")

对于导出的包,需要增加一个 cmake 文件方便其他工程使用。

安装时导出配置

为了方便 find_package 命令导入包,还需要生成 Config 文件。CMake 提供了脚本来自动生成导出的 Config。

include(CMakePackageConfigHelpers)
configure_package_config_file(
  "${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in"
  "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}Config.cmake"
  INSTALL_DESTINATION "${PROJECT_NAME}/cmake")
write_basic_package_version_file(
  "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}ConfigVersion.cmake"
  VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
  COMPATIBILITY AnyNewerVersion)

同时要提供配置文件模板 LibBaseConfig.cmake.in

@PACKAGE_INIT@

include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
check_required_components(@PROJECT_NAME@)

最后把生成好的文件也安装到全局目录下。

install(DIRECTORY "${PROJECT_BINARY_DIR}/cmake"
  DESTINATION ${PROJECT_NAME})

使用包

安装好的包,其他工程就可以通过 find_package 命令直接使用了。

find_package(LibBase 0.1 REQUIRED)
target_link_libraries(base_test PUBLIC libbase)

参考