Question

How do I keep values defined in one build target alive in other targert? If PropertyGroup is not the write MsBuild entity I should use here, what is? ReleaseDir is printed ok in "Package" target, but is empty in "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>
Was it helpful?

Solution

There is a well known issue with properties and the CallTarget task. You should use DependsOnTargets instead.

<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>

OTHER TIPS

It might not be the cleanest way to solve this problem, but if some one still wants to use CallTarget on the build file, he/she must define the PropertyGroup in another Target, the following is the solution to this weird problem.

<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>

If one wants to pass a property to a target, the MSBuild task can be useful. This is the only way to call a target multiple times with different property values, but it does not allow passing in items or item groups. See this comment in the thread that Julien links to.

...[C]all the MSBuild target on it again, this time passing in the required properties. This bypasses incremental building ..., but has many limitations, namely you can't pass in items and you must specify which properties that need to get passed.

Here is what your code snippet would look like using the MSBuild task:

<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>

This technique is useful if you want to use the target as a subroutine, which you can call multiple times with different parameter values. For example, to call a build process for several product configurations.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top