CMake 安装和打包
为了方便使用项目编译的目标文件,快速部署到目标目录,可以使用CMake的安装功能;如果需要对外发布,提供头文件、库文件、或者demo的压缩包则可以使用CMake的打包功能。
在本系列前序的文章中已经介绍了CMake很多内容,在CMake应用:CMakeLists.txt完全指南
一文中简略介绍了安装和打包,本文会更加深入地介绍CMake的安装打包功能。本系列更多精彩文章敬请关注公众号【很酷的程序员】的话题:CMake。
本文主要介绍以下几个方面的内容:
-
安装库文件、可执行文件和所需要对外提供的头文件
-
将需要安装的文件打包成压缩包
-
编译构建脚本编写
本文会先介绍相关命令和知识点,如果想先实践,可直接跳到最后一部分。
一 安装
1 install命令
安装使用install
命令,用于指定一个项目的安装规则。其命令格式如下:
-
install(TARGETS <target>... [...])
-
install({FILES | PROGRAMS} <file>... [...])
-
install(DIRECTORY <dir>... [...])
-
install(SCRIPT <file> [...])
-
install(CODE <code> [...])
-
install(EXPORT <export-name> [...])
以上命令概述显示install
命令可以安装的目标类型:构建目标、文件、程序、目录等,对应的关键字后面跟上对应要安装的目标。
安装不同的目标的时候,有一些通用的关键字,下面着重介绍几个最常使用的。
DESTINATION
很好理解,就是安装对象的目标安装路径,可以是绝对路径,也可以是相对路径,如果是相对路径,则认为是相对于CMAKE_INSTALL_PREFIX
的,所以可以配置CMAKE_INSTALL_PREFIX
指定安装目录。
因为cpack
并不支持绝对路径,所以建议还是不要使用绝对路径,当然,除非这是开发者自己确切的目的。
CONFIGURATIONS
为不同的配置设置不同的安装规则。假如对Debug
和Release
两个配置不同的安装路径,代码示例如下:
-
install(TARGETS target
-
CONFIGURATIONS Debug
-
RUNTIME DESTINATION Debug/bin)
-
install(TARGETS target
-
CONFIGURATIONS Release
-
RUNTIME DESTINATION Release/bin)
PERMISSIONS
设置安装目标的权限,接受的参数是一个权限关键字列表,比如:
-
install(TARGETS target
-
RUNTIME PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
2 安装构建目标
安装构建目标的命令格式为:
-
install(TARGETS static_lib shared_lib exe
-
RUNTIME DESTINATION bin
-
LIBRARY DESTINATION lib
-
ARCHIVE DESTINATION lib)
命令第一个参数TARGETS
指定需要安装的构建目标的列表,可以是静态库文件、动态库文件、可执行文件;安装时常常按照文件类型安装到不同的子目录,比如库文件放在lib
目录,可执行文件放在bin
目录。
针对不同文件类型,比如(RUNTIME
, ARCHIVE
, LIBRARY
,PUBLIC_HEADER
),可以分开进行配置,比如分别指定安装路径(DESTINATION
)、设置文件权限(PERMISSIONS
);如果不是在某个类别下的单独配置,那么就是针对所有类型。
值得一提的是,ARCHIVE
一般是指静态库,LIBRARY
则是指共享库,在不同平台上,略有差异,实际应用感觉不符合预期时查看一下官方文档即可,问题不大。
3 安装目录
安装一个目录,一般用于将头文件安装到目标路径。在实际使用中,一般把需要安装的头文件放到一个特定目录下,然后直接安装整个目录即可,比如:
-
install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/"
-
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
更加完备的命令格式为:
-
install(DIRECTORY dirs...
-
TYPE <type> | DESTINATION <dir>
-
[FILES_MATCHING]
-
[[PATTERN <pattern> | REGEX <regex>]
-
[EXCLUDE] [PERMISSIONS permissions...]]
TYPE/DESTINATION
安装目录必须执行安装的目录类型TYPE
或者安装的目标路径DESTINATION
,但是又不可以同时指定;可以使用TYPE
指定安装的目录中的文件类型,然后CMake会自动按照类型分配安装目录,不同类型对应的安装路径如下图:
当然,开发者也可以选择只使用DESTINATION
显式指定安装的目录。
FILES_MATCHING
安装目录的时候默认会安装所有的文件,如果使用FILES_MATCHING
关键字(在第一个PATTERN
或者REGEX
之前),则表示必须要满足对应的模式或者正则的文件才能被安装。
比如,如果目录下源文件和头文件混在一起,但是只想安装其中的头文件,则可以这样写:
-
install(DIRECTORY src/ DESTINATION include/
-
FILES_MATCHING PATTERN "*.h")
PATTERN/REGEX
PATTERN
表示文件名完全匹配才会被安装,而REGEX
则是通过正则表达式匹配目标安装文件(针对目标文件的全路径);在这两个表达式后面还可以加上EXCLUDE
表示反选,或者使用PERMISSIONS
指定匹配的目标文件的权限。
4 安装文件
和安装目录类似,只不过是安装的是文件列表,核心的参数也是类似的;需要使用TYPE
指定文件类型,自行推断安装目录,或者使用DESTINATION
显式指定安装目录。命令格式为:
-
install(<FILES|PROGRAMS> files...
-
TYPE <type> | DESTINATION <dir>
FILES
和PROGRAMS
的不同之处在于文件的默认权限,前者是一般文件,而后者为可执行文件,默认有可执行权限,包括:OWNER_EXECUTE
,GROUP_EXECUTE
和WORLD_EXECUTE
。
5 自定义安装脚本
使用install命令还可以在安装的时候执行自定义的脚本,使用的命令格式为:
-
install([[SCRIPT <file>] [CODE <code>]]
-
[COMPONENT <component>] [EXCLUDE_FROM_ALL] [...])
SCRIPT
指定安装时需要执行的脚本;CODE
指定的是CMake的命令,也在安装期间执行,比如:
install(CODE "MESSAGE(\"Sample install message.\")")
6 执行安装
在构建编译完成之后,可以使用命令执行安装:
-
cmake --build . --target install
-
# 或者针对make构建工具
-
make install
更加优雅的方法是在cmake
3.15版本往后,使用cmake --install
命令:
cmake --install . --prefix "../output"
--install
指定构建目录;--prefix
指定安装路径,覆盖安装路径变量CMAKE_INSTALL_PREFIX
。
二 打包
1 CPack
要使用打包功能,需要执行include(CPack)
启用相关的功能。
include(CPack)
会在构建路径(Build tree)下生成两个cpack
的配置文件,CPackConfig.cmake
和CPackSourceConfig.cmake
,其实也就对应了两个构建目标:package
和package_source
;
配合cpack
命令,使用-G
参数指定生成器,常用的有ZIP
、TGZ
、7Z
等,可以同时指定多个,格式也是CMake语法中的列表,例如其默认值"STGZ;TGZ"
;--config
参数可以指定打包配置文件,比如:
-
cpack -G TGZ --config CPackConfig.cmake
-
cpack -G TGZ --config CPackSourceConfig.cmake
当然也可以使用cmake
命令:
-
cmake --build . --target package
-
cmake --build . --target package_source
如果使用make
作为构建工具,可以简单地执行:
-
make package
-
make package_source
2 CMake打包相关的内置变量
打包的内容就是install
命令安装的内容,以目标打包(CPackConfig.cmake
)为例,主要的相关变量有:
变量 | 含义 |
---|---|
CPACK_GENERATOR | 打包使用的压缩工具,比如"ZIP";cpack 命令的-G 参数会覆盖此设置 |
CPACK_OUTPUT_CONFIG_FILE | 配置文件,默认为CPackConfig.cmake |
CPACK_OUTPUT_FILE_PREFIX | 打包安装的路径前缀。如果是相对路径,则是相对于构建目录 |
CPACK_INSTALL_PREFIX | 打包压缩包的内部目录前缀 |
CPACK_PACKAGE_FILE_NAME | 打包压缩包的名称,由CPACK_PACKAGE_NAME 、CPACK_PACKAGE_VERSION 、CPACK_SYSTEM_NAME 三部分构成 |
需要特别注意的是:以上变量的设置需要在include(CPack)
语句之前。
Before including this CPack module in your CMakeLists.txt file, there are a variety of variables that can be set to customize the resulting installers.
其中CPACK_PACKAGE_NAME
默认为项目名称,CPACK_PACKAGE_VERSION
默认为项目版本号,它们的默认值都是对应project
命令所设置的值;但是如果没有指定版本号,则会是CMake的默认值。
假如:CPACK_OUTPUT_FILE_PREFIX
设置为/usr/local/package
;CPACK_INSTALL_PREFIX
设置为RealCoolEngineer
;CPACK_PACKAGE_FILE_NAME
设置为CMakeTemplate-1.0.0
;那么执行打包文件的生成路径为:
/usr/local/package/CMakeTemplate-1.0.0.zip
解压这个包得到的目标文件则会位于路径下:
/usr/local/package/CMakeTemplate-1.0.0/RealCoolEngineer/
对于源文件打包,相关的变量名基本是对应地以
CPACK_SOURCE_
开头,细节可以查看官方文档。
三 实践
本文仍以开源项目:https://gitee.com/RealCoolEngineer/cmake-template为例,本文对应的commit id为:5713908
。
在项目根目录中的CMakeLists.txt文件中,使用安装和打包的语句为:
-
# Install
-
install(TARGETS math demo
-
RUNTIME DESTINATION bin
-
LIBRARY DESTINATION lib
-
ARCHIVE DESTINATION lib
-
PUBLIC_HEADER DESTINATION include)
-
file(GLOB_RECURSE MATH_LIB_HEADERS src/c/math/*.h)
-
install(FILES ${MATH_LIB_HEADERS} DESTINATION include/math)
-
-
# Package
-
set(CPACK_GENERATOR "ZIP")
-
set(CPACK_SET_DESTDIR ON) # 支持指定安装目录
-
set(CPACK_INSTALL_PREFIX "RealCoolEngineer")
-
include(CPack)
安装打包的内容为项目构建目标可执行文件demo
,静态库math
,以及math
库对应的头文件。
1 构建脚本
为了方便,笔者通常将构建的命令编写为脚本,在脚本内指定文件的安装、打包的目标目录(CMake参数)。
下面针对cmake-template
的一个示范,将目标文件安装并打包到项目根目录下的output
目录:
-
-
-
set -euf -o pipefail
-
-
BUILD_DIR="cmake-build"
-
INSTALL_DIR=$(pwd)/output
-
rm -rf "${BUILD_DIR}"
-
-
# Configure
-
BUILD_TYPE=Debug
-
cmake -B "${BUILD_DIR}" \
-
-DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \
-
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-
-DCPACK_OUTPUT_FILE_PREFIX="${INSTALL_DIR}"
-
-
# Build
-
cmake --build "${BUILD_DIR}"
-
-
cd "${BUILD_DIR}"
-
# Test
-
make test CTEST_OUTPUT_ON_FAILURE=TRUE GTEST_COLOR=TRUE
-
# GTEST_COLOR=TRUE ctest --output-on-failure
-
-
# Install
-
# cmake --build . --target install
-
# cmake --install . --prefix "../output" # After cmake 3.15
-
make install
-
-
# Package
-
# cmake --build . --target package
-
make package
-
-
cd -
以上便是关于安装和打包的介绍,关于构建脚本开头set
命令的几个参数,可参看往期这篇文章:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了