MSBuild 如何将相同的任务传递给多个项目
MSBuild How to pass same task to multiple projects
我想 运行 从一个构建文件在多个项目上执行相同的任务,而不必将任务复制到每个项目文件。
我正在获取我的解决方案中的所有项目文件并且:
<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 任务中的项目?
MSBuild 导入元素有帮助吗?
https://msdn.microsoft.com/en-us/library/92x05xfs.aspx
只需将您的任务放入一个通用任务文件中,然后将其导入到您的每个项目中。
我认为没有任何方法可以 "inject" 您的任务到其他项目中。
正如 Wolf5 所述,导入一些具有共同目标 and/or 任务的文件是执行此操作的方法。在我们的项目中,我们有 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"/>
并使用共享公共构建 steps/targets/tasks/properties。
由于这个项目有来自不同时区和地点的几个不同的人,我不想添加另一个要求让人们每次都手动更新他们的 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) 来查找和更新项目文件。如果它已经被更新,它不会添加相同的东西两次。然后我在每个项目文件上调用构建并告诉 msbuild 添加到每个项目文件的目标的名称。
我想 运行 从一个构建文件在多个项目上执行相同的任务,而不必将任务复制到每个项目文件。
我正在获取我的解决方案中的所有项目文件并且:
<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 任务中的项目?
MSBuild 导入元素有帮助吗?
https://msdn.microsoft.com/en-us/library/92x05xfs.aspx
只需将您的任务放入一个通用任务文件中,然后将其导入到您的每个项目中。
我认为没有任何方法可以 "inject" 您的任务到其他项目中。
正如 Wolf5 所述,导入一些具有共同目标 and/or 任务的文件是执行此操作的方法。在我们的项目中,我们有 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"/>
并使用共享公共构建 steps/targets/tasks/properties。
由于这个项目有来自不同时区和地点的几个不同的人,我不想添加另一个要求让人们每次都手动更新他们的 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) 来查找和更新项目文件。如果它已经被更新,它不会添加相同的东西两次。然后我在每个项目文件上调用构建并告诉 msbuild 添加到每个项目文件的目标的名称。