【问题标题】:MSBuild: Compare ItemGroups or access by indexMSBuild:比较 ItemGroups 或按索引访问
【发布时间】:2016-08-04 15:14:07
【问题描述】:

对于 C++ 项目,我想自动生成一个带有项目定义的 defs.h 文件,例如日期、git commit 等,以自动化我的应用程序的版本控制过程。

因此,我正在尝试创建一个 MSBuild 目标,它将提取最新的 git 标记、git 提交和当前日期,并将其保存到一个临时的 gitinfo.txt 文件中。 另一个构建目标将依赖于该文件并生成一个 .h 文件。 为了避免对我的项目进行不必要的重新编译,.h 文件和 gitinfo.txt 文件只有在任何信息发生更改时才会被重写。

所以我的想法如下:

  1. 计算 git 和日期信息
  2. 如果可用,请阅读现有的gitinfo.txt
  3. 将计算值与 txt 文件中的值进行比较
  4. 如果有任何变化,请重写gitinfo.txt

我已经掌握了第 1 步和第 2 步,但是我不确定如何在阅读后处理这些值。

<!-- The purpose of this target is to update gitinfo.txt if git information (commit...) has changed -->
<Target
  Name="GetHeaderInfos"
  BeforeTargets="ClCompile"
  Outputs="$(IntDir)\gitinfo.txt"
>

  <!-- Get information about the state of this repo-->    
  <GitDescribe>
    <Output TaskParameter="Tag" PropertyName="NewGitTag" />
    <Output TaskParameter="CommitHash" PropertyName="NewGitCommitHash" />
    <Output TaskParameter="CommitCount" PropertyName="NewGitCommitCount" />
  </GitDescribe>

  <!-- Get the current date -->
  <Time Format="dd.MM.yyyy">
    <Output TaskParameter="FormattedTime" PropertyName="NewBuildDate" />
  </Time>

  <ReadLinesFromFile File="$(IntDir)\gitinfo.txt" Condition="Exists('$(IntDir)\gitinfo.txt')">
    <Output TaskParameter="Lines" ItemName="Version" />
  </ReadLinesFromFile> 

  <!-- Comparison here! HOW TO DO IT PROPERLY -->
  <PropertyGroup>
     <TagChanged> <!-- `$(NewGitTag)` == `$(Version)[0]` --> </TagChanged>
     <!-- Other comparisons -->
  </PropertyGroup>
</Target>

这可能是gitinfo.txt的内容

v4.1.4
04fe34ab
1
31.07.2016

我现在不太确定如何比较这些值。我需要将$(NewGitTag)$(Version) 版本变量中的第一个值进行比较,依此类推。

我还没有找到一个示例,它实际上是在从文件中读取变量后访问它们。 official documentation 没有提供任何帮助,我也没有在 stackoverflow 等上找到任何东西。

我只知道$(Version)这个变量有一个列表,我可以批量处理。如何将其内容与定义的变量 $(NewGitTag)$(NewGitCommitHash)$(NewGitCommitCount)$(NewBuildDate) 进行比较?

【问题讨论】:

  • 另一种方法:将 git 信息和日期写入文件,使用 Exec 任务比较这些文件以调用窗口的 fc.exe 并使用它的返回值来确定文件是否相等,如果不复制文件.像这里的东西:github.com/micropython/micropython/blob/master/windows/msvc/…
  • 是的,这将是一种有效的方式。我会试试。但是,我真的很想知道它是如何实现的,也适用于未来的用例。
  • 好的,看答案。也许编辑您的问题/标题,以便将来的访问者更容易发现它:基本上它是“如何通过索引访问 ItemGroup 中的项目”,甚至只是“如何比较 ItemGroups”。也可能让它变得更小:你只需从一个 ItemGroup 和一堆项目开始,然后你想比较它们。这些项目是来自文件还是来自 GitDescribe 无关紧要,而且由于并非每个人都有 GitDescribe,因此测试代码变得更加困难。

标签: msbuild


【解决方案1】:

假设我们从这个数据开始:

<ItemGroup>
  <Version Include="v4.1.4;04fe34ab;1;31.07.2016"/>
</ItemGroup>

<PropertyGroup>
  <GitTag>v4.1.4</GitTag>
  <GitSHA>04fe34ab</GitSHA>
  <Count>1</Count>
  <Date>31.07.2016</Date>
</PropertyGroup>

那么这里是至少 3种实现比较的方法(除了评论中提到的一种),可能还有其他方法(如果我能想出的话,我会发布它们别的东西):

只需比较项目

我不知道你为什么要单独比较所有内容,而这同样适用:一次比较整个 ItemGroup。

<Target Name="Compare1">
  <PropertyGroup>
    <VersionChanged>True</VersionChanged>
    <VersionChanged Condition="'@(Version)' == '$(GitTag);$(GitSHA);$(Count);$(Date)'">False</VersionChanged>
  </PropertyGroup>
  <Message Text="VersionChanged = $(VersionChanged)" />
</Target>

批量检查是否有区别

版本的每个项目都与例如比较GitTag 通过批处理。如果有差异,结果将为False;False;False;False,否则为True;False;False;False。计算不同的元素,如果它是 2,则意味着我们得到了后者,所以 GitTag 没有改变。请注意,仅当您的每个源项目永远不能与其他项目之一具有相同的值时,这个明显的才有效。

<Target Name="Compare2">
  <PropertyGroup>
    <TagChanged>True</TagChanged>
    <TagChanged Condition="'@(Version->Contains($(GitTag))->Distinct()->Count())' == '2'">False</TagChanged>
  </PropertyGroup>
  <Message Text="TagChanged = $(TagChanged)" />
</Target>

然后您也可以比较其他项目并合并结果。

使用内联任务按索引访问项目

这与您的问题最接近,但确实需要一些内联代码。

<UsingTask TaskName="IndexItemGroup" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >
  <ParameterGroup>
    <Items Required="true" ParameterType="Microsoft.Build.Framework.ITaskItem[]"/>
    <Index Required="true" ParameterType="System.Int32"/>
    <Item Output="true" ParameterType="Microsoft.Build.Framework.ITaskItem"/>
  </ParameterGroup>
  <Task>
    <Code Type="Fragment" Language="cs">
      <![CDATA[Item = Items[ Index ];]]>
    </Code>
  </Task>
</UsingTask>

<Target Name="Compare3">
  <IndexItemGroup Items="@(Version)" Index="1">
    <Output PropertyName="OldGitSHA" TaskParameter="Item"/>
  </IndexItemGroup>

  <PropertyGroup>
    <SHAChanged>True</SHAChanged>
    <SHAChanged Condition="'$(GitSHA)' == '$(OldGitSHA)'">False</SHAChanged>
  </PropertyGroup>

  <Message Text="OldGitSHA = $(OldGitSHA), changed = $(SHAChanged)" />
</Target>

【讨论】:

  • 第一个建议非常有用,这是我最终使用的。关于第二个,如果一切都发生了变化,那么它将是True;True;True;True,因此它会被错误地标记为“未更改”?至于第三个,我不知道它会这么复杂,但至少我知道它是如何使用的。
  • 第二个仅将 GitTag 与 Version 进行比较,因此只能返回 True;True;True;True 如果以某种方式 Version 等于 "v4.1.4;v4.1.4;v4.1.4;v4. 1.4"
猜你喜欢
  • 2011-06-19
  • 1970-01-01
  • 2016-08-31
  • 2020-04-15
  • 2016-11-23
  • 1970-01-01
  • 2015-12-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多