Search code examples
msbuildmsbuild-task

How to invoke the same msbuild target twice with different parameters from within msbuild project file itself


I have the following piece of msbuild code:

  <PropertyGroup>
    <DirA>C:\DirA\</DirA>
    <DirB>C:\DirB\</DirB>
  </PropertyGroup>

  <Target Name="CopyToDirA"
          Condition="Exists('$(DirA)') AND '@(FilesToCopy)' != ''"
          Inputs="@(FilesToCopy)"
          Outputs="@(FilesToCopy -> '$(DirA)%(Filename)%(Extension)')">
    <Copy SourceFiles="@(FilesToCopy)" DestinationFolder="$(DirA)" />
  </Target>

  <Target Name="CopyToDirB"
          Condition="Exists('$(DirB)') AND '@(FilesToCopy)' != ''"
          Inputs="@(FilesToCopy)"
          Outputs="@(FilesToCopy -> '$(DirB)%(Filename)%(Extension)')">
    <Copy SourceFiles="@(FilesToCopy)" DestinationFolder="$(DirB)" />
  </Target>

  <Target Name="CopyFiles" DependsOnTargets="CopyToDirA;CopyToDirB"/>

So invoking the target CopyFiles copies the relevant files to $(DirA) and $(DirB), provided they are not already there and up-to-date.

But the targets CopyToDirA and CopyToDirB look identical except one copies to $(DirA) and the other - to $(DirB). Is it possible to unify them into one target first invoked with $(DirA) and then with $(DirB)?

Thanks.


Solution

  • You should be able to generate an ItemGroup containing the Dirs and then % on that.

    <ItemGroup>
        <Dirs Include="C:\DirA\;C:\DirB\">
    </ItemGroup>
    <Target Name="CopyFiles"
        Condition="Exists('%(Dirs)') AND '@(FilesToCopy)' != ''"
        Inputs="@(FilesToCopy)"
        Outputs="@(FilesToCopy -> '%(Dirs)%(Filename)%(Extension)')">
        <Copy SourceFiles="@(FilesToCopy)" DestinationFolder="%(Dirs)" />
    </Target>
    

    Or you can do 2 explicit calls:

    <Target Name="CopyFiles">
        <MsBuild Projects="$(MSBuildProjectFullPath)" Targets="CopyASetOfFiles" Properties="FilesToCopy=@(FilesToCopy);DestDir=$(DirA)" />
        <MsBuild Projects="$(MSBuildProjectFullPath)" Targets="CopyASetOfFiles" Properties="FilesToCopy=@(FilesToCopy);DestDir=$(DirB)" />
    </Target>
    
    <Target Name="CopyASetOfFiles"
        Condition="Exists('$(DestDir)') AND '@(FilesToCopy)' != ''"
        Inputs="@(FilesToCopy)"
        Outputs="@(FilesToCopy -> '$(DestDir)%(Filename)%(Extension)')">
        <Copy SourceFiles="@(FilesToCopy)" DestinationFolder="$(DestDir)" />
    </Target>
    

    I haven't tested either syntax, but am relatively more confident of the second.

    (The answer, if there is one, is in my Sayed Hashimi book on my desk - you'll have to wait until the first of:

    1. Get the book
    2. I get bored
    3. Sayed finds this post and comes up with a brilliant tested answer)