问题
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.
回答1:
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:
- Get the book
- I get bored
- Sayed finds this post and comes up with a brilliant tested answer)
回答2:
As someone already mentiond the answer is batching.
Here are some links:
- MSBuild Batching Part 1
- MSBuild Batching Part 2
- MSBuild Batching Part 3
- MSBuild RE: Enforcing the Build Agent in a Team Build
回答3:
Yes, what you want is called batching in MSBuild. The
;%(Dirs.Identity)
Defined in the Outputs will cause this task to be executed for each item in the Dirs ItemGroup.
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="CopyFiles"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
ToolsVersion="3.5">
<ItemGroup>
<Dirs Include="C:\DirA" />
<Dirs Include="C:\DirB" />
</ItemGroup>
<Target Name="CopyFiles"
Inputs="@(FilesToCopy);@(Dirs)"
Outputs="@(FilesToCopy -> '%(Dirs.Identity)%(Filename)%(Extension)');%(Dirs.Identity)" >
<Message Text="%(Dirs.Identity)" />
</Target>
</Project>
Outputs:
Build started 8/19/2009 10:11:57 PM.
Project "D:\temp\test.proj" on node 0 (default targets).
C:\DirA
CopyFiles:
C:\DirB
Done Building Project "D:\temp\test.proj" (default targets).
Change the Message task to Copy task with the following condition and you are done:
Condition="Exists('%(Dirs.Identity)') AND '@(FilesToCopy)' != ''"
来源:https://stackoverflow.com/questions/1294147/how-to-invoke-the-same-msbuild-target-twice-with-different-parameters-from-withi