如何从msbuild项目文件本身中使用不同参数调用同一msbuild目标两次

如何从msbuild项目文件本身中使用不同参数调用同一msbuild目标两次,msbuild,msbuild-task,Msbuild,Msbuild Task,我有以下一段msbuild代码: <PropertyGroup> <DirA>C:\DirA\</DirA> <DirB>C:\DirB\</DirB> </PropertyGroup> <Target Name="CopyToDirA" Condition="Exists('$(DirA)') AND '@(FilesToCopy)' != ''"

我有以下一段msbuild代码:

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

C:\DirA\
C:\DirB\
因此,调用目标
CopyFiles
会将相关文件复制到
$(DirA)
$(DirB)
,前提是这些文件尚未存在且是最新的

但是目标
CopyToDirA
CopyToDirB
看起来相同,除了一个复制到
$(DirA)
和另一个复制到
$(DirB)
。是否可以将它们统一到一个目标中,首先使用
$(DirA)
调用,然后使用
$(DirB)
调用


谢谢。

您应该能够生成一个包含目录的项目组,然后在该项目组上生成%

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

或者,您可以执行两个显式调用:

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

这两种语法我都没有测试过,但我对第二种语法相对比较有信心

(答案,如果有的话,在我桌上的Sayed Hashimi书中——你必须等到第一个:

  • 拿到书
  • 我觉得无聊
  • Sayed找到了这篇文章,并给出了一个精彩的答案)

  • 是的,您需要的是在MSBuild中称为批处理。

    ;%(Dirs.Identity)
    
    在输出中定义的将导致对Dirs项目组中的每个项目执行此任务

    <?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>
    
    将消息任务更改为具有以下条件的复制任务,即完成:

    Condition="Exists('%(Dirs.Identity)') AND '@(FilesToCopy)' != ''"
    

    正如有人已经提到的,答案是批处理

    以下是一些链接:


    你好,鲁本。你能把。。。在你的回答中?我对参数化目标不太熟悉,无法理解您的意思。谢谢。@mark:好了。我以前没做这件事的原因有两个。手头没有好的编辑。2.不确定第一个示例的语法。希望这有帮助。强烈推荐内部MSBuild书籍我认为解决方案2存在问题。如果使用命令行中的特定属性调用生成脚本,则在使用任务时不会传递这些属性。我已将
    $(MSBuildProjectFile)
    替换为
    $(MSBuildProjectFullPath)
    为了更清楚地说明CopyFiles目标正在派生另一个MSBuild来调用正下方的
    目标
    ,因此(除非有
    初始目标
    ),将运行的唯一目标是
    CopyASetOfFiles
    ,它只需要传递两个
    属性
    (即
    FilesToCopy
    DestDir
    )。对我来说,解决这个问题的关键是
    BuildInParallel=“true”
    %
    -对
    目录进行批处理,使其可并行化。希望你同意我的推理,我没有遗漏任何东西!@Pete:解决方案2的主要问题是,如果唯一关心的是复制文件和/或做任何可以在
    目标
    中批处理的事情,那就没有意义了e需要进行复制和粘贴,并稍微修改
    目标
    或fork另一个MSBuild比我们想象的要少得多,即#1更为惯用:D
    Condition="Exists('%(Dirs.Identity)') AND '@(FilesToCopy)' != ''"