I\'m trying to set the preprocessor variable in wix and i\'m unable to find an example of this or explanation on how to do it anywhere on the internet, i\'m hoping somebody
I have a very large installer kit to build in Visual Studio 2013 (includes some tools related to the main project, a windows service and a web application with a non-trivial directory structure). I'm still learning how to use WiX, and am still crafting, testing and refining the WiX project. Currently, I have the harvest tasks set up as build events, using a command of the form
"C:\Program Files (x86)\WiX Toolset v3.9\bin\heat.exe" dir "$(SolutionDir)\MyProjectDir\bin\$(ConfigurationName)" -cg MyComponentRef -ag -dr MYINSTALLDIR -srd -wixvar -var var.MySourceFiles -sreg -out "$(SolutionDir)\Deployment\My Installer Project\ComponentList.wxs" -t "$(SolutionDir)\Deployment\My Installer Project\FileFilter.xslt"
This command just grabs all the files in the project's bin\Debug (or bin\Release) folder, then filters it using an xml stylesheet transform. There are quite a few harvests to gather like this, so maintaining all the source file variables (the "var.MySourceFiles" argument in the command) was becoming tedious and error prone. Initially, I had added the declarations to the project's preprocessor variables, but I wanted something that was a little more "self-contained". Using the helpful tips I found at WiX tricks and tips, I declared a new include file, "PreprocessorVars.wxi" with content
and got the xslt to include it in the output generated by heat.exe with the snippet
<xsl:processing-instruction name="include">
$(sys.CURRENTDIR)\PreprocessorVars.wxi
</xsl:processing-instruction>
The xslt now produces output that looks something like this:
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:wix="http://schemas.microsoft.com/wix/2006/wi">
<?include
$(sys.CURRENTDIR)\PreprocessorVars.wxi
?>
<Fragment>
<DirectoryRef Id="MYINSTALLDIR" />
</Fragment>
<Fragment>
<ComponentGroup Id="MyComponentRef">
<Component Id="xyz" Directory="MYINSTALLDIR" Guid="*">
<File Id="abc" KeyPath="yes" Source="$(var.MySourceFiles)\MyProjectExecutable.exe" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>
which Wix processes without any errors.
I found out what it was, after 1 day of trying various things, the link above is correct but to use the var in the heatdirectory task you have to do it like this.
<HarvestDirectory Include="$(ProjectDirectory)\" >
<DirectoryRefId>WEBDIR</DirectoryRefId>
<KeepEmptyDirectories>true</KeepEmptyDirectories>
<SuppressRegistry>true</SuppressRegistry>
<ComponentGroupName>DynamicWebFiles</ComponentGroupName>
<PreprocessorVariable>var.WixDynamicSourceDirectory</PreprocessorVariable>
</HarvestDirectory>
PreprocessorVariable for heat really need more doc and example... I've spend lots of time making it work too. This is how it works in my wixproj file:
<PropertyGroup>
<DefineConstants Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">HarvestPath=..\distribution\Debug</DefineConstants>
<DefineConstants Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">HarvestPath=..\distribution\Release</DefineConstants>
</PropertyGroup>
<Target Name="BeforeBuild">
<HeatDirectory Directory="..\distribution\$(Configuration)"
PreprocessorVariable="var.HarvestPath"
OutputFile="HeatGeneratedFileList.wxs"
ComponentGroupName="HeatGenerated"
DirectoryRefId="INSTALLFOLDER"
AutogenerateGuids="true"
ToolPath="$(WixToolPath)"
SuppressFragments="true"
SuppressRegistry="true"
SuppressRootDirectory="true"/>
</Target>
All you need is to define the variable. There is no magical "HeatDefinitions" :)
I use Wix v3.10.
No need to explicitly call HeatDirectory MSBuild Task. ItemGroup with special name "HarvestDirectory" can be prepared, and later the "HarvestDirectory" target will process it. *.wsx file is created in the IntermediateOutputPath and is included in Compile list (processed by Candle).
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
...
<MyFinalFolder Condition=" '$(MyFinalFolder)' == '' ">$(MSBuildProjectDirectory)\Final\</MyFinalFolder>
<DefineConstants>FinalFolder=$(MyFinalFolder)</DefineConstants>
</PropertyGroup>
...
<Import Project="$(WixTargetsPath)" />
<Target Name="BeforeBuild">
<!--
No need to explicitly call HeatDirectory MSBuild Task.
Instead follow documentation http://wixtoolset.org/documentation/manual/v3/msbuild/target_reference/harvestdirectory.html, which has sample and
important comment:
This target is processed before compilation. Generated authoring is automatically added to the Compile item group to be compiled by the Candle task.
So, *.wsx file created in the IntermediateOutputPath and included in Compile list (processed by Candle).
The following ItemGroup with special name "HarvestDirectory" can be prepared, and later the "HarvestDirectory" target will process it, see
C:\Program Files (x86)\MSBuild\Microsoft\WiX\v3.x\wix2010.targets
-->
<ItemGroup>
<HarvestDirectory Include="$(MyFinalFolder)">
<DirectoryRefId>INSTALLFOLDER</DirectoryRefId>
<SuppressRootDirectory>true</SuppressRootDirectory>
<SuppressCom>true</SuppressCom>
<SuppressRegistry>true</SuppressRegistry>
<ComponentGroupName>FilesComponentGroup</ComponentGroupName>
<PreprocessorVariable>var.FinalFolder</PreprocessorVariable>
</HarvestDirectory>
</ItemGroup>
</Target>
The wxs file:
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<DirectoryRef Id="INSTALLFOLDER">
<Component Id="cmp9AA09F4A73FA53E2BDDE4B7BB5C91DFB" Guid="*">
<File Id="fil9AA09F4A73FA53E2BDDE4B7BB5C91DFB" KeyPath="yes" Source="$(var.FinalFolder)\7z.dll" />
</Component>
There is a $(HeatDefinitions)
property you can set to define these in the parent .wixproj file:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<HeatDefinitions>MySourcePath=..\src\Your.App\bin\Release</HeatDefinitions>
</PropertyGroup>
<ItemGroup>
<Compile Include="Phoenix.wxs" />
<Compile Include="_HeatGeneratedFileList.wxs" />
</ItemGroup>
<Target Name="BeforeBuild">
<HeatDirectory Directory="..\src\Your.App\bin\Release"
OutputFile="_HeatGeneratedFileList.wxs"
PreprocessorVariable="var.MySourcePath" />
</Target>
</Project>
The only existing mention of this magic property I can find (on the entire Internet) is in a single question about Team Build on the wix-users mailing list. I stumbled across it by luck after spending nearly a day tearing out my hair trying to fix undefined preprocessor variable errors.
I created an example project on GitHub showing how to successfully use the HarvestDirectory target, which is a higher-level thing that calls the HeatDirectory task. You don't need to directly call the HeatDirectory task yourself. You can see all of the example code here:
https://github.com/DavidEGrayson/wix-example-harvest-directory
Here are the most important parts:
foo.wixproj
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProductVersion>1.0.0</ProductVersion>
<DefineConstants>ProductVersion=$(ProductVersion);ItemDir=items</DefineConstants>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProjectGuid>27e80d9b-d8b6-423a-a6ff-1d9c5b23bb31</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName>foo-$(ProductVersion)</OutputName>
<OutputType>Package</OutputType>
<DefineSolutionProperties>false</DefineSolutionProperties>
<WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<OutputPath>bin\$(Configuration)\</OutputPath>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
<DefineConstants>Debug;ProductVersion=$(ProductVersion)</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<OutputPath>bin\$(Configuration)\</OutputPath>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="foo.wxs" />
<HarvestDirectory Include="items">
<DirectoryRefId>ItemDir</DirectoryRefId>
<ComponentGroupName>Items</ComponentGroupName>
<PreprocessorVariable>var.ItemDir</PreprocessorVariable>
</HarvestDirectory>
<WixExtension Include="WixUIExtension" />
</ItemGroup>
<Import Project="$(WixTargetsPath)" />
</Project>
foo.wxs
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Name="Foo"
Version="$(var.ProductVersion)"
Manufacturer="Foo Inc."
Language="1033"
UpgradeCode="0c8504c9-4e62-4e2c-9e1c-4fbe1c478b37"
Id="*">
<Package Description="Foo"
Manufacturer="Foo Inc."
Compressed="yes"
InstallerVersion="301" />
<MajorUpgrade AllowDowngrades="no"
DowngradeErrorMessage="A newer version of this software is already installed."
AllowSameVersionUpgrades="no" />
<Media Id="1" Cabinet="cabinet.cab" EmbedCab="yes" />
<Property Id="ARPCOMMENTS">
Foo package.
</Property>
<Property Id="ARPCONTACT">Foo Inc.</Property>
<Property Id="ARPURLINFOABOUT">https://www.example.com/</Property>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder" Name="PFiles">
<Directory Id="INSTALLDIR" Name="Foo">
<Component Id="readme">
<File Id="readme" Name="README.txt" Source="README.txt" />
</Component>
<Directory Id="ItemDir" />
</Directory>
</Directory>
</Directory>
<Feature Id="Software"
Title="Foo"
AllowAdvertise="no"
ConfigurableDirectory="INSTALLDIR">
<ComponentRef Id="readme" />
<ComponentGroupRef Id="Items" />
</Feature>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
<UIRef Id="WixUI_InstallDir" />
</Product>
</Wix>