MSBuild:比较ItemGroups或按索引访问

时间:2016-08-01 13:32:11

标签: msbuild

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

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

所以我的想法如下:

  1. 计算git和日期信息
  2. 如果可用,请阅读现有的gitinfo.txt
  3. 将计算值与txt文件中的值进行比较
  4. 如果有任何更改,请重写gitinfo.txt
  5. 我已经掌握了步骤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)进行比较?

1 个答案:

答案 0 :(得分: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>