4. CPack生成器详解(上):ZIP生成器、TGZ生成器、STGZ生成器(自解压压缩包)
好,咱们今天来聊聊CPack生成器里最常用的三个家伙:ZIP、TGZ和STGZ。说实话,这三个生成器是我在实际项目中打交道最多的。为什么?因为跨平台分发软件,压缩包是最朴素、最通用的方式。你想想看,不管用户用的是Windows、macOS还是Linux,总得有个办法把编译好的二进制文件、库文件、配置文件一股脑儿塞给人家吧?
我个人习惯把这三个生成器归为一类——「压缩包派」。它们本质上都是把安装产物打包成一个文件,区别只在于压缩算法和自解压能力。嗯,咱们一个一个来看。
4.1 ZIP生成器:跨平台的「万金油」
ZIP生成器,说白了就是把你整个安装目录压缩成一个.zip文件。这东西的好处不用我多说——几乎所有的操作系统都原生支持解压ZIP。Windows资源管理器直接双击打开,macOS自带归档工具,Linux也有unzip命令。
我在项目中遇到过最典型的场景:给Windows用户分发一个绿色版工具。用户下载后解压就能用,不需要安装,不需要管理员权限。省心。
配置起来也很简单,在CMakeLists.txt里加上这么几行:
set(CPACK_GENERATOR "ZIP")
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}-${CMAKE_SYSTEM_NAME}")
这里有个小细节要注意——CPACK_PACKAGE_FILE_NAME决定了最终压缩包的文件名。我建议你把操作系统名称加进去,不然用户拿到一个myapp-1.0.0.zip,根本不知道是给哪个平台用的。
4.2 TGZ生成器:Linux世界的「老大哥」
TGZ生成器,其实就是tar.gz。在Linux和macOS生态里,这玩意儿比ZIP更常见。为什么?因为tar格式能完美保留文件权限、符号链接、所有权信息。你想想看,一个Linux守护进程,安装后需要设置setuid位,或者需要创建软链接指向共享库——这些用ZIP就搞不定。
配置方式和ZIP几乎一样:
set(CPACK_GENERATOR "TGZ")
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}-${CMAKE_SYSTEM_NAME}")
但这里有个坑——TGZ生成器默认使用gzip压缩。如果你的项目特别大(比如几百兆的二进制文件),压缩时间会很长。我个人建议,如果对压缩率要求不高,可以换成STGZ或者干脆用ZIP。TGZ的压缩率虽然高,但打包速度确实慢一些。
我记得有一次给客户交付一个嵌入式Linux的SDK,整个包有1.2GB。用TGZ打包花了将近5分钟,压缩后只有400MB。客户那边解压又花了3分钟。后来我换成了ZIP,打包时间缩短到40秒,压缩后500MB。客户反馈说解压也快多了。嗯,有时候压缩率不是唯一指标。
4.3 STGZ生成器:自解压的「黑科技」
STGZ,全称是Self-Extracting TGZ。说白了,就是把一个shell脚本和一个TGZ压缩包粘在一起。用户拿到这个文件后,直接chmod +x然后运行,就能自动解压并执行安装脚本。
这东西在Linux世界里特别有用。你想想看,有些用户可能连tar -xzf都懒得敲,或者干脆不知道这个命令。给一个.run文件,双击就能装,多省事。
配置STGZ生成器:
set(CPACK_GENERATOR "STGZ")
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}-linux-x64")
set(CPACK_STGZ_SCRIPT "${CMAKE_SOURCE_DIR}/cmake/stgz_install.sh")
这里CPACK_STGZ_SCRIPT指向一个自定义的安装脚本。这个脚本会在解压完成后执行,你可以用它来做一些额外的事情,比如创建用户、设置环境变量、注册服务等等。
我曾经给一个内部工具做过STGZ包。那个工具需要把二进制文件放到/opt/myapp,还要在/etc/profile.d里加一个环境变量脚本。用STGZ自解压+自定义脚本,一条命令搞定所有事情。运维同事反馈说「这玩意儿真香」。
- ZIP:跨平台通用,Windows友好,不保留Unix权限
- TGZ:Linux/macOS原生,保留权限和符号链接,压缩率高
- STGZ:自解压,用户体验好,适合给非技术用户分发
4.4 如何选择?我的经验法则
说了这么多,到底该用哪个?我根据自己的项目经验,整理了一个简单的选择矩阵:
| 场景 | 推荐生成器 | 理由 |
|---|---|---|
| Windows桌面应用分发 | ZIP | 用户双击就能解压,不需要额外工具 |
| Linux服务器软件包 | TGZ | 保留权限,适合root用户安装 |
| 给非技术用户的分发 | STGZ | 一条命令安装,体验最好 |
| 跨平台SDK | ZIP + TGZ | 同时提供两种格式,覆盖所有用户 |
| 大型项目(>500MB) | ZIP | 打包和解压速度更快 |
你可能会问:「能不能同时生成多个格式?」当然可以。CPack支持一次生成多种格式的包:
set(CPACK_GENERATOR "ZIP;TGZ;STGZ")
这样执行cpack命令后,你会得到三个包:.zip、.tar.gz和.sh。用户喜欢哪个就用哪个。
${PROJECT_NAME}-${PROJECT_VERSION}-${CPACK_GENERATOR}。这样文件名就变成了myapp-1.0.0-ZIP.zip和myapp-1.0.0-TGZ.tar.gz,一目了然。
4.5 一个完整的例子
最后,给你看一个我实际项目中用过的CMakeLists.txt片段。这个项目是一个跨平台的命令行工具,需要同时提供ZIP和TGZ包:
# 设置版本号
set(PROJECT_VERSION_MAJOR 2)
set(PROJECT_VERSION_MINOR 1)
set(PROJECT_VERSION_PATCH 0)
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
# 安装目标
install(TARGETS mytool DESTINATION bin)
install(FILES README.md LICENSE DESTINATION share/doc/mytool)
# CPack配置
set(CPACK_PACKAGE_NAME "mytool")
set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
set(CPACK_PACKAGE_VENDOR "My Company")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A handy command-line tool")
# 生成器选择
if(WIN32)
set(CPACK_GENERATOR "ZIP")
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-win64")
elseif(APPLE)
set(CPACK_GENERATOR "TGZ")
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-macos")
else()
set(CPACK_GENERATOR "TGZ;STGZ")
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-linux-x64")
set(CPACK_STGZ_SCRIPT "${CMAKE_SOURCE_DIR}/cmake/post_install.sh")
endif()
include(CPack)
你看,这里根据不同的操作系统选择了不同的生成器。Windows用户拿到ZIP包,macOS用户拿到TGZ包,Linux用户则同时有TGZ和STGZ两种选择。嗯,这就是我所谓的「因地制宜」。
好了,关于ZIP、TGZ和STGZ生成器,咱们就聊到这里。下一章我会继续讲剩下的几个生成器——NSIS、DEB和RPM。到时候咱们再聊聊安装包和系统包管理器的那些事儿。