2016-08-01 84 views
1

對於C++項目,我想自動生成defs.h文件,其中包含日期,git commit等項目定義以自動執行應用程序的版本控制過程。MSBuild:比較ItemGroups或按索引訪問

因此,我正在嘗試創建一個MSBuild目標,它將提取最新的git標記,git commit和當前日期,並將其保存到臨時文件gitinfo.txt。 另一個構建目標將取決於該文件並生成一個.h文件。 爲了避免不必要的重新編譯我的項目,.h文件,因此只有在任何信息發生變化時纔會重寫gitinfo.txt文件。

所以我的想法是這樣的:

  1. 計算Git和日期信息
  2. 如果有的話,在現有的gitinfo.txt
  3. 讀取比較計算值與在txt文件
  4. 如果什麼都改變了,重寫了gitinfo.txt

我已經掌握了步驟s 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)進行比較?

+0

另一種方法:寫git的信息和日期到一個文件中,比較使用Exec的任務調用窗口的FC.EXE和使用它的返回值來決定,如果這些文件是相等的這些文件,如果沒有複製文件。就像這裏:https://github.com/micropython/micropython/blob/master/windows/msvc/genhdr.targets#L94 – stijn

+0

是的,這將是一種有效的方式。我會嘗試。但是,我真的很想知道它是如何實現的,也是爲了將來的使用情況。 – kiki

+0

好的,看答案。也許可以編輯你的問題/標題,以便未來的訪問者更容易發現它:基本上是'如何通過索引訪問來自ItemGroup的項目',甚至只是'如何比較ItemGroups'。也可以讓它更小:你只需從一個ItemGroup和一堆項目開始,然後你想比較它們。無論這些項目是來自文件還是來自GitDescribe都無關緊要,並且由於不是每個人都有GitDescribe,因此測試代碼變得更加困難。 – stijn

回答

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

第一個建議非常有用,它是我最終使用的建議。關於第二個問題,如果一切都改變了,那麼它會是「真的;真的;真的;真的」,因此它會被錯誤地標記爲「沒有改變」? 至於第三個,我不知道它會非常複雜,但至少我明白它是如何使用的。 – kiki

+0

第二個只比較GitTag版本,所以只能返回True; True; True; True如果以某種方式版本將等於「v4.1.4; v4.1.4; v4.1.4; v4.1.4」 – stijn