第二章:生成器详解——CPack支持的生成器与选择策略

说到CPack,最核心的就是生成器了。我刚开始接触CPack时,面对一堆生成器选项也是一头雾水。NSIS、DEB、RPM、TGZ……每个都代表不同的打包格式,背后是不同的平台生态。今天我就把这块掰开揉碎了讲清楚。

2.1 CPack支持的主流生成器

CPack支持的生成器其实挺多的,但真正常用的就那么几个。我按平台分类给大家梳理一下:

生成器名称 目标平台 输出格式 典型场景
NSIS Windows .exe 安装包 Windows桌面应用分发
DEB Debian/Ubuntu .deb 包 Linux发行版软件仓库
RPM Red Hat/Fedora/CentOS .rpm 包 企业级Linux部署
TGZ 跨平台 .tar.gz 压缩包 源码分发、通用二进制包
ZIP 跨平台 .zip 压缩包 Windows用户友好分发
DragNDrop macOS .dmg 镜像 macOS应用分发
WIX Windows .msi 安装包 企业级Windows部署

嗯,这里要注意——TGZ和ZIP其实是最简单的,它们只是把文件打包压缩,没有安装逻辑。而NSIS、DEB、RPM这些,是真正的安装包,能处理依赖、注册表、服务安装等复杂操作。

2.2 如何选择生成器?

这个问题我经常被问到。说白了,选择生成器就三个原则:

  1. 看目标平台——Windows用NSIS或WIX,Linux用DEB或RPM,macOS用DragNDrop
  2. 看用户习惯——企业用户喜欢.msi,个人用户习惯.exe,开发者喜欢.tar.gz
  3. 看维护成本——TGZ最省事,但功能也最弱

我在项目中遇到过这样的情况:一个跨平台工具链,Windows用户要求双击安装,Linux用户要求apt/yum直接装,macOS用户要拖拽安装。最后我用了CPack的多生成器配置,一次构建打出三种包。你想想看,这比手动维护三套打包脚本省了多少事?

我的建议:如果你只维护一个平台,就选那个平台最主流的格式。如果你做跨平台分发,用CPack的CPACK_GENERATOR变量一次指定多个生成器。

2.3 生成器的配置参数

每个生成器都有自己的专属配置。我挑几个最常用的讲讲:

2.3.1 NSIS 配置

NSIS是我在Windows上用得最多的。它的配置参数挺多,但核心就这几个:

# 设置NSIS生成器
set(CPACK_GENERATOR "NSIS")

# 安装包基本信息
set(CPACK_PACKAGE_NAME "MyApp")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_PACKAGE_VENDOR "MyCompany")

# NSIS专属配置
set(CPACK_NSIS_DISPLAY_NAME "我的应用 1.0")
set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
set(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '$SMPROGRAMS\\MyApp\\Uninstall.lnk' '$INSTDIR\\uninstall.exe'")
set(CPACK_NSIS_MODIFY_PATH ON)  # 添加到PATH环境变量

我曾经踩过一个坑:CPACK_NSIS_INSTALL_ROOT没设置,结果默认装到了32位目录,64位应用跑不起来。后来我强制指定$PROGRAMFILES64才解决。

2.3.2 DEB 配置

DEB包在Ubuntu上用得最多。配置时要注意依赖关系:

set(CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_NAME "myapp")
set(CPACK_DEBIAN_PACKAGE_VERSION "1.0.0")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "developer@mycompany.com")
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "我的应用描述")

# 依赖管理
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.31), libssl1.1 (>= 1.1.1)")

# 架构
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64")

小技巧:DEB包的依赖版本号一定要写对。我见过太多因为依赖版本写得太宽松或太严格导致的安装失败。建议用dpkg -l查看目标系统上的实际版本。

2.3.3 RPM 配置

RPM和DEB类似,但语法不同:

set(CPACK_GENERATOR "RPM")
set(CPACK_RPM_PACKAGE_NAME "myapp")
set(CPACK_RPM_PACKAGE_VERSION "1.0.0")
set(CPACK_RPM_PACKAGE_RELEASE "1")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
set(CPACK_RPM_PACKAGE_GROUP "Applications/System")

# RPM依赖
set(CPACK_RPM_PACKAGE_REQUIRES "glibc >= 2.31, openssl >= 1.1.1")

2.3.4 TGZ 配置

TGZ最简单,但也有一些参数可以调:

set(CPACK_GENERATOR "TGZ")
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_PROCESSOR}")
set(CPACK_TGZ_COMPRESSION_TYPE "gzip")  # 可选: gzip, bzip2, xz

2.4 生成器选择流程图

为了让大家更直观地理解选择逻辑,我画了个流程图:

选择生成器 目标平台? Windows NSIS/WIX Linux DEB/RPM macOS DragNDrop 跨平台通用 TGZ/ZIP 生成安装包

2.5 多生成器配置实战

在实际项目中,我经常需要一次构建打出多个平台的包。CPack支持这个场景:

# 同时生成DEB和TGZ
set(CPACK_GENERATOR "DEB;TGZ")

# 也可以根据平台条件选择
if(WIN32)
  set(CPACK_GENERATOR "NSIS")
elseif(APPLE)
  set(CPACK_GENERATOR "DragNDrop")
elseif(UNIX)
  set(CPACK_GENERATOR "DEB")
endif()

注意:多生成器时,每个生成器的专属配置要写清楚。我曾经犯过一个错——DEB和RPM的配置混在一起,结果DEB包带了RPM的依赖字段,安装时报错。建议用if(CPACK_GENERATOR MATCHES "DEB")做条件判断。

2.6 生成器的高级技巧

最后分享几个我积累的小技巧:

  • 自定义安装路径:用CPACK_PACKAGE_INSTALL_DIRECTORY控制安装目录
  • 组件化打包:用CPACK_COMPONENTS_ALL实现选择性安装
  • 数字签名:NSIS支持CPACK_NSIS_SIGN_CODE,Windows下可以自动签名
  • 预安装脚本:DEB和RPM都支持CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA添加自定义脚本

嗯,生成器这块内容其实挺多的。我建议你先从TGZ开始练手,熟悉了CPack的工作流程后,再尝试NSIS或DEB。毕竟TGZ出错了也就是个压缩包,NSIS或DEB搞砸了可能影响整个系统。

下一章我会讲如何编写CPack配置文件,到时候会结合今天讲的生成器,给出完整的实战案例。