第28章 打包与分发:CPack、WiX Toolset、DMG、AppImage
说到跨平台开发的最后一公里,打包分发绝对是个绕不开的坎儿。你想想看,代码写好了,编译通过了,测试也跑完了,结果用户拿到手不知道怎么装——这多尴尬。
我个人习惯把打包这件事分成三个维度来看:平台原生性、依赖管理和安装体验。Windows用户要的是双击下一步,macOS用户期待拖拽到Applications,Linux用户则希望一个AppImage搞定一切。嗯,今天我们就来把这三种平台的打包方案掰开揉碎讲清楚。
28.1 CPack:跨平台打包的瑞士军刀
CPack是CMake自带的打包工具,说白了就是给CMake项目配一个统一的打包接口。你只要在CMakeLists.txt里写好配置,CPack就能帮你生成各种平台的安装包。
先看一个最基础的CPack配置:
# CMakeLists.txt 尾部添加
include(CPack)
set(CPACK_PACKAGE_NAME "MyApp")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_PACKAGE_VENDOR "MyCompany")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A cross-platform application")
# 指定生成器
set(CPACK_GENERATOR "ZIP;TGZ")
# Windows下还可以加 NSIS 或 WIX
if(WIN32)
list(APPEND CPACK_GENERATOR "NSIS")
endif()
然后执行:
cpack -G ZIP # 生成zip包
cpack -G TGZ # 生成tar.gz包
cpack -G NSIS # Windows下生成exe安装包
cpack -G WIX # Windows下生成msi安装包
cpack -G DragNDrop # macOS下生成dmg包
cpack -G RPM # Linux下生成rpm包
cpack -G DEB # Linux下生成deb包
28.2 WiX Toolset:Windows安装包的专业方案
Windows平台的安装包,我个人最推荐WiX Toolset。它生成的是.msi文件,Windows Installer原生支持,企业环境里部署起来特别方便。
WiX用XML来描述安装过程,看一个最简单的例子:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="MyApp" Language="1033"
Version="1.0.0" Manufacturer="MyCompany">
<Package InstallerVersion="200" Compressed="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="INSTALLDIR" Name="MyApp" />
</Directory>
</Directory>
<ComponentGroup Id="ProductComponents" Directory="INSTALLDIR">
<Component Id="MainExecutable" Guid="*">
<File Id="MyAppExe" Name="MyApp.exe"
Source="$(var.BuildDir)/MyApp.exe" />
</Component>
</ComponentGroup>
<Feature Id="MainFeature" Title="Main Feature" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
</Product>
</Wix>
然后用candle和light编译:
candle MyApp.wxs -o MyApp.wixobj
light MyApp.wixobj -o MyApp.msi
WiX还支持自定义操作(CustomAction),比如写注册表、创建快捷方式、启动服务等。我一般用WiX的Heat工具自动扫描目录生成.wxs文件,省得手写几百行XML。
28.3 DMG:macOS的优雅分发
macOS用户习惯拖拽安装。DMG(Disk Image)就是干这个的——你打开一个.dmg文件,把.app拖到Applications文件夹里,完事。
用CPack生成DMG最简单:
cpack -G DragNDrop
但如果你想自定义DMG的外观(比如背景图、窗口大小、图标位置),就得用hdiutil和osascript手动做了。我写了一个脚本:
#!/bin/bash
# 创建临时目录
mkdir -p dmg_build
cp -r MyApp.app dmg_build/
# 创建DMG
hdiutil create -srcfolder dmg_build \
-volname "MyApp" \
-fs HFS+ \
-format UDZO \
-size 200m \
MyApp.dmg
# 挂载并设置背景(可选)
hdiutil attach MyApp.dmg
# ... 这里可以用AppleScript设置窗口位置和背景
hdiutil detach /Volumes/MyApp
macOS还有一个坑:代码签名。不签名的.app在Gatekeeper下会被拦截。我建议在打包脚本里加上:
codesign --force --deep --sign "Developer ID Application: YourName" MyApp.app
28.4 AppImage:Linux的便携式方案
Linux发行版太多,deb、rpm、pacman各玩各的。AppImage的好处是——一个文件,到处运行。用户下载后chmod +x就能用,不需要安装依赖。
AppImage的核心是一个AppDir目录结构,然后用appimagetool打包:
# 创建AppDir
mkdir -p MyApp.AppDir/usr/bin
cp MyApp MyApp.AppDir/usr/bin/
cp icon.png MyApp.AppDir/
cp MyApp.desktop MyApp.AppDir/
# 创建.desktop文件
cat > MyApp.AppDir/MyApp.desktop << EOF
[Desktop Entry]
Name=MyApp
Exec=MyApp
Icon=icon
Type=Application
Categories=Utility;
EOF
# 打包
appimagetool MyApp.AppDir MyApp-x86_64.AppImage
AppImage的依赖处理方式很巧妙:它会把所有需要的.so库都打包进去。但要注意,不要打包系统库(比如glibc),否则在不同发行版上反而会出问题。
linuxdeploy工具,它会自动排除系统库,只打包应用特有的依赖。
还有一个实用工具叫linuxdeployqt(Qt项目专用)或linuxdeploy(通用),它们能自动扫描可执行文件的依赖并复制到AppDir里:
linuxdeploy --appdir MyApp.AppDir --executable MyApp --desktop-file MyApp.desktop --icon-file icon.png
28.5 四种打包方案对比
| 方案 | 平台 | 输出格式 | 依赖处理 | 安装体验 | 推荐场景 |
|---|---|---|---|---|---|
| CPack | 全平台 | ZIP/TGZ/NSIS/WIX/DragNDrop等 | 需手动配置 | 取决于生成器 | CMake项目的统一打包入口 |
| WiX Toolset | Windows | .msi | 需手动配置 | 企业级,支持静默安装 | 企业环境、需要组策略部署 |
| DMG | macOS | .dmg | 需代码签名 | 拖拽安装,用户友好 | macOS桌面应用分发 |
| AppImage | Linux | .AppImage | 自动打包应用依赖 | 下载即用,无需安装 | 跨发行版Linux分发 |
28.6 打包流程自动化
在实际项目中,我通常用CI/CD来自动化打包流程。以GitHub Actions为例:
# .github/workflows/package.yml
jobs:
package:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- name: Configure
run: cmake -B build -DCMAKE_BUILD_TYPE=Release
- name: Build
run: cmake --build build --config Release
- name: Package
run: cpack --config build/CPackConfig.cmake
- name: Upload
uses: actions/upload-artifact@v3
with:
name: package-${{ matrix.os }}
path: build/*.zip
这样每次提交代码,三个平台的安装包都会自动生成。我只需要去Artifacts页面下载就行。
- CPack是跨平台打包的入口,统一管理生成器
- WiX适合Windows企业级部署,注意GUID管理
- DMG要配合代码签名,否则Gatekeeper会拦截
- AppImage用linuxdeploy自动处理依赖,别打包系统库
- CI/CD自动化打包,省时省力
打包分发这件事,说白了就是让用户用最舒服的方式拿到你的软件。Windows用户要.msi,macOS用户要.dmg,Linux用户要.AppImage——你都得准备好。CPack帮你统一管理,但每个平台的细节还得自己打磨。
我个人建议:先用CPack搭好架子,然后针对每个平台做定制优化。Windows上WiX的GUID别搞错,macOS别忘了签名,Linux用linuxdeploy自动处理依赖。把这些坑都填平了,你的软件才能顺利到达用户手里。