MSBuild如何将同一任务传递给多个项目

时间:2015-07-22 12:18:41

标签: c# visual-studio-2013 msbuild msbuild-task msbuild-4.0

我想从一个构建文件在多个项目上运行相同的任务,而不必将任务复制到每个项目文件。

我在我的解决方案中获取了所有项目文件:

<ItemGroup>
    <ProjectsToBuild Include="..\Modules\**\*csproj"/>
</ItemGroup>

然后我在每个ProjectToBuild上调用MSBuild任务

<MSBuild Projects ="@(ProjectsToBuild)" 
             Targets="DoStuff"
             ContinueOnError ="false" 
             Properties="Configuration=$(Configuration)">
    <Output ItemName="OutputFiles" TaskParameter="TargetOutputs"/>
</MSBuild>

这不起作用,因为目标必须存在于您正在构建的项目中。

来自MSDN

目标必须出现在所有项目文件中。如果他们不这样做,则会发生构建错误。

有没有办法可以将DoStuff任务传递给传递给MSBuild任务的项目?

3 个答案:

答案 0 :(得分:0)

MSBuild导入元素会有帮助吗?

https://msdn.microsoft.com/en-us/library/92x05xfs.aspx

只需将您的任务放入一个通用任务文件中,然后将其导入每个项目中。

我认为没有办法将你的任务“注入”其他项目。

答案 1 :(得分:0)

正如Wolf5所述,导入一些具有共同目标和/或任务的文件是实现此目的的方法。在我们的项目中,我们有common.targets xml文件,其代码如下:

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
  <!-- Build file for common build targets -->

  <Import Project="$(MSBuildExtensionsPath)/ExtensionPack/4.0/MSBuild.ExtensionPack.VersionNumber.targets" />
  <UsingTask TaskName="MSBuild.ExtensionPack.Compression.Zip" AssemblyFile="$(MSBuildExtensionsPath)/ExtensionPack/4.0/MSBuild.ExtensionPack.dll" />
  <UsingTask TaskName="BuildRevisionTask" AssemblyName="OurMSBuildTasks, Version=1.0.0.0, Culture=neutral, PublicKeyToken=318ab5a03b21183a"/>


  <PropertyGroup>    
    <!-- Set this property to change the branch where the build is working in -->
    <Branch>MAIN</Branch>
  </PropertyGroup>


  <!-- Called after the workspace initialization -->
  <Target Name="AfterinitializeWorkspace">
    <CallTarget Targets="PrintInfo"/>
  </Target>
</Project>

您可以使用和其他语句组合在构建方案中重新出现的一些常见共享构建步骤。然后在对应于特定构建的.proj文件中,您只需引用此common.targets文件,如下所示:

<Import Project="common.targets"/>

并使用共享的公共构建步骤/目标/任务/属性。

答案 2 :(得分:0)

由于这个项目有来自不同时区和地点的几个不同的人,我不想为人们添加另一个要求每次手动更新他们的proj文件。然而,我最终能够做到我想要的。

<Target Name="BuildAll" DependsOnTargets="$(BuildAllDependsOn)"/>

<PropertyGroup>
    <BuildAllDependsOn>UpdateProjects;CoreBuild</BuildAllDependsOn>
</PropertyGroup>

<ItemGroup>
    <ProjectsToBuild Include="$(MSBuildProjectDirectory)\..\MyProjects\**\*csproj" Exclude="$(MSBuildProjectDirectory)\..\MyProjects\**\Team*csproj;$(MSBuildProjectDirectory)\..\MyProjects\**\Image*csproj"/>
</ItemGroup>

<Target Name="CoreBuild">
<Message Text="CoreBuild" />
    <MSBuild Projects ="@(ProjectsToBuild)" 
             Targets ="DoStuff" 
             ContinueOnError ="false" 
             Properties="Configuration=$(Configuration)">
        <Output ItemName="OutputFiles" TaskParameter="TargetOutputs"/>
    </MSBuild>
</Target>

<Target Name="UpdateProjects">
    <Message Text="$(MSBuildProjectDirectory)" />
    <ItemGroup>
      <CSProjects Include="$(MSBuildProjectDirectory)\..\MyProjects\**\*csproj" Exclude="$(MSBuildProjectDirectory)\..\MyProjects\**\Team*csproj;$(MSBuildProjectDirectory)\..\MyProjects\**\Image*csproj" />
    </ItemGroup>
    <Message Text="Updating Projects:[@(CSProjects)]" />
    <UpdateProject ProjectPath="%(CSProjects.Identity)" ImportsPath="$(MSBuildProjectDirectory)\projectImports.Targets" ModuleTargets="$(MSBuildProjectDirectory)\DoStuff.Targets" CommunityTasksPath="$(MSBuildProjectDirectory)" />
 </Target>

<UsingTask
  TaskName="UpdateProject"
  TaskFactory="CodeTaskFactory"
  AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v12.0.dll">
  <ParameterGroup>
      <ProjectPath Required="true" />
      <ImportsPath Required="true" />
      <ModuleTargets Required="true" />
      <CommunityTasksPath Required="true" />
  </ParameterGroup>
  <Task>
      <Reference Include="System.Xml" />
      <Reference Include="System.Xml.Linq" />
      <Using Namespace="System" />
      <Using Namespace="System.Linq" />
      <Using Namespace="System.Xml.Linq" />
      <Code Type="Fragment" Language="cs">
          <![CDATA[
              var document = XDocument.Load(ProjectPath);
              XNamespace ns = "http://schemas.microsoft.com/developer/msbuild/2003";
              var alreadyAdded = document.Descendants(ns + "Target").Any(el => (string)el.Attribute("DependsOnTargets").Value == "DoStuff");
              if (!alreadyAdded)
                  {
                      var importsDoc = XDocument.Load(ImportsPath);
                      importsDoc.Descendants(ns + "Import").FirstOrDefault().Attribute("Project").Value = ModuleTargets;
                      importsDoc.Descendants(ns + "MSBuildCommunityTasksPath").FirstOrDefault().Value = CommunityTasksPath;
                      document.Descendants(ns + "Project").FirstOrDefault().Add(importsDoc.Root.Elements());
                      document.Save(ProjectPath);
                  }
          ]]>
      </Code>
  </Task>
</UsingTask>

我首先调用UpdateProjects,它使用任务的位置更新每个项目文件。我使用代码块(linq to xml)来查找和更新项目文件。如果它已经更新,它不会两次添加相同的东西。然后,我在每个项目文件上调用build,并告诉msbuild添加到每个项目文件的目标名称。