如何使用 MSBuild Target(Exec)中的控制檯輸出

我曾經寫過一篇文章 如何創建一個基於命令行工具的跨平臺的 NuGet 工具包,通過編寫一個控制檯程序來參與編譯過程。但是,相比於 基於 Task 的方式,可控制的因素還是太少了。

有沒有什麼辦法能夠讓控制檯程序也能與 MSBuild Target 之間發生更多的信息交換呢?答案是有的,通過捕獲控制檯的輸出!


捕獲控制檯輸出

如果你喜愛閱讀文檔,那麼答案已經不陌生了,在微軟的官方文檔 Exec Task 中就已經提及了屬性 ConsoleToMSBuild。將此屬性設置爲 True,將能夠捕獲控制檯輸出到 MSBuild 中。(不過據說典型的程序員是不愛看文檔的

那麼,捕獲的輸出去了哪裏呢?

我在 如何創建一個基於 MSBuild Task 的跨平臺的 NuGet 工具包 中提到了使用 Output 來將 Task 中的參數輸出出來。而 Exec 也是這麼做的。我們將 ConsoleOutput 輸出出來即可。由於這個屬性不是 ITaskItem[] 類型的,所以我們只能得到字符串屬性,於是只能通過 PropertyName 來接收這樣的輸出。

<Exec ConsoleToMSBuild="True" Command="&quot;$(NuGetWalterlvToolPath)&quot;">
  <Output TaskParameter="ConsoleOutput" PropertyName="OutputOfTheCommand" />
</Exec>

PropertyGroup 轉 ItemGroup

如果你需要的只是一個字符串,那看完上一節就已經夠了。但如果你希望得到的是一組值(例如新增了一組需要編譯的文件),那麼需要得到的是 ItemGroup 中的多個值,而不是 PropertyGroup 中的單個值。(如果不太明白 ItemGroupPropertyGroup 之間的差別,不要緊,可以閱讀 理解 C# 項目 csproj 文件格式的本質和編譯流程。)

MSBuild 還自帶了一個 Task,名爲 CreateItem,就是從一段字符串創建一組 Item。通過下面這段代碼,我們能將上一節捕獲到的屬性轉換成項的集合。

<CreateItem Include="$(OutputOfTheCommand)">
  <Output TaskParameter="Include" ItemName="AdditionalCompile" />
</CreateItem>

這樣,我們便能夠

更加完整的代碼可能更具有參考意義,所以我貼在了下面:

<Project>
  <Target Name="GenerateAdditionalCode" BeforeTargets="CoreCompile">
    <Exec ConsoleToMSBuild="True" Command="&quot;$(NuGetWalterlvToolPath)&quot;">
      <Output TaskParameter="ConsoleOutput" PropertyName="OutputOfTheCommand" />
    </Exec>
  </Target>
  <Target Name="_IncludeGeneratedAdditionalCode" AfterTargets="GenerateAdditionalCode">
    <CreateItem Include="$(OutputOfTheCommand)">
      <Output TaskParameter="Include" ItemName="AdditionalCompile" />
    </CreateItem>
    <ItemGroup>
      <Compile Include="@(AdditionalCompile)" />
    </ItemGroup>
    <Message Text="額外添加的編譯文件:@(AdditionalCompile)" />
  </Target>
</Project>

CreateItem 的轉換分隔符

CreateItem 從屬性或字符串轉到項是根據分隔符來區分的。由於使用 @(Item) 來獲取項時,會得到一個用 ; 分隔的字符串,所以不難想到我們控制檯輸出的字符串使用 ; 分隔即能滿足我們的轉換需求。但事實上這是不行的!

因爲控制檯的轉換,每行是有緩衝區限制的,也就是說單行字數不能過多,否則會自動加換行符——這可能導致我們轉換成的某一項或者多項中間帶了換行符,從而導致錯誤。

於是,建議直接在控制檯程序中使用換行符本身作爲分隔符,這樣便可以去除這樣的限制。因爲 CreateItem 也是支持換行符分隔的。


參考資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章