14

我目前正在将我的 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 属性中表示。
4

12 回答 12

14

问题:

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"

因此,当蜡烛尝试使用这些常量时,它通常会响应“错误 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;" />
于 2010-04-26T21:24:47.367 回答
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...
于 2010-11-25T19:53:33.973 回答
4

我仍然很难让这个工作,但上面每个答案的部分都有助于我的解决方案,所以我想分享。

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

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

Build 在构建结束时调用一个命令文件,该命令文件包含一个调用 powershell 脚本来构建 Wix 安装程序的步骤。它传入构建的版本号以及源和输出目录(输出是 UNC 文件共享引用 \tfsbuildserver..)

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

  • 使用以双 " 开头的单个 /p:DefineConstants=
  • 编码所有分隔符;作为 %3b
  • = 可以未编码
  • 任何带空格的文件名周围不应有额外的引号

    $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
    
  • 在 wixproj 文件中,我们必须取消转义(在底部,它表示取消注释以进行修改)

      <Target Name="BeforeBuild">
          <CreateProperty Value="$([MSBuild]::Unescape($(DefineConstants)))">
             <Output TaskParameter="Value" PropertyName="DefineConstants" />
          </CreateProperty>
      </Target>
    
  • 另请注意,在 Visual Studio 中,我将使用调试设置,并且可以在“构建”选项卡的“定义预处理器变量”中为这些值设置默认值

  • 在发布设置中,此项应为空白,因为它将在上面的命令行中传递。

于 2012-08-30T15:13:39.737 回答
2

在使用 MSBuild 任务构建 Visual Studio 解决方案时,以下内容适用于我:

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

诀窍是%3b用来转义值;内的分隔符DefineConstants。我不确定这是否也适用=。他们可能需要逃脱,%3d否则它可能根本不起作用......

MSBuild 元素上还有一个TargetAndPropertyListSeparators属性。我找不到任何文档,但可以使用它来设置除;.

于 2010-09-13T06:46:36.603 回答
2

您可以将其作为参数传递,而不是常量。代码将如下所示:

<MSBuild ...
    Properties="ProductVersion=%(WixSetups.ISVersion)" />

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

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

并在需要时在 *.wxs 文件中使用它:

$(var.BuildVersion)

例如:

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

这将适用于多个参数。

于 2012-03-13T15:49:28.673 回答
1

我知道 MSDN 文档充满了错误,有时还具有误导性:这就是它所说的DefineConstants

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

符号 1 = 值 1;符号 2 = 值 2

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

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

根据 MSDN,您可以 1. 定义多个常量和 2. (@Sayed) 赋值

但是,我无法让 MSBuild 任务的此属性的预期行为按预期工作并推荐 Jeff Winn 的解决方法,他的帖子应标记为答案。

于 2010-05-06T15:14:44.380 回答
1

当我将它们包含在 .wixproj 文件中(使用 Visual Studio 2010)时,以下几行有效。

<PropertyGroup>
  <DefineConstants>Const1=Value1;Const2=Value2;Const3=Value3</DefineConstants>
</PropertyGroup>
于 2010-11-09T22:45:53.390 回答
0

我认为这样的事情应该有效。

<DefineConstants>调试;跟踪</DefineConstants> 

查看此博客文章,看看它是否可以帮助您。 http://www.sedodream.com/PermaLink,guid,9b1d23aa-6cb2-48cb-a47a-9cef29622676.aspx

另请查看此论坛帖子。它解决了与您类似的问题。 http://social.msdn.microsoft.com/Forums/en-US/msbuild/thread/3f485bf4-1b00-48bf-b5d0-4b83341ce4a6/

于 2009-02-03T11:00:34.037 回答
0

解决方法黑客。

假设:

  • SomeEnumValue 的可能值为 EnumValue1 和 EnumValue2

在 MSBuild 中:

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

在 WiX 中:

<?ifdef $(var.use_EnumValue1) ?>
  ...
<?elseif $(var.use_EnumValue2) ?>
  ...
<?endif?>
于 2010-07-30T00:47:35.720 回答
0

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

<MSBuild
    Projects="MyApplication.sln"
    Properties="DefineConstants=Sources=$(OutputPath)\MyApplication\&#59;Configuration=$(Configuration)&#59;OutDir=$(OutputPath)\WiX\"
    Targets="Clean;Rebuild"
/>
于 2013-06-05T19:25:52.463 回答
-1

这对我有用,并允许我传入尚未定义键值对的项目。不是最优雅的,但我不是编码员。

msbuild test.proj /p:PassedInProp="ProductVersion=45;rt=669;wewanttoknow=test5"

<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="4.0" DefaultTargets="Test" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
    <test Include="$([MSBuild]::Unescape($(PassedInProp)))" />
  </ItemGroup>
 <Target Name ="Test">
    <CreateItem Include ="$([System.String]::New('%(test.identity)').Split('=')[0])" AdditionalMetadata="value=$([System.String]::New('%(test.identity)').Split('=')[1])">
      <Output TaskParameter="Include" ItemName ="Test2"/>
    </CreateItem>
    <Message Text ="Key: %(test2.identity)  Value: %(test2.value)"/>
  </Target>
</Project>
于 2012-06-22T02:21:33.827 回答
-2

为什么要指定 DefineContstants=ProductVersion=XXXXXX?

对于 DefineConstants,您没有分配值,要么定义了常量(如 DEBUG 或 TRACE),要么没有定义。此属性与/define C# 编译器开关有关。你真正想做什么?

另外,当您说我的博客文章是“黑客”时,我不确定您的意思是什么,因为它被构建了两次,这才是重点。

于 2009-07-01T19:44:52.580 回答