4、CPack生成器详解(下):DEB生成器(Debian包)、RPM生成器(Red Hat包)、NSIS生成器(Windows安装包)、DragNDrop生成器(macOS DMG)
好,咱们接着聊。上一节我们把几个跨平台生成器捋了一遍,这一节专门针对各平台的原生打包格式。说白了,就是让用户用他们最熟悉的方式安装你的软件。
我个人习惯是:面向哪个平台,就用哪个平台的原生包。Linux 用户用 apt 或 yum,Windows 用户双击 exe,macOS 用户拖拽 .app 到 Applications。这样用户体验最好,也最省心。
4.1 DEB 生成器:Debian/Ubuntu 的标配
DEB 生成器,就是用来生成 .deb 包的。Ubuntu、Debian、Deepin 这些发行版都用它。
配置起来其实不复杂。核心就几个变量:
set(CPACK_DEBIAN_PACKAGE_NAME "myapp")
set(CPACK_DEBIAN_PACKAGE_VERSION "1.0.0")
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "yourname@example.com")
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "A useful tool")
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
嗯,这里要注意:依赖关系是 DEB 包的核心。你想想看,用户装完你的软件,结果运行时报错说缺库,那体验多糟糕。
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libssl1.1 (>= 1.1.1), libc6 (>= 2.31)")
我曾经在一个项目中,忘了写 libssl 的依赖。结果用户装完,一运行就崩。排查了半天才发现是 OpenSSL 版本不对。从那以后,我每次打包前都会先跑一遍 ldd 检查动态库依赖。
ldd your_binary 查看所有依赖的共享库,然后对照着写 CPACK_DEBIAN_PACKAGE_DEPENDS。这样基本不会漏。
还有一点,DEB 包支持安装前后脚本。比如安装后自动启动服务,卸载前备份配置。用这两个变量:
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/debian/postinst;${CMAKE_SOURCE_DIR}/debian/prerm")
postinst 是安装后执行,prerm 是卸载前执行。脚本里可以写 systemctl 命令,或者更新数据库之类的操作。
4.2 RPM 生成器:Red Hat 家族的标配
RPM 生成器,对应的是 CentOS、Fedora、openSUSE 这些发行版。配置思路和 DEB 很像,但变量名不同。
set(CPACK_RPM_PACKAGE_NAME "myapp")
set(CPACK_RPM_PACKAGE_VERSION "1.0.0")
set(CPACK_RPM_PACKAGE_RELEASE "1")
set(CPACK_RPM_PACKAGE_ARCHITECTURE "x86_64")
set(CPACK_RPM_PACKAGE_VENDOR "My Company")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
set(CPACK_RPM_PACKAGE_SUMMARY "A useful tool")
set(CPACK_RPM_PACKAGE_DESCRIPTION "A useful tool for doing things")
依赖写法也类似:
set(CPACK_RPM_PACKAGE_REQUIRES "openssl >= 1.1.1, glibc >= 2.31")
我建议你注意一下 RPM 的 Group 字段。虽然现在很多包管理器不强制了,但写对了能让用户在图形界面里找到你的软件。
set(CPACK_RPM_PACKAGE_GROUP "Applications/System")
RPM 还有一个 DEB 没有的特性:条件依赖。比如「如果系统里有 A,就依赖 B,否则依赖 C」。这个用 CPACK_RPM_PACKAGE_REQUIRES_PRE 和 CPACK_RPM_PACKAGE_REQUIRES_POST 可以实现。
1.0.0-beta,但 RPM 可能报错。建议用 1.0.0~beta 这种格式,RPM 能正确识别为比正式版低。
4.3 NSIS 生成器:Windows 安装包
NSIS 生成器,用来生成 Windows 上的 .exe 安装包。这是 Windows 用户最熟悉的安装方式——双击、下一步、下一步、完成。
配置 NSIS 需要先安装 NSIS 工具链。CMake 只是生成脚本,真正打包还得靠 NSIS 编译器。
set(CPACK_NSIS_DISPLAY_NAME "MyApp")
set(CPACK_NSIS_PACKAGE_NAME "MyApp")
set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
set(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '$SMPROGRAMS\\\\MyApp.lnk' '$INSTDIR\\\\bin\\\\myapp.exe'")
我个人觉得 NSIS 最麻烦的是创建快捷方式。Windows 的路径里有很多反斜杠,在 CMake 里写起来很别扭。我建议你把快捷方式逻辑单独写到一个 .nsh 文件里,然后用 CPACK_NSIS_EXTRA_INSTALL_COMMANDS 引入。
set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "!include '${CMAKE_SOURCE_DIR}/nsis/shortcuts.nsh'")
还有一个坑:卸载程序。NSIS 默认会生成卸载程序,但如果你不配置,它可能不会删除所有文件。我建议你显式指定要删除的目录:
set(CPACK_NSIS_DELETE_FILES "*.log;*.tmp")
set(CPACK_NSIS_DELETE_DIRECTORIES "$INSTDIR\\\\logs;$INSTDIR\\\\cache")
我曾经遇到一个用户,卸载后残留了配置文件。下次重装时,旧配置和新版本不兼容,导致软件崩溃。后来我加了卸载时删除配置目录的逻辑,问题才解决。
CPACK_NSIS_INSTALL_TYPES 配置。
4.4 DragNDrop 生成器:macOS DMG
最后是 macOS 的 DMG 生成器。macOS 用户习惯把 .app 拖到 Applications 文件夹里。DMG 就是这种体验的载体。
配置 DMG 生成器相对简单:
set(CPACK_DMG_VOLUME_NAME "MyApp")
set(CPACK_DMG_FORMAT "UDBZ")
set(CPACK_DMG_DS_STORE "${CMAKE_SOURCE_DIR}/dmg/DS_Store")
set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_SOURCE_DIR}/dmg/background.png")
嗯,这里有个关键点:DS_Store 文件。这个文件决定了 DMG 窗口打开时的布局——图标位置、窗口大小、背景图。我建议你在 macOS 上手动创建一个 DMG,调整好布局,然后把隐藏的 .DS_Store 文件复制出来,放到项目里。
为什么这么做?因为 CMake 生成的默认布局很难看。图标乱糟糟的,用户第一印象就不好。
我记得有一次,我给一个开源项目做 macOS 包。默认的 DMG 打开后,图标挤在左上角,背景是纯白的。用户反馈说「这看起来像业余作品」。后来我花了一小时调整布局,加了背景图,体验瞬间提升。
DMG 还支持许可证和欢迎页面:
set(CPACK_DMG_SLA_USE_RESOURCE_FILE_LICENSE ON)
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
set(CPACK_DMG_WELCOME_TEXT "Welcome to MyApp!")
不过说实话,macOS 用户不太喜欢看许可证。我一般只放一个简短的欢迎文字,把许可证放在应用内部。
4.5 各生成器对比总结
最后,我用一个表格总结一下这四种生成器的关键差异。方便你快速查阅:
| 特性 | DEB | RPM | NSIS | DragNDrop |
|---|---|---|---|---|
| 目标平台 | Debian/Ubuntu | Red Hat/Fedora | Windows | macOS |
| 输出格式 | .deb | .rpm | .exe | .dmg |
| 依赖管理 | apt 自动处理 | yum/dnf 自动处理 | 需手动打包 | 需手动打包 |
| 安装脚本 | postinst/prerm | %post/%preun | NSIS 脚本 | 不支持 |
| 跨平台打包 | 可跨平台 | 可跨平台 | 可跨平台 | 仅 macOS |
| 用户友好度 | 中(命令行) | 中(命令行) | 高(图形界面) | 高(拖拽) |
选哪个生成器,其实取决于你的目标用户。如果是服务器软件,DEB 和 RPM 是首选。如果是桌面应用,NSIS 和 DMG 体验更好。
我个人建议:如果条件允许,四种都生成。用 CMake 的 -G 参数切换生成器,一次配置,到处打包。用户拿到手就能装,这才是专业的态度。
好,这一节就到这里。下一节我们聊聊 CPack 的安装规则和组件打包,那是真正让打包变得灵活的关键。