从一个MsBuild任务传递属性组值到另一个任务

14

如何在一个构建目标中定义的值在其他目标中保持不变?如果 PropertyGroup 不是我应该在此处使用的正确 MsBuild 实体,那么是什么?ReleaseDir 在“Package”目标中正常打印,但在“DoPackage”中为空

<Target Name="Package">
  <PropertyGroup>
    <ReleasesDir>c:\tmp</ReleasesDirBase>
  </PropertyGroup>
  <Message Text="$(ReleaseDir)"/>
  <CallTarget Targets="DoPackage" Condition="!Exists('$(ReleaseDir)')"/>
</Target>

<!-- Do the acutal packaging -->
<Target Name="DoPackage">
  <Message Text="Creating package in '$(ReleaseDir)'"/>
  <Error Condition="'$(ReleaseDir)' == ''" Text="No ReleaseDir defined"/>
  <MakeDir Directories="$(ReleaseDir)"/>
  ...
</Target>
3个回答

23

属性和CallTarget任务存在众所周知的问题。您应该使用DependsOnTargets代替。

<Target Name="Package">
  <PropertyGroup>
    <ReleasesDir>c:\tmp</ReleasesDir>
  </PropertyGroup>
  <Message Text="$(ReleasesDir)"/>
</Target>

<Target Name="PrePackage" DependsOnTargets="Package">
  <CallTarget Targets="DoPackage" Condition="!Exists('$(ReleasesDir)')"/>
</Target>

<!-- Do the actual packaging -->
<Target Name="DoPackage" DependsOnTargets="Package">
  <Message Text="Creating package in '$(ReleasesDir)'"/>
  <Error Condition="'$(ReleasesDir)' == ''" Text="No ReleaseDir defined"/>
  <MakeDir Directories="$(ReleasesDir)"/>
</Target>

我希望只有当ReleaseDir存在时才运行DoPackage(我使用CallTarget中的Condition来实现这一点)。我能否使用DependsOnTarget来实现这个目标? - ripper234
现在我实际阅读了您发布的链接,解决方案很简单 - 我编写了一个名为“DefineProperties”的单独任务,在它完成后属性就被定义了。谢谢。 - ripper234
我有一种感觉,属性在任务完成之前未定义的原因是由于并行执行。MsBuild不保证目标中间状态,因为这样它可以并行执行子目标。 - ripper234
1
在这个例子中,DoPackage目标不需要DependsOnTargets="Package",因为PrePackage目标已经有了DependsOnTargets="Package"。如果您的构建文件需要使用不同的ReleasesDir值运行DoPackage,则删除此额外的DependsOnTargets="Package"可能会很有用。像这样:<Target Name="Package2"> <PropertyGroup> <ReleasesDir>c:\tmp2</ReleasesDir> </PropertyGroup> <Message Text="$(ReleasesDir)"/> </Target><Target Name="PrePackage2" DependsOnTargets="Package2"> <CallTarget Targets="DoPackage" Condition="!Exists('$(ReleasesDir)')"/> </Target> - Joel

1
如果想将属性传递给目标,则可以使用MSBuild任务。这是调用目标多次并传递不同属性值的唯一方法,但它不允许传递项或项组。请参见Julien链接中的comment中的内容。

...[C]再次调用MSBuild目标,这次传递所需的属性。 这将绕过增量构建...,但有许多限制,即您无法传递项,并且必须指定需要传递的属性。

以下是使用MSBuild任务的代码片段:
<Target Name="Package">
  <PropertyGroup>
    <ReleasesDir>c:\tmp</ReleasesDir>
  </PropertyGroup>
  <Message Text="$(ReleaseDir)"/>
  <MSBuild Projects="$(MSBuildProjectFile)" Targets="DoPackage" Properties="ReleaseDir=$(ReleaseDir)" /> 
</Target>

<!-- Do the acutal packaging -->
<Target Name="DoPackage">
  <Message Text="Creating package in '$(ReleaseDir)'"/>
  <Error Condition="'$(ReleaseDir)' == ''" Text="No ReleaseDir defined"/>
  <MakeDir Directories="$(ReleaseDir)"/>
  ...
</Target>

如果您想将目标用作子例程,并且可以使用不同的参数值多次调用该子例程,则此技术非常有用。例如,为多个产品配置调用构建过程。


1

这可能不是解决该问题最干净的方式,但如果仍然希望在构建文件上使用CallTarget,则必须在另一个目标中定义PropertyGroup。以下是解决此奇怪问题的方案。

<Target Name="DebugBuild" DependsOnTargets="DebugBuildProp">
  <CallTarget Targets="CompileSolution"/>
</Target>
<Target Name="DebugBuildProp">
  <PropertyGroup>
    <Configuration>Debug</Configuration>
  </PropertyGroup>
</Target>
<Target Name="CompileSolution">
   <Message Text="$(Configuration)" />
</Target>

如果DeugBuild更新了Configuration的值,CompileSolution仍然不会使用新值。 - makhdumi
@Al-Muhandis 实际上是这样的,我不知道为什么,但如果你在依赖目标上定义属性,所有其他使用 CallTarget 调用的目标都会具有该值。你可以自己试试。 - Hossein Shahdoost

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