MSBuild:比较 ItemGroups 或按索引访问 [英] MSBuild: Compare ItemGroups or access by index

查看:31
本文介绍了MSBuild:比较 ItemGroups 或按索引访问的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

所以我的想法如下:

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

我已经掌握了步骤 1. 和 2.,但是我不确定在阅读它们之后如何处理这些值.

<!-- 这个target的目的是在git信息(commit...)发生变化时更新gitinfo.txt --><目标名称="GetHeaderInfos"BeforeTargets="ClCompile"输出="$(IntDir)\gitinfo.txt"><!-- 获取有关此存储库状态的信息--><GitDescribe><Output TaskParameter="Tag" PropertyName="NewGitTag"/><Output TaskParameter="CommitHash" PropertyName="NewGitCommitHash"/><Output TaskParameter="CommitCount" PropertyName="NewGitCommitCount"/></GitDescribe><!-- 获取当前日期--><时间格式="dd.MM.yyyy"><Output TaskParameter="FormattedTime" PropertyName="NewBuildDate"/></时间><ReadLinesFromFile File="$(IntDir)\gitinfo.txt" Condition="Exists('$(IntDir)\gitinfo.txt')"><Output TaskParameter="Lines" ItemName="Version"/></ReadLinesFromFile><!-- 比较在这里!如何正确地做--><属性组><标签已更改><!-- `$(NewGitTag)` == `$(Version)[0]` --></TagChanged><!-- 其他比较--></PropertyGroup></目标>

这可能是gitinfo.txt

的内容

v4.1.404fe34ab131.07.2016

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

我还没有找到从文件中读取变量后实际访问变量的示例.官方文档 没有提供任何帮助,我也没有在 stackoverflow 或喜欢.

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

解决方案

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

<Version Include="v4.1.4;04fe34ab;1;31.07.2016"/></项目组><属性组><GitTag>v4.1.4</GitTag><GitSHA>04fe34ab</GitSHA><计数>1</计数><日期>31.07.2016</日期></PropertyGroup>

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

只需比较项目

我不知道您为什么要单独比较所有内容,而这同样有效:一次比较整个 ItemGroup.

<属性组><VersionChanged>True</VersionChanged><VersionChanged Condition="'@(Version)' == '$(GitTag);$(GitSHA);$(Count);$(Date)'">False</VersionChanged></PropertyGroup><Message Text="VersionChanged = $(VersionChanged)"/></目标>

批量检查是否有差异

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

<属性组><TagChanged>True</TagChanged><TagChanged Condition="'@(Version->Contains($(GitTag))->Distinct()->Count())' == '2'">False</TagChanged></PropertyGroup><Message Text="TagChanged = $(TagChanged)"/></目标>

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

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

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

<UsingTask TaskName="IndexItemGroup" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" ><参数组><Items Required="true" ParameterType="Microsoft.Build.Framework.ITaskItem[]"/><Index Required="true" ParameterType="System.Int32"/><Item Output="true" ParameterType="Microsoft.Build.Framework.ITaskItem"/></参数组><任务><代码类型=片段"语言=cs"><![CDATA[Item = Items[索引];]]></代码></任务></UsingTask><目标名称="比较3"><IndexItemGroup Items="@(Version)" Index="1"><Output PropertyName="OldGitSHA" TaskParameter="Item"/></IndexItemGroup><属性组><SHAChanged>真</SHAChanged><SHAChanged Condition="'$(GitSHA)' == '$(OldGitSHA)'">False</SHAChanged></PropertyGroup><Message Text="OldGitSHA = $(OldGitSHA),已更改 = $(SHAChanged)"/></目标>

For a C++ project, I want to autogenerate a defs.h file with project definitions, such as the date, git commit, ... to automate the versioning process of my application.

Therefore I am trying to create a MSBuild Target that will extract the latest git tag, git commit, and the current date and save it to a temporary gitinfo.txt file. Another build target will depend on that file and generate a .h file. In order to avoid unnecessary recompiles of my project, the .h file and for that reason the gitinfo.txt file shall only be rewritten, if any of the information has changes.

So my idea is the following:

  1. Calculate git and date info
  2. If available, read in the existing gitinfo.txt
  3. Compare the calculated values to those in the txt file
  4. If anything has changed, rewrite the gitinfo.txt

I've mastered steps 1. and 2., however I am not sure how to process the values after reading them.

<!-- 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>

And this could be the content of gitinfo.txt

v4.1.4
04fe34ab
1
31.07.2016

I am not quite sure how to compare the values now. I need to compare $(NewGitTag) to the first value in the $(Version) version variable, and so on.

I haven't found an example, that actually accesses the variables after reading them from a file. The official documentation provides no help, nor have I found anything on stackoverflow or the likes.

I only know that the $(Version) variable holds a list, and I can batch process it. How can I compare its content to the defined variables $(NewGitTag), $(NewGitCommitHash), $(NewGitCommitCount) and $(NewBuildDate)?

解决方案

Suppose we start with this data:

<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>

Then here are at least 3 ways to achieve comparision (apart from the one mentioned in the comment) and there are probably other ways as well (I'll post them if I can come up with something else):

Just compare the items

I'm not sure why you want to compare everything seperately when this works just as well: compare the whole ItemGroup at once.

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

Batch and check if there's one difference

Each item of Version is compared with e.g. GitTag via batching. The result will be False;False;False;False if there's a difference, else it will be True;False;False;False. Count the distinct elements and if it's 2 it means we got the latter so GitTag did not change. Note this obviousle only works if each of your source items can never have the same value as one of the other items.

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

you can then compare the other items as well and combine the result.

Use an inline task to access items by index

This comes closest to what's in your question, but it does need a bit of inline code.

<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>

这篇关于MSBuild:比较 ItemGroups 或按索引访问的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆