CPack入门:CPack是什么、CPack与CMake的关系、CPack安装与基本配置
说实话,很多做C++项目的朋友,CMake用得挺溜,但一到「把项目打包成安装包」这一步就卡住了。我自己早年也踩过这个坑——项目编译通过了,结果交付的时候,要么手动拷贝文件,要么写一堆乱七八糟的脚本。后来接触了CPack,才发现原来CMake生态里早就给你准备好了打包工具。
这一章,我们就来聊聊CPack。嗯,别把它想得太复杂,它其实就是CMake的「亲兄弟」,专门负责把编译好的东西打包成你想要的格式。
CPack是什么?
CPack,全称是CMake Packager。说白了,它是一个跨平台的打包工具。你写好了CMakeLists.txt,用CMake配置、构建完项目,CPack就能帮你把生成的可执行文件、库文件、配置文件、文档等等,一股脑打包成一个安装包。
它支持什么格式?我列一下你感受感受:
- Windows:NSIS、WiX、ZIP
- macOS:DMG、Bundle、PackageMaker
- Linux:DEB、RPM、TGZ、STGZ
- 跨平台:ZIP、TAR.GZ、TAR.BZ2
你看,几乎覆盖了主流平台。我在项目中遇到过最典型的场景:同一个项目,要给Windows用户发exe安装包,给Ubuntu用户发deb包,给CentOS用户发rpm包。如果没有CPack,你得写三套打包脚本。有了它,一套CMakeLists.txt搞定。
核心要点:CPack不是构建工具,它是打包工具。它不编译代码,它只负责把编译好的产物整理成安装包。
CPack与CMake的关系
这个问题很多人问过我。CPack和CMake到底是什么关系?
其实很简单。CMake负责「怎么编译」,CPack负责「怎么打包」。它们共用同一个CMakeLists.txt里的信息。你在CMakeLists.txt里定义的安装规则(install命令),CPack直接拿来用。
我画了一张图,帮你理清这个关系:
从图上你能看出来,CMakeLists.txt是核心。你写好install规则,CMake用它来构建,CPack用它来打包。两者配合得天衣无缝。
小提示:如果你已经在CMakeLists.txt里写好了install命令,那CPack的配置工作其实已经完成了一半。CPack只是在此基础上加了一些打包相关的参数。
CPack的安装
安装CPack?其实你大概率已经装好了。因为CPack是CMake的一部分。你装CMake的时候,CPack就跟着一起装进来了。
验证一下很简单,打开终端敲:
cpack --version
如果看到版本号输出,说明已经装好了。我见过有人折腾半天去单独下载CPack,其实完全没必要。
不同平台的安装方式:
| 平台 | 安装方式 | 备注 |
|---|---|---|
| Ubuntu/Debian | sudo apt install cmake |
CPack 自动包含 |
| CentOS/RHEL | sudo yum install cmake |
CPack 自动包含 |
| macOS | brew install cmake |
CPack 自动包含 |
| Windows | 下载CMake安装包 | 勾选「Add to PATH」 |
我个人习惯在Linux上开发,所以经常用apt安装。装完之后,cpack命令就能直接用了。
CPack的基本配置
配置CPack,主要有两种方式:
- 在CMakeLists.txt里直接写:用set命令设置CPack相关的变量。
- 单独写CPackConfig.cmake文件:把打包配置独立出来。
我建议初学者先用第一种方式,简单直接。等项目复杂了,再考虑拆分文件。
来看一个最基础的例子。假设你有一个简单的项目,编译后生成一个可执行文件myapp。你想把它打包成ZIP和DEB两种格式。
CMakeLists.txt的内容:
cmake_minimum_required(VERSION 3.15)
project(MyApp VERSION 1.0.0)
add_executable(myapp main.cpp)
# 安装规则:把myapp安装到bin目录
install(TARGETS myapp DESTINATION bin)
# ---------- CPack 配置 ----------
set(CPACK_GENERATOR "ZIP;DEB")
set(CPACK_PACKAGE_NAME "MyApp")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A simple example application")
set(CPACK_PACKAGE_VENDOR "Your Company")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "your@email.com")
然后执行:
mkdir build && cd build
cmake ..
make
cpack
你会看到生成了两个文件:MyApp-1.0.0-Linux.zip 和 MyApp-1.0.0-Linux.deb。
注意:CPack默认的包名格式是 <PackageName>-<Version>-<Platform>.<ext>。你可以通过设置 CPACK_PACKAGE_FILE_NAME 来自定义。
常用CPack变量一览
这里我列几个最常用的变量,你记一下:
| 变量名 | 作用 | 示例值 |
|---|---|---|
| CPACK_GENERATOR | 指定打包格式 | ZIP;DEB;RPM;NSIS |
| CPACK_PACKAGE_NAME | 包名 | MyApp |
| CPACK_PACKAGE_VERSION | 版本号 | 1.0.0 |
| CPACK_PACKAGE_VENDOR | 供应商信息 | Your Company |
| CPACK_PACKAGE_CONTACT | 联系方式 | your@email.com |
| CPACK_PACKAGE_DESCRIPTION_SUMMARY | 简短描述 | A useful tool |
| CPACK_PACKAGE_FILE_NAME | 自定义输出文件名 | MyApp-1.0.0 |
| CPACK_OUTPUT_FILE_PREFIX | 输出目录 | ./packages |
避坑指南:我曾经在配置DEB包时,忘了设置 CPACK_DEBIAN_PACKAGE_MAINTAINER,结果生成的deb包死活装不上。后来查了半天,才发现这个变量是必填的。嗯,DEB包规范要求维护者信息不能为空。
一个完整的入门示例
我们来写一个稍微完整点的例子。假设项目结构如下:
myapp/
├── CMakeLists.txt
├── src/
│ └── main.cpp
├── include/
│ └── myapp.h
└── config/
└── myapp.conf
CMakeLists.txt:
cmake_minimum_required(VERSION 3.15)
project(MyApp VERSION 2.0.0 LANGUAGES CXX)
# 添加可执行文件
add_executable(myapp src/main.cpp)
target_include_directories(myapp PRIVATE include)
# 安装可执行文件
install(TARGETS myapp DESTINATION bin)
# 安装配置文件
install(FILES config/myapp.conf DESTINATION etc/myapp)
# 安装头文件(供其他项目使用)
install(DIRECTORY include/ DESTINATION include/myapp)
# ---------- CPack 配置 ----------
set(CPACK_GENERATOR "ZIP;DEB;RPM")
set(CPACK_PACKAGE_NAME "MyApp")
set(CPACK_PACKAGE_VERSION "2.0.0")
set(CPACK_PACKAGE_VENDOR "MyCompany")
set(CPACK_PACKAGE_CONTACT "support@mycompany.com")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "MyApp - a demonstration application")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
# DEB 专属配置
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "support@mycompany.com")
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
# RPM 专属配置
set(CPACK_RPM_PACKAGE_GROUP "Applications/System")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
执行打包:
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr
make
cpack
你会看到生成了三个包:ZIP、DEB、RPM。每个包里的文件结构都是按照你定义的install规则来的。
小技巧:设置 CMAKE_INSTALL_PREFIX 很重要。它决定了安装包里的文件路径前缀。比如你设成 /usr,那可执行文件就会在 /usr/bin 下,配置文件在 /usr/etc/myapp 下。这个路径会直接反映到安装包里。
CPack的工作流程
最后,我总结一下CPack的完整工作流程。你心里有个数:
- 编写CMakeLists.txt:定义项目、构建目标、安装规则。
- 配置CPack变量:指定打包格式、包信息等。
- 构建项目:cmake + make,生成可执行文件和库。
- 运行cpack:CPack读取安装规则和配置,生成安装包。
说白了,你只需要关注第1步和第2步。第3步和第4步都是机械操作。这也是CPack的魅力所在——把重复劳动交给工具,你只负责定义规则。
好了,这一章的内容就到这里。CPack入门其实不难,关键是理解它和CMake的协作关系,以及掌握那几个核心变量。下一章我们会深入聊聊CPack的生成器,看看不同平台下的打包格式有什么门道。