问题描述
我正在尝试配置 WiX 设置和库,以便库中文件之一的版本用作设置中的 Product/@Version.
背景
在本地定义文件的设置中,这相对简单,假设组件项目被 WiX 项目引用,然后进行配置:
<File Id="Company.AssemblyFile"名称="Company.Assembly.dll" KeyPath="是"磁盘 ID="1"Source="$(var.Company.Assembly.TargetPath)"/></组件>
然后产品版本可以设置为
问题
因此,将所有组件移至 WiX 库项目后,不再可能直接引用 !(bind.FileVersion.$(var.Company.AssemblyFile.TargetFileName))
变量.>
我试过在库中配置一个 WixVariable
WixVariable Id="BuildVersion" Value="!(bind.FileVersion.Company.AssemblyFile)"/>
然后从设置中引用
没有成功.
在库或设置中是否需要一些额外的步骤或语法来使 WixVariable(或它的某些派生)可以从设置中访问?
我经常听到这个问题,但我认为 WiX 文档并不能很好地解释这种情况,所以就在这里.简短的回答是你的语法是正确的;使用 WixVariable
元素声明的变量使用语法 !(wix.VariableName)
引用,您可以使用已在引用库中定义的变量,因此 !(wix.BuildVersion)
对于您上面给出的示例是正确的.它不起作用的原因是因为需要在编译阶段验证该值,但直到链接阶段才生成它.所以这是一个很长的答案:
您可以在 *.wxs 文件中引用两种不同类型的变量;预处理器变量和binder(或链接器)变量.前者用 $ 语法引用,例如$(var.VariableName)
而后者用 !语法,例如!(bind.FileVersion.FileId)
.关键区别很简单:预处理器变量在编译阶段(通过candle.exe)进行解析,而绑定变量在链接阶段(通过light.exe)进行解析.编译器负责把源*.wxs文件编译成*.wixobj文件;它不处理实际的有效负载,因此无法从链接文件中读取版本信息.然后将 *.wixobj 文件传递给处理负载并创建 MSI 数据库的链接器.链接器负责从有效负载中收集元数据,这就是为什么它可以为诸如 !(bind.FileVersion.FileId)
之类的变量提供值.
请注意,使用 WixVariable
元素声明的变量使用 !语法所以它是一个绑定变量;它对 light.exe 可用,但对 candle.exe 不可用.这是一个问题,因为candle.exe 将验证应用于某些字段,例如Product/@Version.它不知道 !(wix.BuildVersion)
将评估什么,因此无法验证它是否会产生有效版本.相比之下,您可以使用 !(bind.FileVersion.FileId)
因为蜡烛在编译时满足,它将在链接时解析为有效版本(FileId 是对文件的直接引用在产品中,所以蜡烛相信它会存在以在链接上产生版本号).
因此,您可以在 *.wxs 中的任何其他位置使用 !(wix.BuildVersion)
,但不能将其用作 Product/@Version 的值.据我所知,您可以在这里使用的唯一活页夹变量是 !(bind.FileVersion.FileId)
但如果您想从引用的库中获取值,显然这不好.否则,您只需从其他地方获取您的版本信息并将其传递给 WiX,以便在编译时可用.如果您使用 MSBuild,它可以使用 GetAssemblyIdentity
任务查询版本信息,并可以通过 DefineConstants 属性将其传递给 WiX.*.wixproj 文件中的以下目标应该这样做:
<GetAssemblyIdentity AssemblyFiles="[Path.To.Target.File]"><Output TaskParameter="Assemblies" ItemName="AsmInfo"/></GetAssemblyIdentity><CreateProperty Value="%(AsmInfo.Version)"><Output TaskParameter="Value" PropertyName="BuildVersion"/></CreateProperty><CreateProperty Value="$(DefineConstants)"><Output TaskParameter="Value" PropertyName="DefineConstantsOriginal"/></CreateProperty><CreateProperty Value="$(DefineConstants);BuildVersion=$(BuildVersion)"><Output TaskParameter="Value" PropertyName="DefineConstants"/></CreateProperty></目标><目标名称="AfterBuild"><CreateProperty Value="$(DefineConstantsOriginal)"><Output TaskParameter="Value" PropertyName="DefineConstants"/></CreateProperty></目标>
BuildVersion 属性将传递给candle.exe,因此您可以使用预处理器变量$(var.BuildVersion) 引用它.这当然不如将其全部保存在 *.wxs 文件中那么干净,但它是将版本信息放入蜡烛中的一种方法,因此它可以用作 Product/@Version 中的变量.我当然希望听到任何更好的方法来做到这一点.
I'm trying to configure a WiX setup and library so that the version of one of the files in the library is used as the Product/@Version in the setup.
Background
In a setup with the files defined locally this is relatively straightforward in that assuming the component project is referenced by the WiX project and then configured:
<Component Id="Company.Assembly" Guid="[GUID]">
<File Id="Company.AssemblyFile"
Name="Company.Assembly.dll" KeyPath="yes"
DiskId="1"
Source="$(var.Company.Assembly.TargetPath)" />
</Component>
Then the product version can be set as
<Product Id="[GUID]"
Name="Product Name"
Language="1033"
Version="!(bind.FileVersion.$(var.Company.AssemblyFile
.TargetFileName))"
Manufacturer="Company Name"
UpgradeCode="[GUID]">
Issue
So having moved all the components to a WiX Library project it's no longer possible to directly reference the !(bind.FileVersion.$(var.Company.AssemblyFile.TargetFileName))
variable.
I've tried configuring a WixVariable in the library
WixVariable Id="BuildVersion" Value="!(bind.FileVersion.Company.AssemblyFile)"/>
And then reference that from the setup
<Product Id="[GUID]"
Name="Product Name"
Language="1033"
Version="!(wix.BuildVersion)"
Manufacturer="Company Name"
UpgradeCode="[GUID]">
Without success.
Is there some additional step or syntax required in either the library or setup to make the WixVariable (or some derivation of it) accessible from the setup?
I hear this one a lot and I don't think the WiX documentation does a particularly good job of explaining the situation, so here it is. The short answer is that your syntax is correct; a variable declared with the WixVariable
element is referenced with the syntax !(wix.VariableName)
and you can use variables that have been defined in a referenced library so !(wix.BuildVersion)
is correct for the example you've given above. The reason it doesn't work is because the value needs to be verified during the compilation phase but it's not being generated until the linking phase. So here's the long answer:
There are two distinct types of variable that you can reference in a *.wxs file; preprocessor variables and binder (or linker) variables. The former is referenced with the $ syntax, e.g. $(var.VariableName)
and the latter is referenced with the ! syntax, e.g. !(bind.FileVersion.FileId)
. The key difference is simple: preprocessor variables are parsed during the compile phase (by candle.exe) and binder variables are parsed during the link phase (by light.exe). The compiler is responsible for taking the source *.wxs files and compiling them to *.wixobj files; it doesn't process the actual payload so it's not in a position to read version information from a linked file. The *.wixobj files are then passed to the linker which processes the payload and creates the MSI database. The linker is responsible for collecting metadata from the payload which is why it can provide values for variables like !(bind.FileVersion.FileId)
.
Note that a variable declared with the WixVariable
element is referenced with the ! syntax so it's a binder variable; it will be available to light.exe but it won't be available to candle.exe. This is a problem because candle.exe applies validation to certain fields such as Product/@Version. It has no idea what !(wix.BuildVersion)
will evaluate to so it can't verify that it will yield a valid version. In contrast, you can get away with !(bind.FileVersion.FileId)
because candle is satisfied at compile time that it will resolve to a valid version at link time (FileId is a direct reference to a file in the product so candle trusts that it will exist to yield a version number on link).
So you can use !(wix.BuildVersion)
anywhere else in your *.wxs but you can't use it as a value for Product/@Version. As far as I know the only binder variable you can use here is !(bind.FileVersion.FileId)
but obviously this is no good if you want to get the value from a referenced library. Otherwise you'll just have to get your version information from somewhere else and pass it into WiX so it's available at compile time. If you're using MSBuild it can query version information with the GetAssemblyIdentity
task and can pass this to WiX via the DefineConstants property. The following targets in your *.wixproj file should do it:
<Target Name="BeforeBuild">
<GetAssemblyIdentity AssemblyFiles="[Path.To.Target.File]">
<Output TaskParameter="Assemblies" ItemName="AsmInfo" />
</GetAssemblyIdentity>
<CreateProperty Value="%(AsmInfo.Version)">
<Output TaskParameter="Value" PropertyName="BuildVersion" />
</CreateProperty>
<CreateProperty Value="$(DefineConstants)">
<Output TaskParameter="Value" PropertyName="DefineConstantsOriginal" />
</CreateProperty>
<CreateProperty Value="$(DefineConstants);BuildVersion=$(BuildVersion)">
<Output TaskParameter="Value" PropertyName="DefineConstants" />
</CreateProperty>
</Target>
<Target Name="AfterBuild">
<CreateProperty Value="$(DefineConstantsOriginal)">
<Output TaskParameter="Value" PropertyName="DefineConstants" />
</CreateProperty>
</Target>
The BuildVersion property will be passed to candle.exe so you can reference it with the preprocessor variable $(var.BuildVersion). This certainly isn't as clean as keeping it all in the *.wxs file but it's one way of getting the version information into candle so it can be used as a variable in Product/@Version. I'd certainly like to hear any better ways of doing this.
这篇关于从 WiX 设置项目引用在 WiX 库项目中定义的 WixVariable的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!