15、CPack入门:CPack是什么?CPack的工作流程、支持的打包格式(ZIP/TGZ/DEB/RPM/NSIS)
说实话,很多用CMake的人,都只停留在「编译通过就行」的阶段。
项目写完了,怎么发给别人?
扔一堆源码让人家自己编译?还是手动压缩一下?
嗯,我早年就是这么干的。直到有一次,我给客户发了个zip包,里面少了个动态库,对方直接打电话过来骂了半小时……从那以后,我老老实实学起了CPack。
CPack是什么?
CPack是CMake官方自带的打包工具。它不是一个独立的软件,而是CMake的一部分。你装好CMake,CPack就有了。
它的核心作用就一句话:把编译好的产物,打包成各种格式的分发包。
说白了,你写了一个库或者一个工具,编译完了有一堆二进制文件、头文件、配置文件。CPack帮你把这些东西整理好,塞进一个zip、一个tar.gz、一个deb包,甚至一个Windows安装程序里。
核心理解:CMake负责「怎么编译」,CPack负责「怎么分发」。两者配合,一条命令从源码到安装包全部搞定。
CPack的工作流程
CPack的工作流程其实不复杂。我拆成三步来讲,你跟着走一遍就明白了。
第一步:在CMakeLists.txt里配置打包信息
你需要在项目的CMakeLists.txt里告诉CPack:项目叫什么、版本号多少、维护者是谁、许可证是什么。这些信息通过set()命令设置,变量名都有固定前缀CPACK_。
# 最基本的CPack配置
set(CPACK_PACKAGE_NAME "MyTool")
set(CPACK_PACKAGE_VERSION "1.2.3")
set(CPACK_PACKAGE_VENDOR "MyCompany")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A handy tool for doing things")
set(CPACK_PACKAGE_CONTACT "support@mycompany.com")
# 必须包含这个模块
include(CPack)
注意最后一行include(CPack)。没有这一行,CPack根本不会生效。我见过有人配了一大堆变量,忘了写这一句,然后跑来问我为什么打不了包……
第二步:指定要安装哪些文件
CPack打包的内容,来源于CMake的install()命令。你之前用install()指定了安装规则,CPack就照着这个规则去收集文件。
# 安装可执行文件
install(TARGETS mytool DESTINATION bin)
# 安装头文件
install(FILES mytool.h DESTINATION include)
# 安装配置文件
install(FILES mytool.conf DESTINATION etc)
这里有个坑:CPack只打包install()指定的内容。如果你忘了写install(),CPack会给你一个空包。我曾经在给一个开源库打deb包时,漏掉了动态库的install规则,结果打出来的deb只有几百字节……
第三步:运行CPack命令
配置好之后,在构建目录里运行:
# 先构建项目
cmake --build .
# 然后打包,默认生成当前平台最常用的格式
cpack
# 或者指定格式
cpack -G ZIP
cpack -G TGZ
cpack -G DEB
cpack -G RPM
cpack -G NSIS
就这么简单。一条命令,所有文件自动打包好。
我的习惯:在CI脚本里,我会同时生成ZIP和TGZ两种格式。ZIP给Windows用户,TGZ给Linux用户。这样不管对方用什么系统,都能直接解压使用。
CPack支持的打包格式
CPack支持的格式很多。我把最常用的几个列出来,你根据目标用户选就行。
| 格式名称 | CPack生成器 | 适用平台 | 典型场景 |
|---|---|---|---|
| ZIP | ZIP | 跨平台 | 通用压缩包,Windows用户最爱 |
| TGZ | TGZ | 跨平台 | 通用压缩包,Linux/macOS用户常用 |
| DEB | DEB | Debian/Ubuntu | Linux发行版软件包,支持依赖管理 |
| RPM | RPM | Red Hat/Fedora/CentOS | Linux发行版软件包,支持依赖管理 |
| NSIS | NSIS | Windows | Windows安装程序,带图形界面向导 |
| DMG | DragNDrop | macOS | macOS磁盘映像,拖拽安装 |
ZIP和TGZ:最通用的格式
这两种格式不需要任何额外工具。CPack直接用zlib库就能生成。你想想看,用户拿到压缩包,解压就能用,多方便。
我个人建议:如果你不确定用户用什么系统,优先打ZIP包。Windows和Linux都能解压ZIP,兼容性最好。
DEB和RPM:Linux发行版的标准格式
这两种格式需要系统上安装对应的打包工具。DEB需要dpkg-deb,RPM需要rpmbuild。
为什么要用DEB/RPM?因为它们支持依赖管理。你的程序可能依赖libssl、libcurl之类的系统库。用DEB包的话,用户安装时系统会自动检查并安装这些依赖。这一点,ZIP和TGZ做不到。
注意:打DEB包时,记得设置CPACK_DEBIAN_PACKAGE_DEPENDS变量。我曾经漏掉了一个依赖,结果用户装完包运行时报错说找不到动态库……那场面,挺尴尬的。
# DEB包依赖配置示例
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libssl-dev (>= 1.1), libcurl4 (>= 7.58)")
NSIS:Windows安装程序
NSIS(Nullsoft Scriptable Install System)是Windows上最流行的安装程序制作工具之一。CPack可以自动生成NSIS脚本并调用NSIS编译器生成.exe安装包。
NSIS包的好处是:用户双击安装,有图形界面,可以选择安装路径、创建桌面快捷方式、添加环境变量。对于企业级软件分发,这是标配。
# NSIS配置示例
set(CPACK_NSIS_DISPLAY_NAME "MyTool 1.2.3")
set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
set(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\MyTool.lnk' '$INSTDIR\\\\bin\\\\mytool.exe'")
嗯,这里要注意:NSIS本身需要单独安装。CPack只是帮你生成脚本,真正的编译工作还是交给NSIS工具链完成的。
一张图看懂CPack
下面这张图展示了CPack在整个构建流程中的位置,以及它如何把不同格式的安装包输出给最终用户。
如何选择打包格式?
这个问题没有标准答案。我根据经验给你几个建议:
- 给开发者用的工具库:打ZIP或TGZ包。开发者不介意手动解压,他们更关心能不能快速拿到头文件和库文件。
- 给普通用户用的桌面软件:Windows上打NSIS包,macOS上打DMG包。用户习惯双击安装,别让他们碰命令行。
- 给服务器部署用的服务:打DEB或RPM包。运维人员需要依赖管理和版本控制,apt/yum安装是标准流程。
- 跨平台分发:同时打ZIP和TGZ。我在GitHub Release里经常这么干,一个项目挂两个包,用户自己选。
一个小技巧:你可以用cpack -G "ZIP;TGZ;DEB"一次生成多种格式。CPack会依次调用各个生成器,省得你一条一条敲命令。
避坑指南
最后分享几个我踩过的坑:
- 忘了include(CPack):这是最基础的错误。没有这一行,你配再多变量都没用。
- install()路径写错:CPack打包时,文件路径是相对于
CMAKE_INSTALL_PREFIX的。如果你写死了绝对路径,换台机器就废了。 - DEB包版本号格式:Debian的版本号有严格规范,不能有连字符以外的特殊符号。我试过在版本号里加了下划线,结果dpkg直接报错。
- NSIS需要单独安装:CPack不会帮你装NSIS。如果你在CI环境里打NSIS包,记得先装好NSIS工具链。
CPack入门其实不难。你只要记住:先配install(),再配CPACK变量,最后跑cpack。这三步走完,你的项目就有了专业的分发包。
公众号:蓝海资料掘金营,微信deep3321