MSBuild将动态生成的文件复制为项目依赖项的一部分

xoo*_*ofx 18 c# msbuild build-process

我有一个自定义的msbuild任务,它生成一些输出文件到ProjectA的输出目录($(TargetDir)).当前代码是这样的:

<MyCustomTask ...>
   <Output TaskParameter="OutputFiles" ItemName="FileWrites"/>
</MyCustomTask>
Run Code Online (Sandbox Code Playgroud)

ProjectB正在引用ProjectA,但问题是在构建ProjectB时,MyCustomTask生成的文件不会复制到ProjectB的输出目录中.

我们如何使用MSBuild将动态生成的附加文件作为项目依赖项的一部分进行复制?

xoo*_*ofx 13

我终于设法自动执行项目B的副本而无需修改它.IIya离解决方案不远,但事实是我无法静态生成,因为使用MyCustomTask 从项目A生成的文件列表是动态的.在深入研究之后Microsoft.Common.targets,我发现ProjectB将通过调用目标获得项目A的输出列表GetCopyToOutputDirectoryItems.此目标依赖于其AssignTargetPaths自身依赖于目标列表属性AssignTargetPathsDependsOn.

因此,为了生成动态内容并通过标准项目依赖项自动复制此内容,我们需要在两个不同的位置挂钩项目A.

  • AssignTargetPathsDependsOn,因为它是通过间接地称为项目B项目A通过GetCopyToOutputDirectoryItems.并且当被调用时,它也被项目A间接PrepareResource调用.在这里,我们只输出将由项目A生成或由项目B使用的文件列表.AssignTargetPathsDependsOn将调用一个自定义任务MyCustomTaskList,该任务仅负责输出文件列表(但不生成它们),这个文件列表将创建动态"内容" CopyOutputDirectory.
  • BuildDependsOn以实际生成的内容项目A.这将调用MyCustomTask将生成内容.

所有这些都是在ProjectA中设置的:

<!-- In Project A -->

<!-- Task to generate the files -->
<UsingTask TaskName="MyCustomTask" AssemblyFile="$(PathToMyCustomTaskAssembly)"/>

<!-- Task to output the list of generated of files - It doesn't generate the file -->
<UsingTask TaskName="MyCustomTaskList" AssemblyFile="$(PathToMyCustomTaskAssembly)"/>

<!-- 1st PART : When Project A is built, It will generate effectively the files -->
<PropertyGroup>
  <BuildDependsOn>
    MyCustomTaskTarget;
    $(BuildDependsOn);
  </BuildDependsOn>
</PropertyGroup>

<Target Name="MyCustomTaskTarget">
  <!-- Call MyCustomTask generate the files files that will be generated by MyCustomTask -->
  <MyCustomTask
      ProjectDirectory="$(ProjectDir)"
      IntermediateDirectory="$(IntermediateOutputPath)"
      Files="@(MyCustomFiles)"
      RootNamespace="$(RootNamespace)"
      >
  </MyCustomTask>
</Target>

<!-- 2nd PART : When Project B is built, It will call GetCopyToOutputDirectoryItems on ProjectA so we need to generate this list when it is called  -->
<!-- For this we need to override AssignTargetPathsDependsOn in order to generate the list of files -->
<!-- as GetCopyToOutputDirectoryItems  ultimately depends on AssignTargetPathsDependsOn -->
<!-- Content need to be generated before AssignTargets, because AssignTargets will prepare all files to be copied later by GetCopyToOutputDirectoryItems -->
<!-- This part is also called from ProjectA when target 'PrepareResources' is called -->
<PropertyGroup>
  <AssignTargetPathsDependsOn>
    $(AssignTargetPathsDependsOn);
    MyCustomTaskListTarget;
  </AssignTargetPathsDependsOn>
</PropertyGroup>

<Target Name="MyCustomTaskListTarget">

  <!-- Call MyCustomTaskList generating the list of files that will be generated by MyCustomTask -->
  <MyCustomTaskList
      ProjectDirectory="$(ProjectDir)"
      IntermediateDirectory="$(IntermediateOutputPath)"
      Files="@(MyCustomFiles)"
      RootNamespace="$(RootNamespace)"
      >
      <Output TaskParameter="ContentFiles" ItemName="MyCustomContent"/>
  </MyCustomTaskList>

  <ItemGroup>
    <!--Generate the lsit of content generated by MyCustomTask -->
    <Content Include="@(MyCustomContent)" KeepMetadata="Link;CopyToOutputDirectory"/>
  </ItemGroup>
</Target>
Run Code Online (Sandbox Code Playgroud)

此方法适用于使用Common.Targets的任何C#项目(因此它与纯桌面,WinRT XAML应用程序或Windows Phone 8项目一起使用).