Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>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 <code>WixVariable</code> element is referenced with the syntax <code>!(wix.VariableName)</code> and you can use variables that have been defined in a referenced library so <code>!(wix.BuildVersion)</code> 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:</p> <p>There are two distinct types of variable that you can reference in a *.wxs file; <em>preprocessor</em> variables and <em>binder</em> (or <em>linker</em>) variables. The former is referenced with the $ syntax, e.g. <code>$(var.VariableName)</code> and the latter is referenced with the ! syntax, e.g. <code>!(bind.FileVersion.FileId)</code>. 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 <code>!(bind.FileVersion.FileId)</code>.</p> <p>Note that a variable declared with the <code>WixVariable</code> 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 <code>!(wix.BuildVersion)</code> will evaluate to so it can't verify that it will yield a valid version. In contrast, you can get away with <code>!(bind.FileVersion.FileId)</code> 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).</p> <p>So you can use <code>!(wix.BuildVersion)</code> 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 <code>!(bind.FileVersion.FileId)</code> 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 <code>GetAssemblyIdentity</code> task and can pass this to WiX via the DefineConstants property. The following targets in your *.wixproj file should do it:</p> <pre class="lang-xml prettyprint-override"><code>&lt;Target Name="BeforeBuild"&gt; &lt;GetAssemblyIdentity AssemblyFiles="[Path.To.Target.File]"&gt; &lt;Output TaskParameter="Assemblies" ItemName="AsmInfo" /&gt; &lt;/GetAssemblyIdentity&gt; &lt;CreateProperty Value="%(AsmInfo.Version)"&gt; &lt;Output TaskParameter="Value" PropertyName="BuildVersion" /&gt; &lt;/CreateProperty&gt; &lt;CreateProperty Value="$(DefineConstants)"&gt; &lt;Output TaskParameter="Value" PropertyName="DefineConstantsOriginal" /&gt; &lt;/CreateProperty&gt; &lt;CreateProperty Value="$(DefineConstants);BuildVersion=$(BuildVersion)"&gt; &lt;Output TaskParameter="Value" PropertyName="DefineConstants" /&gt; &lt;/CreateProperty&gt; &lt;/Target&gt; &lt;Target Name="AfterBuild"&gt; &lt;CreateProperty Value="$(DefineConstantsOriginal)"&gt; &lt;Output TaskParameter="Value" PropertyName="DefineConstants" /&gt; &lt;/CreateProperty&gt; &lt;/Target&gt; </code></pre> <p>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.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload