denalisk
denalisk

Reputation: 193

How to set 'env' preprocessor variables in .wixproj file

With the wix toolset, environment variables are accessible in the .wxs file via the env preprocessor prefix, such as

$(env.TestEnvVariable)

I've configured our build pipeline to set the environment variables I need, and the msi builds fine. However, you can no longer build the .msi locally, because none of the variables are defined in the local development environment.

I'm using the wix extension for visual studio, and I've been trying to update my .wixproj files to set properties like so:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" InitialTargets="EnsureWixToolsetInstalled" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" xmlns:fg="http://www.firegiant.com/schemas/v3/wxs/fgwep.xsd">

  <!-- ... some other bits -->

  <PropertyGroup>
    <TestEnvVariable>TestValue</TestEnvVariable>
  </PropertyGroup>

</Project>

But when I try and build the msi, I get the error

Undefined preprocessor variable '$(env.TestEnvVariable)'

Additionally, I get the same error when trying to access the variable with the 'var' prefix:

Undefined preprocessor variable '$(var.TestEnvVariable)'

I understand that you can set 'var' style preprocessor variables using the define constant element

<PropertyGroup>
  <DefineConstants>SomeOtherVariable=someValue</DefineConstants>
</PropertyGroup>

But in our hosted pipelines we are setting these variables as environment variables, because that is easily surfaced in what we're using (azure devops). I could convert all those 'env' variables to 'var' via redefining them all, but that seems unnecessarily complicated, and I would like to maintain their distinction as environment variables. My goal is to allow local dev builds to use the same variable structure, just set them conditionally on configuration=Debug or something.

Is there no better way to set 'env' preprocessor variables for local dev other than conditionally running a batch file to set TestEnvVariable=TestValue?

Upvotes: 3

Views: 2986

Answers (2)

Christopher Painter
Christopher Painter

Reputation: 55581

Please take a look at the source code to IsWiX. You'll find an example of pulling the environment variable TF_BUILD_BUILDNUMBER and using it to set the ProductVersion.

The concept is to set an MSBuild property, pass it through to the compiler as a constant and then use it in the Product Version attribute.

https://github.com/iswix-llc/iswix-tutorials/blob/master/windows-service/Installer/WindowsService/WindowsService.wixproj

Lines 14,21,27

https://github.com/iswix-llc/iswix-tutorials/blob/master/windows-service/Installer/WindowsService/Code/Product.wxs

Line 11

Upvotes: 1

denalisk
denalisk

Reputation: 193

Alright after a bit of sleeping on it and kicking around, here's the solution that I came to: The main issue that I was encountering was not fully grasping where Environment variables were pulled from by wix, and how that interacted with the MSBuild steps in the .wixproj file.

The solution is to create a custom MSBuild task to set environment variables locally during the build. You can create a custom build task .dll for this, or use the technique described in this answer for more current versions of MSBuild: https://stackoverflow.com/a/20014410/11908758

Basically, in the Project element in your .wixproj you need to define the custom task:

<UsingTask
  TaskName="SetEnvironmentVariableTask"
  TaskFactory="CodeTaskFactory"
  AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
  <ParameterGroup>
    <Name ParameterType="System.String" Required="true" />
    <Value ParameterType="System.String" Required="true" />
  </ParameterGroup>
  <Task>
    <Using Namespace="System" />
    <Code Type="Fragment" Language="cs">
      <![CDATA[
      Environment.SetEnvironmentVariable(Name, Value);
    ]]>
    </Code>
  </Task>
</UsingTask>

Then, inside the BeforeBuild target, use it to set the environment variables based on a condition that will only be true for local debug builds. Note that this task will only set the variable for the Target the task is called in, and the task will not work outside of a Target element :

<Target Name="BeforeBuild">
    <!-- Set environment variables for debug build-->
    <SetEnvironmentVariableTask Condition="'$(Configuration)'=='Debug'" Name="MyEnvironmentVariable" Value="Value_for_debug_installer" />
</Target>

Then, you can access it in your .wxs files somewhere and not get the pre-processor error:

<Property Id="PROP_MyProperty" Value="$(env.MyEnvironmentVariable)" />

Upvotes: 1

Related Questions