23、CPack打包类型:生成器详解(ZIP、TGZ、DEB、RPM、NSIS、DMG)、选择打包格式
打包这件事,说白了就是把你编译好的程序、库文件、配置文件、文档等一堆东西,按照目标平台的规范整理成一个安装包。CPack 之所以强大,就是因为它支持多种打包格式——也就是所谓的「生成器」。你只需要写一份 CMakeLists.txt,就能同时产出 .zip、.deb、.rpm、甚至 macOS 的 .dmg。
我个人习惯把生成器分成三类:通用归档类、Linux 包管理类、平台安装向导类。下面我一个一个讲。
通用归档生成器:ZIP、TGZ、STGZ
这类生成器不依赖特定操作系统,说白了就是压缩包。适合跨平台分发,或者给用户「解压即用」的场景。
| 生成器名称 | 输出格式 | 适用场景 |
|---|---|---|
| ZIP | .zip | Windows / 跨平台通用 |
| TGZ | .tar.gz | Linux / macOS 通用 |
| STGZ | .sh (自解压) | Linux 下无需 root 权限安装 |
我在项目中遇到过这样一个坑:用 TGZ 打包时,文件权限会丢失。尤其是可执行文件,解压后没了 x 权限,用户跑不起来。后来我加了一行 INSTALL(TARGETS ... PERMISSIONS OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE) 才搞定。
set(CPACK_GENERATOR "ZIP;TGZ")
set(CPACK_SOURCE_GENERATOR "TGZ")
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}-${CMAKE_SYSTEM_NAME}")
嗯,这里要注意:CPACK_PACKAGE_FILE_NAME 决定了压缩包的文件名。我建议把系统名加进去,比如 myapp-1.0.0-Linux.tar.gz,用户一看就知道该下载哪个。
Linux 包管理生成器:DEB、RPM
如果你要给 Ubuntu 用户分发软件,那 .deb 是首选。给 Fedora 或 CentOS 用户,.rpm 更合适。这两个生成器会生成符合各自包管理规范的安装包,支持依赖声明、预安装脚本、后安装脚本等高级功能。
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "yourname@example.com")
set(CPACK_DEBIAN_PACKAGE_SECTION "devel")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libssl-dev (>= 1.1), zlib1g-dev")
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/debian/postinst")
我曾经在给一个内部工具打包时,忘了设置 CPACK_DEBIAN_PACKAGE_DEPENDS,结果用户安装后运行时提示缺少 libssl。嗯,从那以后我每次都会用 dpkg -I 检查生成的 .deb 包的依赖信息。
RPM 的配置思路类似,但变量名不同:
set(CPACK_RPM_PACKAGE_RELEASE "1")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
set(CPACK_RPM_PACKAGE_GROUP "Development/Libraries")
set(CPACK_RPM_PACKAGE_REQUIRES "openssl >= 1.1, zlib")
1.0-beta,结果 rpmbuild 直接报错。改成 1.0~beta 才通过。
平台安装向导生成器:NSIS、DMG
NSIS 是 Windows 下的安装程序生成器。它会生成一个 .exe 安装向导,用户双击后一路 Next 就能装好。DMG 是 macOS 下的磁盘映像格式,用户拖拽 App 到 Applications 文件夹即可完成安装。
我个人觉得 NSIS 的配置稍微有点繁琐,但效果很好:
set(CPACK_NSIS_DISPLAY_NAME "MyApp")
set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES")
set(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\MyApp.lnk' '$INSTDIR\\\\bin\\\\myapp.exe'")
set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '$INSTDIR\\\\bin\\\\register.dll'")
DMG 打包相对简单,但要注意背景图和卷标:
set(CPACK_DMG_VOLUME_NAME "MyApp-1.0.0")
set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_SOURCE_DIR}/dmg_background.png")
set(CPACK_DMG_DS_STORE "${CMAKE_SOURCE_DIR}/DS_Store_template")
如何选择打包格式?
你想想看,如果你的用户群体是 Linux 开发者,那 TGZ 和 DEB 都要提供。如果是 Windows 普通用户,NSIS 是必须的。macOS 用户则习惯 DMG。
我一般这样决策:
- 跨平台命令行工具:ZIP + TGZ,用户自己解压放到 PATH 里
- Linux 库文件:DEB + RPM,方便系统包管理
- Windows 桌面应用:NSIS,带安装向导和开始菜单快捷方式
- macOS 应用:DMG,符合 Mac 用户的使用习惯
- 内部测试:STGZ,一行命令就装好了,不需要 root 权限
你可以同时指定多个生成器:
set(CPACK_GENERATOR "ZIP;TGZ;DEB;RPM")
if(WIN32)
set(CPACK_GENERATOR "NSIS")
elseif(APPLE)
set(CPACK_GENERATOR "DMG")
endif()
这样在 Linux 上执行 cpack 就会同时生成 .zip、.tar.gz、.deb、.rpm 四个包。在 Windows 上只生成 NSIS 安装包,macOS 上只生成 DMG。
cpack -G "TGZ" 可以临时指定生成器,覆盖 CMakeLists.txt 里的默认设置。调试时我经常这么干。
知识体系结构图
最后说一句:不要试图一次性支持所有生成器。我刚开始做打包时,恨不得把十几种格式全列上,结果配置了三天还没调通。后来我学乖了——先搞定 TGZ,再逐个添加 DEB、RPM、NSIS。每加一个,就用对应的平台测试一遍。稳扎稳打,比什么都强。
公众号:蓝海资料掘金营,微信 deep3321