CMake CPack 打包
CPack 是 CMake 自带的打包工具,可以将项目打包成各种格式的安装包,如 DEB、RPM、NSIS、DragNDrop 等。本章将详细介绍如何使用 CPack 进行软件打包和分发。
CPack 简介
什么是 CPack?
CPack 是 CMake 套件中的打包程序,它可以:
- 生成安装包:支持多种安装包格式
- 跨平台分发:为不同平台创建原生安装包
- 自动安装配置:处理文件安装、依赖关系等
- 版本管理:自动生成版本信息
支持的打包格式
| 格式 | 平台 | 说明 |
|---|---|---|
| DEB | Linux (Debian/Ubuntu) | Debian 软件包 |
| RPM | Linux (Red Hat/Fedora) | RPM 软件包 |
| TGZ | 跨平台 | 压缩包 |
| ZIP | 跨平台 | ZIP 压缩包 |
| NSIS | Windows | Windows 安装程序 |
| WIX | Windows | Windows Installer (MSI) |
| DragNDrop | macOS | DMG 磁盘镜像 |
| Bundle | macOS | macOS 应用程序包 |
| PKG | macOS | macOS 安装包 |
基本使用
启用 CPack
在 CMakeLists.txt 末尾添加:
cmake_minimum_required(VERSION 3.15)
project(MyApp VERSION 1.0.0)
add_executable(myapp src/main.cpp)
# 安装规则
install(TARGETS myapp RUNTIME DESTINATION bin)
# 启用 CPack
include(CPack)
打包基本信息
设置包的基本信息:
# 项目信息
set(CPACK_PACKAGE_NAME "MyApp")
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A sample application")
set(CPACK_PACKAGE_VENDOR "MyCompany")
set(CPACK_PACKAGE_CONTACT "[email protected]")
# 安装目录结构
set(CPACK_PACKAGING_INSTALL_PREFIX "/opt/myapp")
include(CPack)
生成安装包
# 配置项目
cmake -B build
# 构建
cmake --build build
# 打包
cd build
cpack
# 指定生成器
cpack -G DEB
cpack -G TGZ
常用配置变量
基本信息
# 包名称
set(CPACK_PACKAGE_NAME "MyApp")
# 版本号
set(CPACK_PACKAGE_VERSION_MAJOR 1)
set(CPACK_PACKAGE_VERSION_MINOR 0)
set(CPACK_PACKAGE_VERSION_PATCH 0)
# 或直接使用
set(CPACK_PACKAGE_VERSION "1.0.0")
# 描述
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "My Application")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md")
# 供应商
set(CPACK_PACKAGE_VENDOR "MyCompany")
set(CPACK_PACKAGE_CONTACT "[email protected]")
# 图标
set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/resources/icon.png")
文件和目录
# 安装前缀
set(CPACK_PACKAGING_INSTALL_PREFIX "/usr/local")
# 资源文件目录
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md")
set(CPACK_RESOURCE_FILE_WELCOME "${CMAKE_SOURCE_DIR}/WELCOME.txt")
# 输出目录
set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}/packages")
压缩设置
# 压缩格式
set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)
# 压缩级别
set(CPACK_ARCHIVE_THREADS 0) # 使用所有 CPU 核心
Linux 打包
DEB 包(Debian/Ubuntu)
# DEB 包配置
set(CPACK_GENERATOR "DEB")
# 包信息
set(CPACK_DEBIAN_PACKAGE_NAME "myapp")
set(CPACK_DEBIAN_PACKAGE_VERSION ${PROJECT_VERSION})
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Developer <[email protected]>")
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "My Application
This is a longer description of my application.
It can span multiple lines.")
# 依赖关系
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.17), libstdc++6 (>= 4.9)")
# 推荐和建议依赖
set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "myapp-plugins")
set(CPACK_DEBIAN_PACKAGE_SUGGESTS "myapp-doc")
# 包分类
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
# 控制文件
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
"${CMAKE_SOURCE_DIR}/debian/postinst"
"${CMAKE_SOURCE_DIR}/debian/prerm"
)
include(CPack)
维护脚本
debian/postinst(安装后脚本):
#!/bin/sh
set -e
# 创建配置目录
mkdir -p /etc/myapp
# 设置权限
chmod 755 /usr/bin/myapp
echo "MyApp has been installed successfully!"
debian/prerm(卸载前脚本):
#!/bin/sh
set -e
echo "Preparing to remove MyApp..."
RPM 包(Red Hat/Fedora)
# RPM 包配置
set(CPACK_GENERATOR "RPM")
# 包信息
set(CPACK_RPM_PACKAGE_NAME "myapp")
set(CPACK_RPM_PACKAGE_VERSION ${PROJECT_VERSION})
set(CPACK_RPM_PACKAGE_RELEASE "1")
set(CPACK_RPM_PACKAGE_ARCHITECTURE "x86_64")
set(CPACK_RPM_PACKAGE_SUMMARY "My Application")
set(CPACK_RPM_PACKAGE_DESCRIPTION "A longer description
of my application.")
# 许可证
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
# 分组
set(CPACK_RPM_PACKAGE_GROUP "Applications/Utilities")
# 依赖关系
set(CPACK_RPM_PACKAGE_REQUIRES "glibc >= 2.17, libstdc++ >= 4.9")
# 指定文件
set(CPACK_RPM_PACKAGE_RELOCATABLE ON)
# 安装前/后脚本
set(CPACK_RPM_PRE_INSTALL_SCRIPT_FILE "${CMAKE_SOURCE_DIR}/rpm/preinst")
set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${CMAKE_SOURCE_DIR}/rpm/postinst")
set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE "${CMAKE_SOURCE_DIR}/rpm/prerm")
set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE "${CMAKE_SOURCE_DIR}/rpm/postrm")
include(CPack)
Windows 打包
NSIS 安装程序
# NSIS 配置
set(CPACK_GENERATOR "NSIS")
# 安装程序信息
set(CPACK_NSIS_PACKAGE_NAME "MyApp")
set(CPACK_NSIS_DISPLAY_NAME "My Application")
set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
set(CPACK_NSIS_INSTALLER_ICON_CODE "")
set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/resources/icon.ico")
set(CPACK_NSIS_MUI_UNIICON "${CMAKE_SOURCE_DIR}/resources/uninstall.ico")
# 安装选项
set(CPACK_NSIS_MODIFY_PATH ON) # 添加到 PATH
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
# 创建桌面快捷方式
set(CPACK_NSIS_CREATE_ICONS_EXTRA
"CreateShortCut '$DESKTOP\\\\MyApp.lnk' '$INSTDIR\\\\bin\\\\myapp.exe'"
)
# 开始菜单
set(CPACK_NSIS_MENU_LINKS
"bin/myapp.exe" "MyApp"
"https://example.com" "Website"
)
include(CPack)
WIX(MSI 安装程序)
# WIX 配置
set(CPACK_GENERATOR "WIX")
# 基本信息
set(CPACK_WIX_PRODUCT_GUID "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE")
set(CPACK_WIX_UPGRADE_GUID "FFFFFFFF-GGGG-HHHH-IIII-JJJJJJJJJJJJ")
set(CPACK_WIX_PRODUCT_ICON "${CMAKE_SOURCE_DIR}/resources/icon.ico")
# 安装目录
set(CPACK_WIX_INSTALL_DIR_SCOPE "perMachine")
# UI 设置
set(CPACK_WIX_UI_BANNER "${CMAKE_SOURCE_DIR}/resources/banner.bmp")
set(CPACK_WIX_UI_DIALOG "${CMAKE_SOURCE_DIR}/resources/dialog.bmp")
include(CPack)
macOS 打包
DMG(磁盘镜像)
# DMG 配置
set(CPACK_GENERATOR "DragNDrop")
# 基本信息
set(CPACK_DMG_FORMAT "UDBZ") # 压缩格式
set(CPACK_DMG_VOLUME_NAME "MyApp")
# 背景图片
set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_SOURCE_DIR}/resources/background.png")
# 图标位置
set(CPACK_DMG_DS_STORE "${CMAKE_SOURCE_DIR}/resources/DS_Store")
include(CPack)
Bundle(应用程序包)
# 创建 macOS Bundle
add_executable(myapp MACOSX_BUNDLE src/main.cpp)
# 设置 Bundle 属性
set_target_properties(myapp PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/Info.plist.in"
MACOSX_BUNDLE_GUI_IDENTIFIER "com.mycompany.myapp"
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION}
MACOSX_BUNDLE_BUNDLE_NAME "MyApp"
MACOSX_BUNDLE_ICON_FILE "icon.icns"
)
# 安装 Bundle
install(TARGETS myapp
BUNDLE DESTINATION .
)
# 打包设置
set(CPACK_GENERATOR "Bundle")
set(CPACK_BUNDLE_NAME "MyApp")
set(CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/resources/icon.icns")
set(CPACK_BUNDLE_PLIST "${CMAKE_SOURCE_DIR}/Info.plist")
include(CPack)
组件化打包
定义组件
# 定义安装组件
install(TARGETS myapp
RUNTIME DESTINATION bin
COMPONENT Runtime
)
install(TARGETS mylib
LIBRARY DESTINATION lib
COMPONENT Development
)
install(FILES include/mylib.h
DESTINATION include
COMPONENT Development
)
install(DIRECTORY docs/
DESTINATION share/doc/myapp
COMPONENT Documentation
)
# 组件配置
set(CPACK_COMPONENTS_ALL Runtime Development Documentation)
set(CPACK_COMPONENT_Runtime_DISPLAY_NAME "Runtime")
set(CPACK_COMPONENT_Runtime_DESCRIPTION "Runtime libraries and executables")
set(CPACK_COMPONENT_Runtime_REQUIRED ON)
set(CPACK_COMPONENT_Development_DISPLAY_NAME "Development")
set(CPACK_COMPONENT_Development_DESCRIPTION "Headers and libraries for development")
set(CPACK_COMPONENT_Development_DEPENDS Runtime)
set(CPACK_COMPONENT_Documentation_DISPLAY_NAME "Documentation")
set(CPACK_COMPONENT_Documentation_DESCRIPTION "User documentation")
include(CPack)
组件组
# 定义组件组
set(CPACK_COMPONENT_RUNTIME_GROUP "Base")
set(CPACK_COMPONENT_DEVELOPMENT_GROUP "Development")
set(CPACK_COMPONENT_DOCUMENTATION_GROUP "Extras")
# 组配置
set(CPACK_COMPONENT_GROUP_BASE_DISPLAY_NAME "Base Installation")
set(CPACK_COMPONENT_GROUP_BASE_DESCRIPTION "Essential components")
set(CPACK_COMPONENT_GROUP_BASE_EXPANDED ON)
set(CPACK_COMPONENT_GROUP_DEVELOPMENT_DISPLAY_NAME "Development Files")
set(CPACK_COMPONENT_GROUP_DEVELOPMENT_DESCRIPTION "Files for developers")
set(CPACK_COMPONENT_GROUP_EXTRAS_DISPLAY_NAME "Extra Components")
set(CPACK_COMPONENT_GROUP_EXTRAS_DESCRIPTION "Optional components")
多配置打包
同时生成多种格式
# 同时生成多个格式
set(CPACK_GENERATOR "DEB;RPM;TGZ")
# 或者使用命令行
# cpack -G "DEB;RPM;TGZ"
条件化配置
# 根据平台选择打包格式
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
find_program(DPKG_FOUND dpkg)
if(DPKG_FOUND)
set(CPACK_GENERATOR "DEB")
else()
set(CPACK_GENERATOR "RPM")
endif()
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(CPACK_GENERATOR "NSIS")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(CPACK_GENERATOR "DragNDrop")
endif()
include(CPack)
完整示例
跨平台项目打包
cmake_minimum_required(VERSION 3.15)
project(MyApp VERSION 1.0.0 LANGUAGES CXX)
# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 可执行文件
add_executable(myapp src/main.cpp)
# 安装规则
install(TARGETS myapp
RUNTIME DESTINATION bin
COMPONENT Runtime
)
install(FILES README.md LICENSE
DESTINATION share/doc/myapp
COMPONENT Documentation
)
install(DIRECTORY config/
DESTINATION etc/myapp
COMPONENT Runtime
)
# CPack 通用配置
set(CPACK_PACKAGE_NAME "myapp")
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "My Application - A sample project")
set(CPACK_PACKAGE_VENDOR "MyCompany")
set(CPACK_PACKAGE_CONTACT "[email protected]")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md")
# 平台特定配置
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(CPACK_GENERATOR "DEB;RPM;TGZ")
# DEB 配置
set(CPACK_DEBIAN_PACKAGE_NAME "myapp")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "MyCompany <[email protected]>")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.17)")
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
# RPM 配置
set(CPACK_RPM_PACKAGE_NAME "myapp")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
set(CPACK_RPM_PACKAGE_GROUP "Applications/Utilities")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(CPACK_GENERATOR "NSIS;ZIP")
# NSIS 配置
set(CPACK_NSIS_DISPLAY_NAME "MyApp ${PROJECT_VERSION}")
set(CPACK_NSIS_MODIFY_PATH ON)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(CPACK_GENERATOR "DragNDrop;TGZ")
set(CPACK_DMG_VOLUME_NAME "MyApp")
endif()
# 组件配置
set(CPACK_COMPONENTS_ALL Runtime Documentation)
set(CPACK_COMPONENT_Runtime_REQUIRED ON)
set(CPACK_COMPONENT_Documentation_DISPLAY_NAME "Documentation")
include(CPack)
命令行使用
基本命令
# 生成默认格式的包
cpack
# 指定生成器
cpack -G DEB
cpack -G "DEB;RPM"
# 指定配置
cpack -C Release
# 指定输出目录
cpack -B ./packages
# 详细输出
cpack -V
# 打包特定组件
cpack -C Release -G DEB --component Runtime
使用预设
# 使用预设打包
cpack --preset myapp-deb
调试和验证
验证 DEB 包
# 查看包信息
dpkg-deb --info myapp-1.0.0-Linux.deb
# 解压包内容
dpkg-deb -x myapp-1.0.0-Linux.deb ./extracted
# 安装测试
sudo dpkg -i myapp-1.0.0-Linux.deb
验证 RPM 包
# 查看包信息
rpm -qip myapp-1.0.0-Linux.rpm
# 查看文件列表
rpm -qlp myapp-1.0.0-Linux.rpm
# 安装测试
sudo rpm -ivh myapp-1.0.0-Linux.rpm
查看 ZIP/TGZ 内容
# ZIP
unzip -l myapp-1.0.0-Linux.zip
# TGZ
tar -tvzf myapp-1.0.0-Linux.tar.gz
常见问题
问题 1:包中缺少文件
确保安装规则正确:
# 检查安装规则
install(TARGETS myapp RUNTIME DESTINATION bin)
install(FILES ${HEADERS} DESTINATION include)
问题 2:依赖关系不正确
手动指定依赖:
# DEB
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libstdc++6, libc6")
# RPM
set(CPACK_RPM_PACKAGE_REQUIRES "libstdc++, glibc")
问题 3:安装路径错误
检查安装前缀:
# 设置正确的安装前缀
set(CMAKE_INSTALL_PREFIX "/usr")
set(CPACK_PACKAGING_INSTALL_PREFIX "/usr")
小结
本章我们学习了:
- CPack 基础:基本配置和打包流程
- Linux 打包:DEB 和 RPM 包配置
- Windows 打包:NSIS 和 WIX 安装程序
- macOS 打包:DMG 和 Bundle
- 组件化打包:分离安装组件
- 调试和验证:验证打包结果
CPack 让软件分发变得简单,是 CMake 项目发布的重要组成部分。
练习
- 为一个简单项目创建 DEB 和 RPM 包
- 创建 Windows NSIS 安装程序
- 实现组件化安装,分离运行时和开发文件
- 添加自定义安装脚本(postinst、prerm)