使用MSBuild将多个值传递给Wix DefineConstants属性

15

我正在将我的Wix项目集成到MSBuild中。对我来说有必要向Wix项目传递多个值。下面的示例中只有一个值会起作用(ProductVersion)。

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

然而,我该如何将多个值传递给DefineConstants键?我尝试了所有“逻辑”分隔符(空格、逗号、分号、管道符),但都不起作用。

有其他人遇到过这个问题吗?

不起作用的解决方案:

  1. 尝试添加DefineConstants元素不起作用,因为DefineConstants需要在Properties属性内表示。
12个回答

15

问题:

MSBuild任务(不是MSBuild.exe,而是名为MSBuild的MSBuild任务)无法处理WIX项目中使用的多个常量。通常,您会在构建脚本中指定属性,如下所示:

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

然而,当查看构建日志时,您会发现MSBuild将常量分开,并没有像您期望的那样将值分组在一起 - 类似于:

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

当Candle尝试使用这些常量时,通常会返回“错误CNDL0150:未定义的预处理器变量'$(var.SOMETHINGELSE)'”。这意味着MSBuild任务没有正确处理包含多个'='的属性值,即使这些值在引号内分组。如果没有将属性值分组在引号中,则它们应该被视为单独的属性,而不是一个单一的值。

解决方法:

为了解决这个问题,您需要直接调用MSBuild.exe并手动传递这些值。

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

这将使您的常量按照您想要的方式工作,而无需重新设计WiX安装项目。

注意:如果您只使用单个常量,则仍可以使用MSBuild任务,如下所示:

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

2
有一种方法可以使用MSBuild任务来完成这个操作,而不是调用exe:https://dev59.com/questions/OnRB5IYBdhLWcg3wz6QJ#4280454 - Rory MacLeod
似乎如果您没有使用MSBuild 4,那么这是一种可行的方法。 - Daniel Powell

14
问题在于将名称-值对传递给MSBuild任务,然后使MSBuild正确解析它们以便可以将其传递到Candle任务。看起来MSBuild可以处理简单名称的列表或单个名称-值对,但不能处理一系列的名称-值对。

我的解决方案是在传递到MSBuild任务时对列表进行转义,在传递到Candle任务时取消转义。

在您的MSBuild文件中,像这样在属性中定义名称-值对:

<PropertyGroup>
    <WixValues>
        One=1;
        Two=2;
        Three=3;
    </WixValues>
</PropertyGroup>

当您调用MSBuild任务时,请转义属性(需要MSBuild 4):

<MSBuild 
    Projects="setup.wixproj"
    Properties="WixValues=$([MSBuild]::Escape($(WixValues)))" />

需要在wixproj文件中进行反转义,但不需要手动编辑该文件。只需打开项目属性,转到“生成”选项卡,在其中说“定义预处理器变量”的位置上写入:

$([MSBuild]::Unescape($(WixValues)))

即使在该框中已经有其他变量,也可以使用分号将此变量添加到列表中。

您将在 MSBuild 日志中看到 candle.exe 工具已正确接收参数:

candle.exe -dOne=1 -dTwo=2 -dThree=3 -dConfiguration=Release...

4

我仍然遇到了很多问题来让这个工作,但是上面每个回答的一部分都对我的解决方案做出了贡献,所以我想分享一下。

环境:TFS Build Server 2010 - Powershell调用MSBuild.exe 在构建服务器上安装了Wix 3.6

目标是将构建版本号和5个目录传递到MSBuild中,以便Candle.exe可以正确地接收它们

构建在最后调用一个命令文件,并且那个命令文件包含调用Powershell脚本来构建Wix安装程序的步骤。它传递了构建的版本号和源目录和输出目录(输出是UNC文件共享引用\tfsbuildserver..)

为了让它工作,在Powershell ps1文件中,

  • use a single /p:DefineConstants= that starts with a double "
  • encode all the seperating ; as %3b
  • the = are ok unencoded
  • there should be no additional quotes around any file names with spaces

    $msbuild = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe"
    
    $options = " /p:Configuration=Release /p:Platform=x64 "
    $options = $options + " /p:DefineConstants="""
    $options = $options + "SolutionDir=" + $SourceDir
    $options = $options + "%3bTFSBuildSourceLanding=" + $OutputLocation + "SharepointWebRoot\Landing"
    $options = $options + "%3bTFSBuildSourceLandingAdmin=" + $OutputLocation + "SharepointWebRoot\LandingAdmin"
    $options = $options + "%3bTFSBuildSourceRegistration=" + $OutputLocation + "Extranet_Registration"
    $options = $options + "%3bTFSBuildSourceGAC=" + $OutputLocation + "GAC"
    $options = $options + "%3bTFSBuildSourceSQL=" + $OutputLocation + "SQL"
    $options = $options + "%3bProductVersion=" + $BuildVersion + """" 
    
    
    $build = $msbuild + " ""EUM WIX\EUM Wix.wixproj"" " + $options + " /t:Build"
    $clean = $msbuild + " ""EUM WIX\EUM Wix.wixproj"" " + $options + " /t:Clean"
    
    
    Write-Host "Building Wix Installer..."
    Invoke-Expression $clean
    Invoke-Expression $build
    
  • Inside the wixproj file, we have to unescape (down at the bottom, where it says to uncomment to modify)

      <Target Name="BeforeBuild">
          <CreateProperty Value="$([MSBuild]::Unescape($(DefineConstants)))">
             <Output TaskParameter="Value" PropertyName="DefineConstants" />
          </CreateProperty>
      </Target>
    
  • Also note that in Visual Studio, I will use the debug settings, and I can have defaults set for these values, in the Build Tab, "Define preprocessor Variables"

  • in the Release settings this item should be blank as it will get passed in on the command line above.


2
您可以将它作为参数传递,而不是常量。代码将如下所示:
<MSBuild ...
    Properties="ProductVersion=%(WixSetups.ISVersion)" />

现在在WiX项目中添加一个常量:

<DefineConstants>BuildVersion=$(ProductVersion)</DefineConstants>

然后在需要的*.wxs文件中使用它:

$(var.BuildVersion)

例如:
<Product Id="*" Name="My Company" Language="1033" Version="$(var.BuildVersion)"... />

这将适用于多个参数。

2
当我使用MSBuild任务构建Visual Studio解决方案时,以下内容对我有用:
<MSBuild Projects="Solution.sln"
         Targets="Rebuild"
         Properties="Configuration=Debug;DefineConstants=DEBUG%3bTRACE" />

使用%3b来转义DefineConstants值内部的分号分隔符,这是一个技巧。我不确定对于=是否也适用。它们可能需要被转义为%3d,或者根本无法工作...
在MSBuild元素上还有一个TargetAndPropertyListSeparators属性。我找不到任何关于它的文档,但可能可以使用它来设置其他分隔符而不是;

1
这在传递简单名称(如“debug”和“trace”)时有效,但在想要传递名称-值对(如“config=debug;log=trace”)时无效。 - Rory MacLeod

1
以下代码行在我将它们包含在.wixproj文件中时工作正常(使用Visual Studio 2010)。
<PropertyGroup>
  <DefineConstants>Const1=Value1;Const2=Value2;Const3=Value3</DefineConstants>
</PropertyGroup>

1

我知道MSDN文档中充满了错误,有时会误导人:以下是它对DefineConstants的解释:

定义条件编译常量。符号/值对由分号分隔,并使用以下语法指定:

symbol1 = value1 ; symbol2 = value2

该属性等同于/define编译器开关。

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

根据MSDN,您可以1.定义多个常量和2.(@Sayed)分配值。
然而,我无法获得此MSBuild任务属性的预期行为,并建议使用Jeff Winn的解决方法,他的帖子应该标记为答案。

0

1
这样做是不起作用的,因为DefineConstants需要在Properties属性内表达。它不能作为单独的属性工作。 - Sardaukar
谢谢,但我已经阅读了这两篇文章。即使第一篇有效,我仍然认为它是一种hack,因为项目需要构建两次。 - Sardaukar
我自己无法测试,但是在定义了这个元素之后,您不能像Properties="DefineConstants=$(DefineConstants)"一样使用它吗? - Aamir

0

一个解决方案的hack。

假设:

  • SomeEnumValue可能的取值为EnumValue1和EnumValue2

在MSBuild中:

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

在WiX中:
<?ifdef $(var.use_EnumValue1) ?>
  ...
<?elseif $(var.use_EnumValue2) ?>
  ...
<?endif?>

0

我的解决方案是使用&#59;转义分号,就像这样:

<MSBuild
    Projects="MyApplication.sln"
    Properties="DefineConstants=Sources=$(OutputPath)\MyApplication\&#59;Configuration=$(Configuration)&#59;OutDir=$(OutputPath)\WiX\"
    Targets="Clean;Rebuild"
/>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接