views:

1716

answers:

7

I'm currently integrating my Wix projects in MSBuild. It is necessary for me to pass multiple values to the Wix project. One value will work (ProductVersion in the sample below).

<Target Name="BuildWixSetups">
    <MSBuild Condition="'%(WixSetups.Identity)'!=''"
       Projects="%(WixSetups.Identity)"
       Targets="Rebuild" Properties="Configuration=Release;OutputPath=$(OutDir);DefineConstants=ProductVersion=%(WixSetups.ISVersion)" ContinueOnError="true"/>
</Target>

However, how do I pass multiple values to the DefineConstants key? I've tried all the 'logical' separators (space, comma, semi-colon, pipe-symbol), but this doesn't work.

Has someone else come across this problem?

Solutions that don't work:

  1. Trying to add a DefineConstants element does not work because DefineConstants needs to be expressed within the Properties attribute.
A: 

I think something like this should work.

 <DefineConstants>DEBUG;TRACE</DefineConstants> 

Check this blog post to see if it can help you out. http://www.sedodream.com/PermaLink,guid,9b1d23aa-6cb2-48cb-a47a-9cef29622676.aspx

Also check this forum post. It solves a similar problem as yours. http://social.msdn.microsoft.com/Forums/en-US/msbuild/thread/3f485bf4-1b00-48bf-b5d0-4b83341ce4a6/

Aamir
This does not work, because DefineConstants needs to be expressed WITHIN the Properties attribute. It does not work as an attribute on its own.
Sardaukar
I have updated the post, please see if it is helpful now.
Aamir
Thanks, but I already read both those articles. Even if the first one works, I still consider it a hack because projects need to be built two times.
Sardaukar
I can't test it myself but after defining this element can't you use it like Properties="DefineConstants=$(DefineConstants)" ?
Aamir
A: 

I've 'solved' it by making my Wix setup no longer dependent on those multiple values. I could not find another way to do it.

Sardaukar
A: 

Why are you specifying DefineContstants=ProductVersion=XXXXXX?

For DefineConstants you are not assigning values, either a constant (like DEBUG or TRACE) is defined or it is not. This property relates to the /define C# compiler switch. What are you really trying to do?

Also I'm not sure what you mean when you say tha my blog post is a "hack" the fact that it was built twice is the whole point.

Sayed Ibrahim Hashimi
Sayed, I actually bought your book because I wanted to understand MSBuild better. I'll get back to your question when I've finished your book ;-)
Sardaukar
@Sardaukar Cool! :)
Sayed Ibrahim Hashimi
+3  A: 

The problem:

The MSBuild task (not MSBuild.exe, the MSBuild task named MSBuild) cannot handle multiple constants used by WIX projects. Normally you would specify the properties in your build script like:

<MSBuild Projects="YourSolution.sln" Properties="Configuration=MyConfig;Platform=x86;DefineConstants=&quot;SOMETHING=1;SOMETHINGELSE=2&quot;" />

What you see however, when looking at the build logs is the MSBuild separates the constants and does not keep the values grouped together like you would expect - similar to:

Task "MSBuild" Global Properties:
Configuration=MyConfig
Platform=x86
DefineConstants="SOMETHING=1
SOMETHINGELSE=2"

So when candle tries to use those constants it typically responds with "error CNDL0150: Undefined preprocessor variable '$(var.SOMETHINGELSE)'. What this means is the MSBuild task is not properly handling properties which contain multiple '=' in the value even when grouped within quotation marks. Without the property value being grouped in quotation marks, they should obviously be treated as separate properties, rather than a single value.

The workaround:

In order to fix this problem, you need to call MSBuild.exe directly and pass those values to it manually.

msbuild.exe /p:Configuration=MyConfig /p:Platform=x86 /p:DefineConstants="SOMETHING=1;SOMETHINGELSE=2" YourSolution.sln

This will get your constants the work the way you want them to, without having to redesign your WiX installation project.

NOTE: If you're only using a single constant you can still use the MSBuild task like so:

<MSBuild Projects="YourSolution.sln" Properties="Configuration=MyConfig;Platform=x86;DefineConstants=&quot;SOMETHING=1&quot;" />
Jeff Winn
A: 

I know MSDN docs are full of errors and sometimes misleading: here is what it says about DefineConstants

Defines conditional compiler constants. Symbol/value pairs are separated by semicolons and are specified by using the following syntax:

symbol1 = value1 ; symbol2 = value2

The property is equivalent to the /define compiler switch.

http://msdn.microsoft.com/en-us/library/bb629394.aspx

According to MSDN, you can 1. define multiple constants and 2. (@Sayed) assign values

HOWEVER I could not get the expected behaviour of this property of the MSBuild task to work as expected and recommend Jeff Winn's workaround, and his post should be marked as the answer.

RyBolt
Done. Thanks for the explanation.
Sardaukar
A: 

A workaround hack.

Assumptions:

  • SomeEnumValue's possible values are EnumValue1 and EnumValue2

In MSBuild:

<DefineConstants>Debug;use_$(SomeEnumValue)</DefineConstants>

In WiX:

<?ifdef $(var.use_EnumValue1) ?>
  ...
<?elseif $(var.use_EnumValue2) ?>
  ...
<?endif?>
donpark
A: 

The following works for me when using an MSBuild task to build a Visual Studio Solution:

<MSBuild Projects="Solution.sln"
         Targets="Rebuild"
         Properties="Configuration=Debug;DefineConstants=DEBUG%3bTRACE" />

The trick is using %3b to escape the ; separator inside the DefineConstants value. I'm not sure if this will work for the = too. They may need to be escaped as %3d or it may not work at all...

There's also a TargetAndPropertyListSeparators attribute on the MSBuild element. I can't find any documentation for it but it might be possible to use it to set a separator other than ;.

Dave