Using Wix to create 32bit and 64bit installers from one .wxs file
Asked Answered
P

2

33

I would like to keep my top level .wxs DRY while building 32 and 64 bit installers. I am using the -arch argument to candle.exe to control what default installer architecture is getting built.

The wall I am hitting right now is that it appears the ProgramFilesFolder is different between 32 and 64bit (ProgramFiles64Folder) architectures. Here is my first attempt to work around:

<?if $(sys.BUILDARCH)=x64 ?>
<Directory Id='ProgramFiles64Folder' Name='PFiles'>
<?else ?>
<Directory Id='ProgramFilesFolder' Name='PFiles'>
<?endif ?>
    <Directory Id='the-rest' Name="Company Name">
...

I tried this with an error. Apparently the XML validation is fired before the preprocessor is evaluated. When I manually change to use ProgramFiles64Folder my build works.

I tried to go down the DirectoryRef route without success. Any suggestions on getting this to work without doing a sed replace within the .wxs file?

Note: I tried this in Wix 3.5 and 3.6.

Penile answered 3/6, 2011 at 19:49 Comment(1)
I use the technique described in this answer: https://mcmap.net/q/104220/-wix-tricks-and-tips/…Etui
A
54

Rather than conditionally including the opening Directory elements (which invalidates the XML), conditionally set preprocessor variables which are used as directory names, as @Daniel Pratt's comment refers to. Similarly, having a "yes/no" variable conditioned on platform makes it easy to set up 64 bit components, registry searches, etc.

Defining the variables

(From this answer)

<?if $(var.Platform) = x64 ?>
  <?define ProductName = "Product Name (64 bit)" ?>
  <?define Win64 = "yes" ?>
  <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
<?else ?>
  <?define ProductName = "Product Name" ?>
  <?define Win64 = "no" ?>
  <?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
<?endif ?>

$(var.Platform) is built-in, but its value is used to define custom variables $(var.ProductName), $(var.Win64) and $(var.PlatformProgramFilesFolder).

Using the variables

You can either use preprocessor <?if directives to test variables' values (as is done with $(var.Platform) when defining the custom variables above) or have the preprocessor insert variables' values into XML attribute or element values. Couple of examples:

32/64-bit components

<Component Id="..." Win64="$(var.Win64)">
   ...
</Component>

This will produce warnings in the Visual Studio WiX editor about $(var.Win64) not being one of the allowable attribute values (yes/no) but these can be safely ignored, because the preprocessor will have substituted an appropriate value by the time the compiler gets hold of it.

32/64 bit Program Files directory

<Directory Id="$(var.PlatformProgramFilesFolder)">
  ...
</Directory>

Update to handle separate 32/64 bit product codes

In response to rharrison33's comment asking how to handle the requirement for different product codes (or pretty much anything) in the 32 and 64 bit installers (assuming you can't/don't want to auto-generate them):

  • Pass separate product codes to candle as preprocessor variables, on the command line or using a response file:
candle <all other flags> -d ProductCode32=<guid1> -d ProductCode64=<guid2>
  • Add a product code as one of your architecture-dependent preprocessor variables, and set it to the appropriate input variable:
    • In the 32-bit <?if ?> branch: <?define ProductCode = "$(var.ProductCode32)" ?>
    • In the 64-bit <?if ?> branch: <?define ProductCode = "$(var.ProductCode64)" ?>
  • Refer to $(var.ProductCode) in Product/@Id.

Made this CW because Daniel's link answers the question and has a lot more great info besides.

Afterdinner answered 3/6, 2011 at 19:49 Comment(8)
That is basically what I did. I now have a config.wxi included where necessary which defines the correct Program Files folder to use for the platform.Penile
But this way will create problems if you are packaging this msi into a burn bundle because there is a requirement that the product codes must be different between the x86 and x64 versions. Can anyone provide a workaround?Liverwurst
@Liverwurst See my edit if you can't simply auto-generate your product codes.Antenatal
What makes <Component Id="..." Win64="$(var.Win64)"> any different from just <Component Id="..."> ? Isn't the default value automatically determined by the platform?Jerky
@Joey Yes, looking at the docs, I think you're right. I have a vague memory of needing to explicitly specify this, but it was a long time ago and I could well be mistaken.Antenatal
var.Platform is not defined unless you're using the Votive .wixproj. sys.BUILDARCH is, though.Airy
With the conditional 64 Bit and 32 Bit installation path you get in trouble on an update, when the user selects an custom installation folder. Look here: #47507233Friedafriedberg
Do I have to set different UpgradeCodes?Hefner
S
9

I had this problem with WiX 3.7. It was a tiny installer and I did not need the flexibility of variables so I hid the closing Directory tag from the parser by wrapping it in the same way as the opening tag:

<?if $(sys.BUILDARCH)=x64?>
    <Directory Id="ProgramFiles64Folder">
<?else?>
    <Directory Id="ProgramFilesFolder">
<?endif?>

...

<?if $(sys.BUILDARCH)=x64?></Directory><?else?></Directory><?endif?>

It's a hack, but it worked for my use case.

Sufi answered 3/12, 2013 at 11:4 Comment(1)
Thanks for sharing, it helps understanding the root cause of the problem. :-)Cryo

© 2022 - 2024 — McMap. All rights reserved.