第二章:CPack核心概念——生成器、包类型、组件与安装规则
好,咱们进入正题。CPack 这东西,说白了就是 CMake 的打包小弟。你负责编译,它负责把编译好的东西收拾整齐,装进一个包里。但想用好它,你得先搞懂四个核心概念:生成器、包类型、组件、安装规则。
这四个概念,我当年刚接触时也绕了一阵子。尤其是生成器和包类型,名字长得像,但干的活完全不同。咱们一个一个来拆。
2.1 生成器(Generator)——打包的“后端引擎”
生成器,就是 CPack 用来生成安装包的那个“后端”。它决定了最终产出什么格式的文件。比如 .tar.gz、.deb、.rpm、.dmg,这些都是不同生成器干的事。
我个人习惯把生成器分成两类:
- 平台原生生成器:比如 DEB(Debian/Ubuntu)、RPM(Red Hat/Fedora)、NSIS(Windows)、DragNDrop(macOS)。它们生成的包可以直接在对应系统上安装。
- 跨平台生成器:比如 TGZ、STGZ、ZIP。这些格式通用性强,但需要用户手动解压或运行脚本。
你可以在 CMakeLists.txt 里这样指定生成器:
set(CPACK_GENERATOR "TGZ;DEB")
嗯,这里要注意:生成器可以同时指定多个。CPack 会依次调用每个生成器,生成对应的包。我在项目中遇到过,同时生成 TGZ 和 DEB 包,方便不同用户使用。
cpack --help 查看列表。我经常这么干。
2.2 包类型(Package Type)——你最终拿到的是什么
包类型,其实就是生成器产出的“文件类型”。它和生成器是一一对应的。比如:
| 生成器 | 包类型 | 典型后缀 |
|---|---|---|
| TGZ | tar.gz 压缩包 | .tar.gz |
| DEB | Debian 软件包 | .deb |
| RPM | Red Hat 软件包 | .rpm |
| NSIS | Windows 安装程序 | .exe |
| DragNDrop | macOS 磁盘映像 | .dmg |
说白了,生成器是“怎么造”,包类型是“造出啥”。你想想看,如果你只指定了 TGZ 生成器,那最终用户拿到的就是一个 .tar.gz 文件。如果你指定了 DEB,那用户就能用 apt install 直接装。
我建议,在跨平台项目里,至少保留一个通用包类型(比如 TGZ),再根据目标平台添加原生包类型。这样兼容性最好。
2.3 组件(Component)——把安装内容分门别类
组件,是 CPack 里一个非常实用的概念。它允许你把安装内容分成多个逻辑单元。比如:
- Runtime:运行时库和可执行文件
- Development:头文件、静态库、CMake 配置文件
- Documentation:文档和示例
- Tests:测试用例和数据
为什么要分组件?因为用户可能只需要运行时,不需要开发文件。或者你只想发布一个轻量级的包给最终用户。
在 CMake 里,你可以用 COMPONENT 关键字来标记安装目标:
install(TARGETS mylib
LIBRARY DESTINATION lib
COMPONENT Runtime
)
install(FILES mylib.h
DESTINATION include
COMPONENT Development
)
然后,在 CPack 配置里,你可以指定打包哪些组件:
set(CPACK_COMPONENTS_ALL Runtime Development)
我曾经踩过一个坑:忘记设置 CPACK_COMPONENTS_ALL,结果 CPack 把所有组件都打包进去了,包体积大了三倍。嗯,从那以后我每次都会检查这个变量。
CPACK_COMPONENTS_ALL,CPack 会默认打包所有组件。这可能导致包体积失控。
2.4 安装规则(Install Rules)——打包的“地基”
安装规则,是 CPack 打包的基础。没有安装规则,CPack 根本不知道要打包什么。说白了,install() 命令就是告诉 CMake:哪些文件、装到哪个目录、属于哪个组件。
常见的安装规则有:
- 安装目标:
install(TARGETS ...) - 安装文件:
install(FILES ...) - 安装目录:
install(DIRECTORY ...) - 安装脚本:
install(SCRIPT ...)
举个例子,一个典型的安装规则长这样:
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
)
这里要注意 DESTINATION 的路径。它通常是相对于安装前缀的。默认安装前缀是 /usr/local,但你可以通过 CMAKE_INSTALL_PREFIX 修改。
我个人习惯在项目根目录的 CMakeLists.txt 里统一管理安装规则,而不是分散在各个子目录。这样维护起来方便,也容易发现遗漏。
2.5 它们如何协同工作?
咱们用一张图来理清关系:
流程很清楚:
- 你通过
install()定义安装规则,指定文件装到哪里、属于哪个组件。 - CPack 根据组件配置,筛选出要打包的内容。
- 生成器读取这些内容,按照指定格式生成安装包。
- 最终产出对应包类型的文件。
举个例子,假设你有一个库项目,你想同时发布 .tar.gz 和 .deb 包。你只需要:
- 定义好安装规则,把库文件、头文件、文档分别归入 Runtime、Development、Documentation 组件。
- 设置
CPACK_GENERATOR为TGZ;DEB。 - 设置
CPACK_COMPONENTS_ALL为Runtime;Development(文档单独打包)。
运行 cpack 后,你就会得到两个包:一个 .tar.gz,一个 .deb。每个包里都只包含 Runtime 和 Development 组件的内容。
CPACK_DEBIAN_PACKAGE_MAINTAINER,结果打包失败。这些元信息变量,一定要提前配好。
好了,这四个核心概念就讲到这里。下一章咱们会深入生成器的具体配置,包括如何为不同平台定制打包参数。到时候我会分享一些实际项目里的配置模板,保证你能直接拿来用。