CMake CPack WIX Generator 完全指南:用 WiX Toolset 构建 Windows Installer(.msi)安装包
CMake CPack WIX Generator 完全指南:用 WiX Toolset 构建 Windows Installer(.msi)安装包
导读
本文以 CMake 官方文档 Help/cpack_gen/wix.rst 为骨架,系统讲解 CPack 的 WIX 生成器如何调用 WiX Toolset 产出 Windows Installer(.msi)数据库,涵盖两种工具链(WiX .NET Tools v4 与 WiX Toolset v3)的环境准备、全部 CPACK_WIX_* 配置变量的含义与默认行为、自定义模板与补丁注入等高级玩法。读完本文,你将能在一份 CMakeLists.txt 中直接配置出带组件选择、快捷方式、许可协议、自定义 UI 与注册表信息的专业 MSI 安装程序,并理解生成器底层(Source/CPack/WiX/cmCPackWIXGenerator.cxx)的关键调用链。
一、WIX 生成器是什么
CPack 的 WIX 生成器使用 WiX Toolset(Windows Installer XML Toolset)来生成 Windows Installer 数据库文件,即常见的 .msi 安装包。在配置阶段通过 -G WIX 指定生成器,打包阶段由 CPack 自动调用 WiX 工具完成编译与链接。
与 NSIS 等自解压安装程序不同,MSI 走的是 Windows 系统级安装服务(Windows Installer Service)通道,因此天然支持添加/删除程序管理、静默安装(msiexec /i)、按用户或按机器安装(per-user / per-machine)等能力,适合企业级软件分发。
从源码结构看,整个生成器位于 Source/CPack/WiX 目录,核心类 cmCPackWIXGenerator 继承自 cmCPackGenerator(cmCPackWIXGenerator.h),它对外输出扩展名为 .msi(GetOutputExtension() 返回 ".msi"),支持组件化安装(SupportsComponentInstallation() 返回 true)。
二、选择 WiX 工具链:CPACK_WIX_VERSION
CPack 依据 CPACK_WIX_VERSION 变量在两类 WiX 工具链之间做出选择:
4:使用 WiX .NET Tools(即 v4 工具链,命令为wix)。3:使用 WiX Toolset v3(命令为candle+light)。这是默认值。
该变量在 Modules/Internal/CPack/CPackWIX.cmake 中直接决定工具查找与 InstallScope 默认值;在生成器实现中,InitializeWiXConfiguration() 会解析该值,任何非 3/4 的取值都会以 "CPACK_WIX_VERSION has unknown value" 报错。
2.1 WiX .NET Tools(v4)
打包流程由单一命令 wix build 完成:把 WiX 源文件直接构建为 .msi 数据库。该命令的调用可通过两类工具专属变量定制:
CPACK_WIX_BUILD_EXTENSIONS(见CPACK_WIX_<TOOL>_EXTENSIONS)CPACK_WIX_BUILD_EXTRA_FLAGS(见CPACK_WIX_<TOOL>_EXTRA_FLAGS)
v4 的 WiX 扩展必须按 WixToolset.<Name>.wixext 形式命名。CPack 期望 wix .NET 工具可直接命令行调用,且所需扩展已预先安装;同时要求 wix 版本与 CPACK_WIX_VERSION 兼容,扩展版本与 wix 工具版本一致。
安装步骤(Windows,bat 命令):
-
用
dotnet安装wix命令行工具。全局安装到当前用户:dotnet tool install --global wix --version 4.0.4这会生成
%USERPROFILE%\.dotnet\tools\wix.exe,并把该目录加入当前用户的PATH。或安装到指定路径(例如
c:\WiX):dotnet tool install --tool-path c:\WiX wix --version 4.0.4此时
wix.exe位于c:\WiX,但不会自动加入PATH。可以设置WIX环境变量告知 CPack 工具位置,例如set WIX=c:\WiX。 -
添加 CPack 默认 WiX 模板所需的
UI扩展:wix extension add --global WixToolset.UI.wixext/4.0.4全局添加的扩展存放在
%USERPROFILE%\.wix;若设置了WIX_EXTENSIONS环境变量,则存放在%WIX_EXTENSIONS%\.wix。
2.2 WiX Toolset v3
打包流程分为两步:
candle:把.wxs源文件编译为.wixobj中间对象文件。可用CPACK_WIX_CANDLE_EXTENSIONS与CPACK_WIX_CANDLE_EXTRA_FLAGS定制。light:把.wixobj链接为最终的.msi数据库。可用CPACK_WIX_LIGHT_EXTENSIONS与CPACK_WIX_LIGHT_EXTRA_FLAGS定制。
CPack 会按需先后调用两个工具,中间的 .wixobj 属于实现细节(打包目录 _CPack_Packages 下可看到)。v3 的扩展必须按 Wix<Name>Extension 形式命名。
v3 工具通过 PATH 查找;若设置了 WIX 环境变量,则 CPack 在 %WIX% 与 %WIX%\bin 下查找。这一查找逻辑可见 CPackWIX.cmake:v4 只查找 wix 可执行文件,v3 则查找 candle 与 light 两个可执行文件,找不到即 FATAL_ERROR。
从源码看两种工具链的实际调用命令形态:
- v4 路径 PackageWithWix():
wix build -arch <arch> -out <msi> -ext <ext>... -culture "<culture>"... -src <wxs>...; - v3 路径 PackageWithWix3():先对每个源文件执行 RunCandleCommand()(
candle -nologo -arch <arch> -out <wixobj> -ext <ext>...),再执行 RunLightCommand()(light -nologo -out <msi> -ext <ext>... -cultures:<...>)。
三、CPack WIX 专属配置变量详解
以下变量专门针对使用 WiX 构建的 Windows 安装程序,配置于 CMakeLists.txt(或 CPACK_PROJECT_CONFIG_FILE)中。
3.1 版本与 GUID:升级与产品标识
-
CPACK_WIX_VERSION(自 3.30 起):指定配置面向的 WiX Toolset 版本,取值为4或3(默认3)。如前所述,它决定了工具链与后续若干变量的默认行为。 -
CPACK_WIX_UPGRADE_GUID:升级 GUID,对应 WiX 中的Product/@UpgradeCode。未显式设置时由 CPack 自动生成。建议显式设置为一个固定的全局唯一 GUID,这样后续版本的安装包可以替换掉使用同一 GUID 的旧安装。你可以在首次打包后,把 CPack 自动生成的值回填到 CMakeLists.txt 中固化下来。不要使用他人或他项目生成的 GUID。GUID 语法为固定长度格式:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX(每个 X 为大写十六进制数字)
-
CPACK_WIX_PRODUCT_GUID:产品 GUID,对应Product/@Id。未显式设置时自动生成。显式设置后决定安装器的 Product Id;如果检测到已有使用同一 GUID 的安装,安装器会中止。语法与CPACK_WIX_UPGRADE_GUID相同。
源码佐证:在 InitializeWiXConfiguration() 中,未设置的两个 GUID 均由 GenerateGUID() 生成——Windows 上调用 UuidCreate,非 Windows 平台使用 uuid_generate。其中 CPACK_WIX_UPGRADE_GUID 自动生成时会给出 WARNING,提醒用户最好显式固化。两个 GUID 随后被写入 cpack_variables.wxi 供默认模板引用(见 CreateWiXVariablesIncludeFile() 与 WIX.template.in)。
3.2 许可协议与品牌元素
-
CPACK_WIX_LICENSE_RTF:RTF 许可协议文件。行为规则:- 若
CPACK_RESOURCE_FILE_LICENSE是.rtf扩展名,则原样使用; - 若为
.txt扩展名,WIX 生成器会隐式转换为 RTF,源文件编码需为 UTF-8; - 当
CPACK_RESOURCE_FILE_LICENSE是不受支持的格式、或.txt → .rtf转换不符合预期时,可用此变量直接覆盖。
转换由
cmWIXRichTextFormatWriter(cmWIXRichTextFormatWriter.cxx)实现;CreateLicenseFile() 中,.rtf直接拷贝,.txt逐行写入 RTF,其他扩展名直接报错。模板中通过WixVariable Id="WixUILicenseRtf"引用(WIX-v3/WIX.template.in)。 - 若
-
CPACK_WIX_PRODUCT_ICON:显示在"添加或删除程序"中程序名旁边的图标。设置后将替换默认图标。对应模板中的ARPPRODUCTICON属性与Icon元素。 -
CPACK_WIX_UI_BANNER:除欢迎页与完成页外所有安装页顶部显示的位图。设置后替换默认横幅。图片尺寸必须为 493 × 58 像素。 -
CPACK_WIX_UI_DIALOG:欢迎页与完成页的背景位图。设置后替换默认对话框图像。图片尺寸必须为 493 × 312 像素。
3.3 界面与快捷方式
-
CPACK_WIX_UI_REF:指定 WiXUI扩展的对话框集合:- v4 下是默认模板中
<ui:WixUI>元素的 Id; - v3 下是默认模板中
<UIRef>元素的 Id。
默认值:未定义任何 CPack 组件时为
WixUI_InstallDir,定义了组件时为WixUI_FeatureTree(源码见 InitializeWiXConfiguration())。默认模板中始终附带WixUI_ErrorProgressText(WIX.template.in)。 - v4 下是默认模板中
-
CPACK_WIX_PROGRAM_MENU_FOLDER:启动器的开始菜单文件夹名。未设置时初始化为CPACK_PACKAGE_NAME。自 3.16 起,若设置为.,应用快捷方式将直接创建于开始菜单,并且省略卸载快捷方式(源码中通过判断cpackWixProgramMenuFolder == "."关闭emitUninstallShortcut,见 cmCPackWIXGenerator.cxx)。 -
CPACK_WIX_CULTURES:安装程序的语言。语言被编译进 WixUI扩展库,直接给出 culture 名称即可使用。多个 culture 以逗号或分号分隔时,第一个匹配到语言资源的生效。官方支持语言列表见 WiX 文档的 wixui_localization 页面(仓库文档原文引用了该地址,此处不展开外部链接)。源码中,v4 以-culture "<culture>"逐项传递,v3 以-cultures:<...>一次性传递。
3.4 模板与补丁:深度定制入口
-
CPACK_WIX_TEMPLATE:WiX 生成的模板文件。设置后使用指定模板生成.wxs文件,适合需要进一步定制输出的场景。注意:模板内容会覆盖大部分CPACK_WIX_变量的效果。未设置时使用 CMake 自带的默认 MSI 模板:模板选取逻辑在 GenerateMainSourceFileFromTemplate():v3 用
WIX-v3/子目录模板,v4 用根模板,最终 configure 生成main.wxs。模板中的@CPACK_WIX_CUSTOM_XMLNS_EXPANDED@占位符用于注入自定义命名空间。 -
CPACK_WIX_PATCH_FILE(可选,自 3.5 起支持多个补丁文件):指定一个 XML 文件,WIX 生成器将其中的片段注入生成的 WiX 源文件。补丁文件大致遵循如下 RELAX NG compact schema:start = CPackWiXPatch CPackWiXPatch = element CPackWiXPatch { CPackWiXFragment* } CPackWiXFragment = element CPackWiXFragment { attribute Id { string }, fragmentContent* } fragmentContent = element * - CPackWiXFragment { (attribute * { text } | text | fragmentContent)* }当前可注入片段到大多数
Component、File、Directory和Feature元素。附加的特殊 Id(自 3.3 起):#PRODUCT:对应<Product>元素;#PRODUCTFEATURE:对应根<Feature>元素。
自 3.7 起支持补丁任意
<Feature>元素;自 3.9 起允许设置额外属性。示例:假设生成器创建了如下 XML 元素:
<Component Id="CM_CP_applications.bin.my_libapp.exe" Guid="*"/>下面这个补丁文件可向其中注入一个 Environment 元素:
<CPackWiXPatch> <CPackWiXFragment Id="CM_CP_applications.bin.my_libapp.exe"> <Environment Id="MyEnvironment" Action="set" Name="MyVariableName" Value="MyVariableValue"/> </CPackWiXFragment> </CPackWiXPatch>补丁机制由 cmWIXPatch.cxx 与 cmWIXPatchParser.cxx 实现,注入点在
cmWIXSourceWriter各写入器生成元素时统一调用Patch->ApplyFragment(...);生成结束后还会通过CheckForUnappliedFragments()校验所有补丁片段是否都已生效(cmCPackWIXGenerator.cxx)。
3.5 额外源文件与扩展
-
CPACK_WIX_EXTRA_SOURCES:额外的 WiX 源文件(.wxs)列表,会被一并编译与链接。路径必须为绝对路径。源码中通过 AppendUserSuppliedExtraSources() 追加到WixSources。 -
CPACK_WIX_EXTRA_OBJECTS(仅 v3):额外的 WiX 对象文件(.wixobj)和/或库文件(.wixlib)列表,路径必须为绝对路径,由 AppendUserSuppliedExtraObjects() 追加到light链接输入。 -
CPACK_WIX_EXTENSIONS:为所有 WiX 工具指定额外扩展列表。命名规则见上文工具链小节(v4 为WixToolset.<Name>.wixext,v3 为Wix<Name>Extension)。 -
CPACK_WIX_<TOOL>_EXTENSIONS:为特定 WiX 工具指定额外扩展。v4 的<TOOL>为BUILD;v3 的<TOOL>为CANDLE、LIGHT。从 InitializeWiXConfiguration() 可见:v3 下CPACK_WIX_EXTENSIONS会同时作用于 candle 与 light,而CPACK_WIX_CANDLE_EXTENSIONS/CPACK_WIX_LIGHT_EXTENSIONS分别作用于各自工具。 -
CPACK_WIX_<TOOL>_EXTRA_FLAGS:为特定 WiX 工具追加额外命令行参数。使用风险自负:未来 CPack 版本生成的参数可能与你的参数冲突。实现上由 AddCustomFlags() 原样拼入命令行。 -
CPACK_WIX_ROOT:自定义 WiX Toolset 安装根目录(可选)。未指定时,CPack 通过WIX环境变量定位工具(CPackWIX.cmake)。 -
CPACK_WIX_CUSTOM_XMLNS(自 3.19 起):自定义命名空间声明列表,用于支持 WiX 扩展。每项形如name=url,name是不带xmlns:前缀的命名空间名,url是不加引号的命名空间 URL。常见 WiX schema 列表见 WiX 官方 xsd 页面(仓库文档原文引用了该地址)。源码中由 CollectXmlNamespaces() 收集并经 InjectXmlNamespaces() 注入所有生成的源文件。 -
CPACK_WIX_SKIP_WIX_UI_EXTENSION(自 3.23 起):设为 true 时跳过默认包含的 WiXUI扩展,即不再向 WiX 工具传递-ext WixUIExtension(v3)或-ext WixToolset.UI.wixext(v4)参数(源码见 InitializeWiXConfiguration())。
3.6 架构与安装范围
-
CPACK_WIX_ARCHITECTURE(自 3.24 起):可选设置安装包的目标架构,例如x64或arm64。未指定时 CPack 依据CPACK_WIX_SIZEOF_VOID_P推断为x64或x86(GetArchitecture())。 -
CPACK_WIX_INSTALL_SCOPE(自 3.29 起):设置安装器的InstallScope属性,取值:perMachine:为所有用户安装,需要管理员权限,开始菜单条目对所有用户可见。默认值(v4 与 v3 在 CPackWIX.cmake 中分别默认perMachine/NONE;文档另注见策略 CMP0172)。perUser:仅当前用户安装,不需要管理员权限,开始菜单条目仅当前用户可见。为支持 per-user 安装,安装器需生成额外的注册表项作为已装组件的 "key paths"(对应 MSI 验证规则 ICE38),这些注册表项创建于HKEY_CURRENT_USER下,路径由CPACK_WIX_COMPONENT_KEYS_REGISTRY_PATH指定。注意:CMake 4.3 之前该值仅保留未实现。NONE:创建不含任何InstallScope属性的安装器。仅当CPACK_WIX_VERSION未设置或为3时支持。该值已弃用(3.29 弃用),仅为兼容 CPack 3.28 及更早版本的不一致行为:生成的安装器需要管理员权限、安装到系统级ProgramFiles,但开始菜单条目与卸载注册仅对当前用户创建。
警告:不同
InstallScope值创建的安装器之间无法被干净地更新或互相替换。例如要从NONE迁移到perMachine、或从perMachine迁移到perUser,后一个安装器应附带"先手动卸载旧版本"的说明。默认模板对
InstallScope的处理可见 WIX-v3/WIX.template.in:NONE时输出不带 InstallScope 的<Package>,否则输出带InstallScope="$(var.CPACK_WIX_INSTALL_SCOPE)"的<Package>;v4 模板则始终输出Scope="$(var.CPACK_WIX_INSTALL_SCOPE)"。 -
CPACK_WIX_COMPONENT_KEYS_REGISTRY_PATH(自 4.3 起):当CPACK_WIX_INSTALL_SCOPE为perUser时,安装器在HKEY_CURRENT_USER下创建组件 key path 注册表项的路径。路径分隔符建议使用正斜杠/(会自动转换为反斜杠\,源码见 cmCPackWIXGenerator.cxx)。默认值为Software/<Vendor>/<PackageName>/Components,其中<Vendor>取自CPACK_PACKAGE_VENDOR,<PackageName>取自CPACK_PACKAGE_NAME。例如:Software/MyCompany/MyProduct/Components。
3.7 安装目录与文件布局
-
CPACK_WIX_ROOT_FEATURE_TITLE(自 3.7 起):设置 WIX 安装器中根安装功能的名称,与组件的CPACK_COMPONENT_<compName>_DISPLAY_NAME语义一致。未设置时使用CPACK_PACKAGE_NAME(源码见 cmCPackWIXGenerator.cxx)。 -
CPACK_WIX_ROOT_FEATURE_DESCRIPTION(自 3.7 起):设置根安装功能的描述,与组件的CPACK_COMPONENT_<compName>_DESCRIPTION语义一致。 -
CPACK_WIX_SKIP_PROGRAM_FOLDER(自 3.7 起):设为 true 时,生成包的默认安装位置直接为CPACK_PACKAGE_INSTALL_DIRECTORY,不再位于ProgramFiles或ProgramFiles64之下。注意:使用该特性创建的安装器不考虑"创建安装包的系统"与"实际安装系统的差异",因此可能出现试图安装到不可用的驱动器、或不符合目标系统本地化/惯例路径的情况。
同时要注意:当跳过 ProgramFiles 目录时,默认组件 GUID
*无法使用,生成器会改用 CMake 生成的 GUID(cmCPackWIXGenerator.cxx)。 -
CPACK_WIX_ROOT_FOLDER_ID(自 3.9 起):指定自定义根文件夹 ID。生成器特有的<64>标记可用于同时存在 32/64 位变体的文件夹 ID:32 位构建中该标记展开为空,64 位构建中展开为64。未设置时:CPACK_WIX_INSTALL_SCOPE为perUser则安装到LocalAppDataFolder,否则安装到ProgramFiles<64>Folder。完整逻辑见 GetRootFolderId()。
3.8 组件、注册表与打包性能
-
CPACK_WIX_CMAKE_PACKAGE_REGISTRY:设置后,生成的安装器会在注册表HKEY_LOCAL_MACHINE\Software\Kitware\CMake\Packages\<PackageName>创建条目,<PackageName>即该变量值。若同时安装了 CMake 配置文件,其他 CMake 项目即可用find_package找到你的包。源码中通过 CreateCMakePackageRegistryEntry() 生成,其中还携带了CPACK_WIX_UPGRADE_GUID。 -
CPACK_WIX_PROPERTY_<PROPERTY>(自 3.1 起):为 Windows Installer 属性<PROPERTY>提供值。可用于定制"程序和功能"(又称"添加或删除程序")中的信息,常用示例属性:属性 含义 ARPCOMMENTS注释 ARPHELPLINK帮助和支持信息 URL ARPURLINFOABOUT常规信息 URL ARPURLUPDATEINFO更新信息 URL ARPHELPTELEPHONE帮助和支持电话号码 ARPSIZE应用程序大小(千字节 KB) 实现上,CreateWiXPropertiesIncludeFile() 扫描所有以
CPACK_WIX_PROPERTY_开头的选项,生成<Property Id="..." Value="..."/>元素。同时,若未设置CPACK_WIX_PROPERTY_ARPINSTALLLOCATION,生成器会自动创建INSTALL_ROOT安全属性,并通过RegistrySearch在卸载注册表里反查安装位置,再以SetProperty填充ARPINSTALLLOCATION,保证"添加或删除程序"能显示正确的安装路径。此外,若设置了CPACK_PACKAGE_CONTACT而未显式设置CPACK_WIX_PROPERTY_ARPCONTACT,会自动把联系人填入 ARPCONTACT(cmCPackWIXGenerator.cxx)。 -
CPACK_WIX_CAB_PER_COMPONENT(自 4.2 起):设为 true 时,每个组件生成一个.cab文件;默认为整个安装包的所有文件生成单个.cab。WiX 会并行生成.cab文件,因此多个.cab可能更有利于加快打包速度。源码中 CreateWiXProductFragmentIncludeFile() 按组件数量生成mediaN.cab的<Media>定义,AddComponentsToFeature() 则为每个组件分配独立 diskId;未开启时默认模板只声明<Media Id="1" Cabinet="media1.cab" EmbedCab="yes"/>。
四、组件化安装与快捷方式
WIX 生成器支持 CPack 组件化安装(SupportsComponentInstallation() 为 true),其组件与功能(Feature)的映射关系在 CreateFeatureHierarchy() 中建立:组件组(ComponentGroups)与无组组件会分别生成对应 <Feature>,每个组件对应一个以 CM_C_<compName> 命名的 feature Id。
快捷方式方面(相关函数 CreateShortcuts() 与 CreateShortcutsOfSpecificType()):
- 通过
CPACK_PACKAGE_EXECUTABLES(成对的<executable>与<text label>)创建开始菜单快捷方式,可选的CPACK_CREATE_DESKTOP_LINKS同时创建桌面快捷方式(AddComponentsToFile 路径 中对.exe文件名进行小写匹配); - 开始菜单快捷方式组件还会自动生成卸载快捷方式(
EmitUninstallShortcut),除非CPACK_WIX_PROGRAM_MENU_FOLDER为.; - 为组件设置
CPACK_WIX_ACL安装文件属性可生成访问控制列表(ACL)相关条目,该逻辑位于 cmWIXAccessControlList.cxx; - perUser 安装时,快捷方式、目录、文件组件所需的 key path 注册表项由
CPACK_WIX_COMPONENT_KEYS_REGISTRY_PATH决定(经 cmWIXDirectoriesSourceWriter / cmWIXFilesSourceWriter 传入)。
五、端到端配置示例
下面给出一个可运行的完整示例,集中展示常用变量与组件化用法(实际配置于 CMakeLists.txt 的 CPack 部分):
# 启用 WIX 生成器所需的通用设置
set(CPACK_GENERATOR "WIX")
set(CPACK_PACKAGE_NAME "MyProduct")
set(CPACK_PACKAGE_VENDOR "MyCompany")
set(CPACK_PACKAGE_VERSION "1.2.3")
set(CPACK_PACKAGE_CONTACT "support@example.com")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "MyCompany/MyProduct")
# 固定升级 GUID,保证后续版本可覆盖旧安装(自行用工具生成一次并固化)
set(CPACK_WIX_UPGRADE_GUID "01234567-89AB-CDEF-0123-456789ABCDEF")
# 可选:固定产品 GUID
# set(CPACK_WIX_PRODUCT_GUID "FEDCBA98-7654-3210-FEDC-BA9876543210")
# 许可协议:.txt 会被自动转换为 RTF(需 UTF-8 编码)
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt")
# 使用 WiX Toolset v3(默认);切换 v4 需安装 wix .NET 工具
# set(CPACK_WIX_VERSION 3)
# 品牌与 UI
set(CPACK_WIX_PRODUCT_ICON "${CMAKE_CURRENT_SOURCE_DIR}/icon.ico")
set(CPACK_WIX_UI_BANNER "${CMAKE_CURRENT_SOURCE_DIR}/banner.bmp") # 493x58
set(CPACK_WIX_UI_DIALOG "${CMAKE_CURRENT_SOURCE_DIR}/dialog.bmp") # 493x312
set(CPACK_WIX_CULTURES "zh-CN;en-US")
# 安装范围与开始菜单
set(CPACK_WIX_INSTALL_SCOPE "perMachine")
set(CPACK_WIX_PROGRAM_MENU_FOLDER "MyCompany/MyProduct")
# 添加或删除程序信息
set(CPACK_WIX_PROPERTY_ARPURLINFOABOUT "https://example.com/about")
set(CPACK_WIX_PROPERTY_ARPURLUPDATEINFO "https://example.com/update")
# 组件定义(未定义组件时默认使用 WixUI_InstallDir)
set(CPACK_COMPONENTS_GROUPING "ALL_COMPONENTS_IN_ONE")
include(CPack)
打包命令(Windows):
cmake -G "NMake Makefiles" -DCPACK_GENERATOR=WIX ..
cmake --build . --config Release
cpack -G WIX
产物为 _CPack_Packages 目录下的 .msi 文件。若 CPack 找不到 WiX 工具,请检查 PATH(v3 的 candle/light,v4 的 wix)或设置 WIX 环境变量指向工具根目录。
六、调试与常见问题
- 找不到
candle/light/wix:确认 CPackWIX.cmake 的查找路径是否覆盖你的安装位置(PATH、CPACK_WIX_ROOT、WIX环境变量、PATH_SUFFIXES "bin")。 CPACK_WIX_VERSION非法取值:只接受3或4,其余值会直接报错退出。- 许可协议无法转换:确认源文件为 UTF-8 编码的
.txt或原生.rtf;其他扩展名(如.md)会触发 "unsupported WiX License file extension" 错误,此时应使用CPACK_WIX_LICENSE_RTF显式指定。 - 图标/横幅尺寸不符:
CPACK_WIX_UI_BANNER必须 493×58,CPACK_WIX_UI_DIALOG必须 493×312,否则安装界面显示异常。 - 升级无法覆盖旧版:检查
CPACK_WIX_UPGRADE_GUID是否固定为与旧安装包相同的 GUID。 - per-user 安装异常:
CPACK_WIX_INSTALL_SCOPE=perUser需要 CMake 4.3+ 支持,并依赖CPACK_WIX_COMPONENT_KEYS_REGISTRY_PATH(默认Software/<Vendor>/<PackageName>/Components)生成 key path 注册表项。 - 调试工具调用:WiX 命令及其输出会追加写入打包目录下的日志文件,报错信息中会提示具体日志路径(见 RunWiXCommand())。
七、小结
CPack 的 WIX 生成器把 WiX Toolset 的能力完整封装进 CMake 生态:通过 CPACK_WIX_VERSION 在 v4(wix build)与 v3(candle+light)两套工具链间切换,用十余个 CPACK_WIX_* 变量覆盖 GUID、许可协议、UI、快捷方式、安装范围、注册表与打包性能等全部关键环节。默认模板(WIX-v3/WIX.template.in 与 WIX.template.in)承担绝大多数生成工作,而 CPACK_WIX_TEMPLATE 与 CPACK_WIX_PATCH_FILE 则为需要深度定制的项目保留了完整的扩展入口。如需进一步深入实现细节,可直接研读 Source/CPack/WiX 目录下的生成器源码与各写入器实现。