从WiX设置项目引用WiX库项目中定义的WixVariable

时间:2011-12-06 13:43:54

标签: wix wix3.5

我正在尝试配置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(或某些派生)?

2 个答案:

答案 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

也许在其他地方也很有用。