我正在尝试配置WiX设置和库,以便将库中某个文件的版本用作设置中的Product / @ Version。
背景
在本地定义文件的设置中,这是相对简单的,假设组件项目由WiX项目引用然后配置:
<Component Id="Company.Assembly" Guid="[GUID]">
<File Id="Company.AssemblyFile"
Name="Company.Assembly.dll" KeyPath="yes"
DiskId="1"
Source="$(var.Company.Assembly.TargetPath)" />
</Component>
然后可以将产品版本设置为
<Product Id="[GUID]"
Name="Product Name"
Language="1033"
Version="!(bind.FileVersion.$(var.Company.AssemblyFile
.TargetFileName))"
Manufacturer="Company Name"
UpgradeCode="[GUID]">
问题
因此,将所有组件移至WiX Library项目后,再也无法直接引用!(bind.FileVersion.$(var.Company.AssemblyFile.TargetFileName))
变量。
我尝试在库中配置WixVariable
WixVariable Id="BuildVersion" Value="!(bind.FileVersion.Company.AssemblyFile)"/>
然后从设置中引用
<Product Id="[GUID]"
Name="Product Name"
Language="1033"
Version="!(wix.BuildVersion)"
Manufacturer="Company Name"
UpgradeCode="[GUID]">
没有成功。
在库或设置中是否需要一些额外的步骤或语法才能从设置中访问WixVariable(或某些派生)?
答案 0 :(得分:49)
我经常听到这一点,我认为WiX文档在解释情况方面做得不是很好,所以现在就是这样。简短的回答是你的语法是正确的;使用WixVariable
元素声明的变量使用语法!(wix.VariableName)
引用,并且您可以使用已在引用库中定义的变量,因此!(wix.BuildVersion)
对于您在上面给出的示例是正确的。它不起作用的原因是因为需要在编译阶段验证该值,但是在链接阶段之前不会生成它。所以这是一个很长的答案:
您可以在* .wxs文件中引用两种不同类型的变量; 预处理程序变量和 binder (或链接器)变量。前者用$语法引用,例如$(var.VariableName)
后者被引用!语法,例如!(bind.FileVersion.FileId)
。关键区别很简单:在编译阶段(通过candle.exe)解析预处理器变量,并在链接阶段(通过light.exe)解析binder变量。编译器负责获取源* .wxs文件并将它们编译为* .wixobj文件;它不处理实际的有效负载,因此它无法从链接文件中读取版本信息。然后将* .wixobj文件传递给处理有效负载并创建MSI数据库的链接器。链接器负责从有效负载中收集元数据,这就是它可以为!(bind.FileVersion.FileId)
等变量提供值的原因。
请注意,使用WixVariable
元素声明的变量会被引用!语法所以它是一个binder变量;它将可用于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文件中的以下目标应该执行此操作:
<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>
BuildVersion属性将传递给candle.exe,因此您可以使用预处理器变量$(var.BuildVersion)引用它。这当然不像在* .wxs文件中保存它那样干净,但它是将版本信息转换为蜡烛的一种方式,因此它可以用作Product / @ Version中的变量。我当然希望听到更好的方法。
答案 1 :(得分:1)
使用Heat.exe时遇到了类似的问题,这使我可以覆盖源变量而不会弄乱系统环境变量或其他类似的东西:
"%wix%bin\heat.exe" dir "$(SolutionDir)Web\obj\$(Configuration)\Package" -cg PACKAGEFILES -gg -g1 -sreg -srd -dr DEPLOYFOLDER -var wix.PackageSource="$(SolutionDir)Web\obj\$(Configuration)\Package" -out "$(SolutionDir)WebInstaller\PackageFragment.wxs"
我认为这种语法可用于任何在链接时无法工作的变量声明:
<wix.YOURVAR="VALUE">-in command line/<!(wix.YOURVAR="VALUE")>-in .WXS files
也许在其他地方也很有用。