WiX Toolset 创建 Bundle 骨架:从空的 `<Bundle>` 到可用的引导程序工程
WiX Toolset 创建 Bundle 骨架:从空的 <Bundle> 到可用的引导程序工程
本文围绕 WiX Toolset v3.x 的官方文档 Create the Skeleton Bundle Authoring 展开,完整讲解如何搭建一个 Burn Bundle 的最小可运行骨架:从 <Wix> 根元素下的空 <Bundle> 起步,逐步加入 BootstrapperApplicationRef、Chain、Variable 等核心子元素,并辅以仓库源码(src/tools/wix/Compiler.cs、src/tools/wix/Xsd/wix.xsd、src/Setup/Bundle/Bundle.wxs)印证编译与运行时行为。读完本文,你将能独立写出一个结构正确、可被 candle/light 正常编译的 Bundle 骨架,并为下一步接入标准引导程序与安装包链打好基础。
从空的 Bundle 开始
在 WiX Toolset 中,Bundle 的根元素是 <Bundle>,它必须直接位于 <Wix> 元素之下。一个空 Bundle 的骨架代码如下:
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Bundle>
<!-- Contents of the bundle goes here -->
</Bundle>
</Wix>
这是创建 Bundle 的最基本形态。从源码结构看,编译器在 Compiler.cs 中通过 ParseBundleElement 处理 <Wix> 下的 Bundle 子元素;也就是说,任何 Bundle 都必须落在 <Wix> 根命名空间(http://schemas.microsoft.com/wix/2006/wi)之内,这是编译器的基本约束。
加入两个最常用的子元素:BootstrapperApplicationRef 与 Chain
原文档指出,在示例中要往 <Bundle> 中逐步添加以下元素:
<BootstrapperApplicationRef>:引用一个引导程序应用程序;<Chain>:存放构成 Bundle 的按序安装的包列表;<Variable>:定义 Burn 引擎变量。
作为起步,先加入其中最常见的两个元素:
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Bundle>
<BootstrapperApplicationRef />
<Chain>
</Chain>
</Bundle>
</Wix>
<BootstrapperApplicationRef>最终将指向 WiX Toolset 提供的标准 BootstrapperApplication;<Chain>最终将容纳组成 Bundle 的有序包列表。
Bundle 元素的合法子元素与编译约束
为了写出正确骨架,有必要了解 <Bundle> 的合法内容模型。在编译器 Compiler.cs 的 ParseBundleElement 中,Bundle 的子元素按 switch 分派处理,合法子元素包括:
ApprovedExeForElevationBootstrapperApplication/BootstrapperApplicationRefOptionalUpdateRegistrationCatalogChainContainerLogPayload/PayloadGroup(按代码上下文推断)VariableUpdate、RelatedBundle等
同时,源码还体现了两个重要的结构约束:
- BootstrapperApplication 至多一个:
baSeen标志保证<Bundle>下只能有一个BootstrapperApplication元素(Compiler.cs),否则抛出TooManyChildren错误;而BootstrapperApplicationRef不参与该唯一性检查,理论上可多次出现; - Chain 至多一个:
chainSeen标志保证<Bundle>下只能有一个Chain元素(Compiler.cs)。
此外,ParseBundleElement 还要求(Compiler.cs):
Version属性是必填的;UpgradeCode属性是必填的;- 若未提供
Name,编译器会自动生成 GUID 作为 active section 名称,并据此派生日志变量名WixBundleLog:Setup.log(Compiler.cs)。
所以一个“真正能编译”的骨架通常需要补上这些属性,例如 src/Setup/Bundle/Bundle.wxs 中 WiX 自身安装包的写法:
<Bundle Name='!(loc.ShortProduct) v$(var.WixVersion)' Manufacturer='!(loc.Company)'
Version='$(var.WixVersion)' UpgradeCode='65E893AD-EDD5-4E7D-80CA-F0F50F383532'
IconSourceFile='ProjectFile.ico' SplashScreenSourceFile='SplashScreen.bmp'
AboutUrl='!(loc.SupportUrl)' UpdateUrl='!(loc.UpdateUrl)'
Compressed='$(var.WixBundleCompressed)'>
...
</Bundle>
Variable:为 Bundle 定义引擎变量
原文档把 <Variable> 列为骨架阶段需要了解的元素之一。它用于描述一个要定义的 Burn 引擎变量(见 wix.xsd),典型用法是:
<Bundle>
<Variable Name="MyVariable" Value="some-value" />
...
</Bundle>
Variable 可以出现在 Bundle 中,用于预定义贯穿整个 Burn 引擎会话的变量,供包命令行、条件表达式与自定义引导程序引用。具体变量的语义可进一步参考 bundle_built_in_variables 文档。
下一步:为 BootstrapperApplicationRef 填充内容
骨架完成后,接下来的操作是往 <BootstrapperApplicationRef> 中添加信息,详细步骤见 Author the BootstrapperApplication for a Bundle。这里先给出一个最小可用示例(来自官方文档 authoring_bundle_application.html.md):
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense" />
该 Id 来自 WixBalExtension.dll 提供的 WiX Standard Bootstrapper Application。如果标准引导程序不满足需求,也可以编写自定义引导程序 DLL,并通过 BootstrapperApplication 元素指定:
<BootstrapperApplication SourceFile="path\to\ba.dll">
<Payload SourceFile="path\to\en-us\resources.dll" />
<PayloadGroupRef Id="ResourceGroupforJapanese" />
</BootstrapperApplication>
若需使用 RtfLicense 这类带许可证界面的标准引导程序,仓库中对应的实现与文档位于 wixstdba 目录;而 Bundle.wxs(src/Setup/Bundle/Bundle.wxs)则展示了如何通过 <BootstrapperApplicationRef> 挂载 BootstrapperCore.config 与自定义 DLL 等附加 Payload。
为 Chain 填充包列表(骨架的最终目的)
<Chain> 的最终用途是承载构成 Bundle 的包。原文档提供两种接法(详见 bundle_author_chain):
方式一:包定义直接写在 Chain 下
<Chain>
<ExePackage
SourceFile="path\to\MyPackage.exe"
DownloadUrl="http://example.com/?mypackage.exe"
InstallCommand="/q /ACTION=Install"
RepairCommand="/q ACTION=Repair /hideconsole" />
</Chain>
方式二:通过 PackageGroupRef 引用共享定义
<Chain>
<PackageGroupRef Id="MyPackage" />
</Chain>
其中 PackageGroupRef 引用定义在别处 <Fragment> 或 WiX 扩展中的 <PackageGroup>,便于多个 Bundle 复用同一组包定义。src/Setup/Bundle/Bundle.wxs 中 WixPackages、NetFx462Redist 的用法即为此模式的实际样例。
总结:从骨架到完整 Bundle 的路线
| 阶段 | 关键操作 | 依据 |
|---|---|---|
| 1 | 写 <Wix> 根元素 + 空 <Bundle> |
Compiler.cs |
| 2 | 加入 <BootstrapperApplicationRef> 与 <Chain> |
wix.xsd |
| 3 | 可选:添加 <Variable> 预定义引擎变量 |
wix.xsd |
| 4 | 填充 BootstrapperApplicationRef 指向标准/自定义引导程序 | authoring_bundle_application |
| 5 | 在 Chain 下添加包或引用 PackageGroup | bundle_author_chain |
| 6 | 补全 Version、UpgradeCode 等必填属性并编译 |
Compiler.cs |
至此,你已经掌握了 Bundle 骨架的完整编写方式:从最简的空 <Bundle> 出发,加入 BootstrapperApplicationRef 与 Chain,理解 Variable 的用途,并明确了编译器对 Bundle 子元素与必填属性的约束。下一步即可按文档顺序进入引导程序作者指南,让骨架真正具备可执行的安装能力。