Passing property group value from one MsBuild task to another
Asked Answered
A

3

14

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>
Algin answered 3/9, 2009 at 12:37 Comment(0)
S
23

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>
Sulphate answered 3/9, 2009 at 12:44 Comment(4)
I would like DoPackage to run only if ReleaseDir exists (I used the Condition in CallTarget to achieve this). Can I achieve this using DependsOnTarget?Algin
Now that I actually read the link you posted, the solution is simple - I wrote a separate task called 'DefineProperties', and after it's finished the properties are ... defined. Thanks.Algin
I have a feeling the reason properties are not defined until a task has finished is because of parallel execution. MsBuild doesn't guarantee anything mid-target because this way it can execute the subtargets in parallel.Algin
In this example the DoPackage Target does not need the DependsOnTargets="Package" because the PrePackage Target already has DependsOnTargets="Package". It might be useful to remove this extra DependsOnTargets="Package" if your build file needs to run DoPackage with different values of ReleasesDir. Like so:<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>Schoolroom
P
1

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.

Pollak answered 27/4, 2015 at 3:51 Comment(0)
P
1

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>
Popp answered 16/10, 2015 at 13:9 Comment(2)
If DeugBuild updates the value of Configuration, CompileSolution still won't use the new value.Brooch
@Al-Muhandis It actually does, I don't know why but if you define the Property on the dependency target all the other targets which you call using CallTarget would have the value. Try it yourselfPopp

© 2022 - 2024 — McMap. All rights reserved.