WIX Heat.exe command parameter -var does not accep

2019-06-19 08:51发布

问题:

I have this WIX command that uses all invariant paths and it doesn't need a system environment (unlike this example http://weblogs.sqlteam.com/mladenp/archive/2010/02/23/WiX-3-Tutorial-Generating-filedirectory-fragments-with-Heat.exe.aspx):

"%wix%bin\heat.exe" dir "$(SolutionDir)Web\obj\$(Configuration)\Package" 
                    -cg PACKAGEFILES -gg -g1 -sreg -srd -dr DEPLOYFOLDER 
                    -var wix.PackageSource="$(SolutionDir)Web\obj\$(Configuration)\Package"
                    -out "$(SolutionDir)WebInstaller\PackageFragment.wxs"

It works great, except on our build server where the solution path has a space in it and this error is thrown:

heat.exe error HEAT5057: The switch '-var' does not allow the spaces from the value. Please remove the spaces in from the value: wix.PackageSource=C:\Build\Builds 1\26e27895ae75b7cb\CADPortal\src\trunk\Web\obj\Debug\Package

I can't change the path and it shouldn't be necessary anyway in my opinion.

My question is: How do I solve this? (I don't even get why WIX is making trouble over a quoted path/string var with a space)

回答1:

To include a variable and its definition using heat, use the following mechanism.

  1. Create an include (myinclude.wxi) file where you define your variable and its value:
<?xml version="1.0" encoding="utf-8"?>
<Include> 
  <?define PackageSource="c:\somePath"?>
</Include>
  1. Create an xsl file (mytransform.xsl) for adding the <?include myinclude.wxi?> to the wxs file:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:wix="http://schemas.microsoft.com/wix/2006/wi">
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

  <xsl:template match="wix:Wix">
    <xsl:copy>
      <xsl:processing-instruction name="include">myInclude.wxi</xsl:processing-instruction>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <!-- Identity transform. -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>
  1. Run heat and specify the -t parameter that points to the transform:

    heat.exe dir "c:\somePath" -cg PACKAGEFILES -gg -g1 -sreg -srd -dr DEPLOYFOLDER -var PackageSource -t mytransform.xsl -out PackageFragment.wxs

This will create the PackageFragment.wxs file as intended, add the include statement using the xsl transform, and use the variable value from the wxi file when compiling the msi (using candle later on).



回答2:

For this cases you can define a prepocessor variable in the Build section of the project properties, in your case PackageSource=Web\obj\$(Configuration)\Package

and reference in the heat call like

"%wix%bin\heat.exe" dir "$(SolutionDir)Web\obj\$(Configuration)\Package"
                   -cg PACKAGEFILES -gg -g1 -sreg -srd -dr DEPLOYFOLDER
                   -var var.PackageSource
                   -out "$(SolutionDir)WebInstaller\PackageFragment.wxs"


回答3:

The -var switch provides the name of a preprocessor variable. Something like var.Foo. Preprocessor variable names cannot contain spaces in them. The value wix.PackageSource=Whatever SolutionDir Expands To\Web\obj\Whatever Configuration Expands To\Package is not a valid name for a preprocessor variable because it has spaces in it. I expect the backslashes will be a problem as well.



回答4:

So I ended up coding some build event code that inserts the necessary definition into the Heat generated file at the top, but under the starting WIX tag. Personally I'm starting to question the power of WIX if you need to do this kind of shenanigans/hacks.

Anyway this is my full build event code for anyone that needs it. (It also finds an invariant path for MSBuild.exe and creates a web package.)

echo off

set THEME_REGKEY=HKLM\Software\Microsoft\MSBuild\4.0
set THEME_REGVAL=MSBuildOverrideTasksPath

REM Check for presence of key first.
reg query %THEME_REGKEY% /v %THEME_REGVAL% 2>nul || (echo No theme name present! & exit /b 1)

REM query the value. pipe it through findstr in order to find the matching line that has the value. only grab token 3 and the remainder of the line. %%b is what we are interested in here.
set THEME_NAME=
for /f "tokens=2,*" %%a in ('reg query %THEME_REGKEY% /v %THEME_REGVAL% ^| findstr %THEME_REGVAL%') do (
    set THEME_NAME=%%b
)

REM Possibly no value set
if not defined THEME_NAME (echo No theme name present! & exit /b 1)

REM replace any spaces with +
set THEME_NAME=%THEME_NAME: =+%

if errorlevel 1 goto BuildEventFailed
%THEME_NAME%MSBuild  "$(SolutionDir)Web\Web.csproj" /t:Build;Package /p:Configuration=$(Configuration)
if errorlevel 1 goto BuildEventFailed

"%wix%bin\heat.exe" dir "$(SolutionDir)Web\obj\$(Configuration)\Package" -cg PACKAGEFILES -gg -g1 -sreg -srd -dr DEPLOYFOLDER -var var.PackageSource -out "$(SolutionDir)WebInstaller\PackageFragment.wxs"

REM FUNC "HeatFix" - This inserts the var. definition in top of the heat generated fragment:
 MOVE /Y "$(SolutionDir)WebInstaller\PackageFragment.wxs" temp.txt
(
  FOR /F "tokens=*" %%A IN (temp.txt) DO (
    ECHO %%A
    IF "%%A" EQU "<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">" (
      ECHO ^<^?define PackageSource^=^"$(SolutionDir)Web\obj\$(Configuration)\Package^"^?^>
    )
  )
) > "$(SolutionDir)WebInstaller\temp.txt"
move /Y "$(SolutionDir)WebInstaller\temp.txt" "$(SolutionDir)WebInstaller\PackageFragment.wxs"
REM END FUNC "HeatFix"

goto BuildEventOK
:BuildEventFailed
echo POSTBUILDSTEP for $(ProjectName) FAILED
exit 1
:BuildEventOK
echo POSTBUILDSTEP for $(ProjectName) COMPLETED OK