MSBuild - 比较 ItemGroups 元数据

2024-02-13

我正在尝试为我们的源树编写构建脚本。该树由(大量)解决方案组成,它们之间具有程序集引用。我创建了一个包含所有解决方案的 ItemGroup,并对该 ItemGroup 进行批处理以构建解决方案。

我也需要复制some项目输出到“exes 输出”文件夹,每个文件夹都在自己的文件夹中。我已将一些元数据附加到解决方案项,指向我想要从中获取输出的项目。由于每个解决方案可能会输出多个项目,因此我通过向元数据提供传递给 ItemGroup 的 Include 的值来单独创建一个 ItemGroup 来实现这一点。这工作得很愉快,我能够对这个动态创建的 ItemGroup 进行批处理。

我想做的最后一步,这让我头疼,是some在这些输出项目中,我想指定一个特殊的文件夹名称。现在,我可以通过更改正在执行工作的目标内的元数据来做到这一点,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
         DefaultTargets="Build">

  <!-- Define all the solutions to build, and any projects we want to handle the output of -->
  <ItemGroup>

    <SolutionsToBuild Include="$(MSBuildProjectDirectory)\Solution1\Solution1.sln">
      <ProjectsToOutput>
        $(MSBuildProjectDirectory)\Solution1\Project1A\Project1A.csproj;
        $(MSBuildProjectDirectory)\Solution1\Project1B\Project1B.csproj;
      </ProjectsToOutput>
    </SolutionsToBuild>
    <SolutionsToBuild Include="$(MSBuildProjectDirectory)\Solution2\Solution2.sln">
      <ProjectsToOutput>
        $(MSBuildProjectDirectory)\Solution2\Project2A\Project2A.csproj;
        $(MSBuildProjectDirectory)\Solution2\Project2B\Project2B.csproj;
      </ProjectsToOutput>
    </SolutionsToBuild>

  </ItemGroup>

  <Target Name="Build">

    <CallTarget Targets="DoBuild" />

  </Target>

  <Target Name="DoBuild" Outputs="%(SolutionsToBuild.Identity)">

    <Message Text="Building project: %(SolutionsToBuild.FullPath)" />
    <!-- e.g. <MSBuild Projects="%(SolutionsToBuild.FullPath)" /> -->

    <PropertyGroup>
      <ProjectsToOutputIncludeMask>%(SolutionsToBuild.ProjectsToOutput)</ProjectsToOutputIncludeMask>
    </PropertyGroup>

    <ItemGroup>
      <OutputProjects Include="$(ProjectsToOutputIncludeMask)" />

      <!-- Now create the OutputTo metadata -->
      <!-- Default to the same name as the project file -->
      <OutputProjects>
        <OutputTo>%(OutputProjects.FileName)</OutputTo>
      </OutputProjects>

      <!-- Now override specific projects OutputTo metadata -->
      <OutputProjects Condition="'%(OutputProjects.FileName)' == 'Project1A'">
        <OutputTo>ArbitraryFolder1</OutputTo>
      </OutputProjects>
      <OutputProjects Condition="'%(OutputProjects.FileName)' == 'Project2B'">
        <OutputTo>ArbitraryFolder2</OutputTo>
      </OutputProjects>

    </ItemGroup>

    <Message Text=" Outputting project: %(OutputProjects.FullPath) -> %(OutputTo)" />

  </Target>      
</Project>

然而,这个构建脚本需要由团队中的所有开发人员维护,并非所有人都熟悉 MSBuild。因此,我想在脚本顶部定义另一个 ItemGroup 来定义任何特殊名称。然后,他们可以忽略所有目标和任务,只维护 ItemGroup,如下所示:

<ItemGroup>

  <SolutionsToBuild Include="$(MSBuildProjectDirectory)\Solution1\Solution1.sln">
    <ProjectsToOutput>
      $(MSBuildProjectDirectory)\Solution1\Project1A\Project1A.csproj;
      $(MSBuildProjectDirectory)\Solution1\Project1B\Project1B.csproj;
    </ProjectsToOutput>
  </SolutionsToBuild>
  <SolutionsToBuild Include="$(MSBuildProjectDirectory)\Solution2\Solution2.sln">
    <ProjectsToOutput>
      $(MSBuildProjectDirectory)\Solution2\Project2A\Project2A.csproj;
      $(MSBuildProjectDirectory)\Solution2\Project2B\Project2B.csproj;
    </ProjectsToOutput>
  </SolutionsToBuild>

  <OutputNames Include="Project1A">
    <OutputFolder>ArbitraryFolder1</OutputFolder>
  </OutputNames>
  <OutputNames Include="Project2B">
    <OutputFolder>ArbitraryFolder2</OutputFolder>
  </OutputNames>

</ItemGroup>

然而,我尝试让 DoBuild 目标更新元数据的任何方法都失败了。我想我可以这样做:

  <!-- Now override specific projects OutputTo metadata -->
  <OutputProjects Condition="'%(OutputProjects.FileName)' == '%(OutputNames.Identity)'">
    <OutputTo>%(OutputNames.OutputFolder)</OutputTo>
  </OutputProjects>

但是该代码对 OutputProjects 项目组进行批处理,并且then在 OutputNames 项组上,因此条件永远不会为真(比较的参数之一始终为空)。

不幸的是,现阶段我无法更改解决方案结构或输出文件夹结构要求。我缺少的 MSBuild 技巧是否可以在这里帮助我?我并不反对包含自定义任务来完成这项工作,但如果可能的话,我更喜欢直接的 MSBuild 解决方案。

如果有什么区别,我正在使用 MSBuild v4。


啊。偶然发现an一边玩这个一边回答。

首先,我正在调查这个帖子 http://blogs.msdn.com/b/msbuild/archive/2006/05/30/610494.aspx关于获取两个项目组的交集。因此,我将 Output_Names 项目组更改为与输出项目项目组具有相同的标识:

<OutputNames Include="$(MSBuildProjectDirectory)\Solution1\Project1A\Project1A.csproj">
  <OutputFolder>ArbitraryFolder1</OutputFolder>
</OutputNames>
<OutputNames Include="$(MSBuildProjectDirectory)\Solution2\Project2B\Project2B.csproj">
  <OutputFolder>ArbitraryFolder2</OutputFolder>
</OutputNames>

这让我可以对 %(Identity) 进行批处理并获得如下交集:

<Message Condition="'%(Identity)' != '' and
         '@(OutputProjects)' != '' and
         '@(OutputNames)' != ''"
         Text="Found a match for %(Identity)" />

但是,当在同一任务中引用 OutputFolder 元数据时,它也成为批处理的一部分,导致以下内容永远不会打印到输出:

<Message Condition="'%(Identity)' != '' and
         '@(OutputProjects)' != '' and
         '@(OutputNames)' != ''"
         Text="Found a match for %(Identity): %(OutputNames.OutputFolder)" />

但是,通过对属性使用转换而不是直接访问,它不会被视为批处理的一部分:

<Message Condition="'%(Identity)' != '' and
         '@(OutputProjects)' != '' and
         '@(OutputNames)' != ''"
         Text="Found a match for %(Identity): @(OutputNames->'%(OutputFolder)')" />

因此,我可以执行以下操作来更新我的元数据:

  <!-- Now override specific projects OutputTo metadata -->
  <OutputProjects Condition="'%(Identity)' != '' AND
                             '@(OutputProjects)' != '' AND
                             '@(OutputNames)' != ''">
    <OutputTo>@(OutputNames->'%(OutputFolder)')</OutputTo>
  </OutputProjects>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MSBuild - 比较 ItemGroups 元数据 的相关文章

随机推荐