我目前正在将我的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键?我已经尝试了所有'逻辑'分隔符(空格,逗号,分号,管道符号),但这不起作用。
有其他人遇到过这个问题吗?
不起作用的解决方案:
答案 0 :(得分:13)
问题:
MSBuild任务(不是MSBuild.exe,名为MSBuild的MSBuild任务)无法处理WIX项目使用的多个常量。通常,您可以在构建脚本中指定属性,如:
<MSBuild Projects="YourSolution.sln" Properties="Configuration=MyConfig;Platform=x86;DefineConstants="SOMETHING=1;SOMETHINGELSE=2"" />
然而,在查看构建日志时,您看到的是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="SOMETHING=1"" />
答案 1 :(得分:13)
问题在于将名称 - 值对传递给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)))" />
unescaping必须在wixproj文件中完成,但不需要手动编辑文件。只需打开项目的属性,转到Build选项卡,并在其中显示“Define preprocessor variables”,放置:
$([MSBuild]::Unescape($(WixValues)))
即使该框中已有其他变量,这也有效;只需将其与分号一起添加到列表中。
您将在MSBuild日志中看到candle.exe
工具正确接收参数:
candle.exe -dOne=1 -dTwo=2 -dThree=3 -dConfiguration=Release...
答案 2 :(得分:3)
我仍然很难让这个工作,但上面每个答案的peices促成了我的解决方案,所以我想分享。
环境:TFS Build Server 2010 - Powershell调用MSBuild.exe Wix 3.6安装在构建服务器上
目标是将构建版本号和5个目录传递给MSBuild,以便Candle.exe正确接收它们
Build在构建结束时调用命令文件,该命令文件包含调用powershell脚本以构建Wix安装程序的步骤。它传递构建的版本号以及源和输出目录(输出是UNC文件共享引用\ tfsbuildserver ..)
要在Powershell ps1文件中使其正常工作,
任何带空格的文件名都不应附加引号
$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文件中,我们必须unescape(在底部,在其中说取消注释以进行修改)
<Target Name="BeforeBuild">
<CreateProperty Value="$([MSBuild]::Unescape($(DefineConstants)))">
<Output TaskParameter="Value" PropertyName="DefineConstants" />
</CreateProperty>
</Target>
另请注意,在Visual Studio中,我将使用调试设置,并且我可以为这些值设置默认值,在“构建”选项卡中,“定义预处理器变量”
此项目应为空白,因为它将在上面的命令行中传递。
答案 3 :(得分:2)
使用MSBuild任务构建Visual Studio解决方案时,以下内容适用于我:
<MSBuild Projects="Solution.sln"
Targets="Rebuild"
Properties="Configuration=Debug;DefineConstants=DEBUG%3bTRACE" />
诀窍是使用%3b
来转义;
值内的DefineConstants
分隔符。我不确定这是否适用于=
。它们可能需要以%3d
进行转义,否则可能根本不起作用......
MSBuild元素上还有一个TargetAndPropertyListSeparators
属性。我找不到任何文档,但可以使用它来设置;
以外的分隔符。
答案 4 :(得分:2)
您可以将其作为参数传递,而不是常量。代码如下所示:
<MSBuild ...
Properties="ProductVersion=%(WixSetups.ISVersion)" />
现在在WiX项目中添加一个常量:
<DefineConstants>BuildVersion=$(ProductVersion)</DefineConstants>
并在需要的* .wxs文件中使用它:
$(var.BuildVersion)
例如:
<Product Id="*" Name="My Company" Language="1033" Version="$(var.BuildVersion)"... />
这将适用于多个参数。
答案 5 :(得分:1)
我知道MSDN文档中充满了错误,有时会产生误导:这就是它所说的 DefineConstants
定义条件编译器 常量。符号/值对是 用分号隔开并且是 使用以下指定 语法:
symbol1 = value1; symbol2 = value2
该属性相当于 / define compiler switch。
http://msdn.microsoft.com/en-us/library/bb629394.aspx
根据MSDN,您可以1.定义多个常量和2.(@Sayed)赋值
HOWEVER 我无法使MSBuild任务的此属性的预期行为按预期工作,并推荐Jeff Winn的解决方法,并且应将其帖子标记为答案。
答案 6 :(得分:1)
当我将它们包含在.wixproj文件中时(使用Visual Studio 2010),以下行有效。
<PropertyGroup>
<DefineConstants>Const1=Value1;Const2=Value2;Const3=Value3</DefineConstants>
</PropertyGroup>
答案 7 :(得分:0)
我认为这样的事情应该有用。
<DefineConstants>DEBUG;TRACE</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/
答案 8 :(得分:0)
解决方法黑客。
假设:
在MSBuild中:
<DefineConstants>Debug;use_$(SomeEnumValue)</DefineConstants>
在WiX中:
<?ifdef $(var.use_EnumValue1) ?>
...
<?elseif $(var.use_EnumValue2) ?>
...
<?endif?>
答案 9 :(得分:0)
我的解决方案是使用;
以这种方式转义分号:
<MSBuild
Projects="MyApplication.sln"
Properties="DefineConstants=Sources=$(OutputPath)\MyApplication\;Configuration=$(Configuration);OutDir=$(OutputPath)\WiX\"
Targets="Clean;Rebuild"
/>
答案 10 :(得分:-1)
为什么要指定DefineContstants = ProductVersion = XXXXXX?
对于DefineConstants,您没有分配值,或者定义了常量(如DEBUG或TRACE),或者不是。此属性与/define C#编译器开关有关。你真的想做什么?
另外,当你说我的博客帖子是“黑客”时,我不确定你的意思是它建立两次的事实是重点。
Sayed Ibrahim Hashimi
我的书:Inside the Microsoft Build Engine : Using MSBuild and Team Foundation Build
答案 11 :(得分:-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>