MSBuild 或 Roslyn 編譯項目時均支持差量編譯,畢竟爲了性能。我在 每次都要重新編譯?太慢!讓跨平臺的 MSBuild/dotnet build 的 Target 支持差量編譯 一文中介紹瞭如何使一個 Target 支持差量編譯。在那篇文章中我說到差量編譯會導致 Target 不執行;也就是說,如果一個 Target 對後續的編譯會產生影響,那麼一定不能設置爲差量編譯。
不過,真的會寫出一些非常耗時的 Target,但是它會對後續的編譯產生影響。這些 Target 如果要做差量編譯,那麼就不能直接使用原生的差量編譯方案了。本文將介紹如何處理這樣的情況。
我們遇到的問題
SourceFusion 是一個預編譯框架,它在你編譯期間對你的代碼做一些改變。dotnet-campus/SourceFusion: SourceFusion is a pre-compile framework based on Roslyn. It helps you to build high-performance .NET code.。
這意味着,這個耗時的 Target 是會改變後續的編譯的,典型的是 —— 它會在編譯期間增加和刪除幾個源代碼文件。如果完全使用 Target 原生的差量編譯,那麼一旦這個 Target 跳過,那麼也就不會增加和刪除任何源代碼文件了。
解決方案
解決方案是,我們寫一個前置的 Target,這個 Target 支持差量編譯。於是我們可以利用它的差量編譯特性得知當前是否處於差量編譯的狀態。
<Target Name="_WalterlvDemoRebuildingTest" BeforeTargets="WalterlvDemoCoreTarget"
Inputs="$(MSBuildProjectFullPath)" Outputs="$(WalterlvDemoFolder)RebuildingTest.txt">
<PropertyGroup>
<WalterlvDemoRebuildRequired>true</WalterlvDemoRebuildRequired>
</PropertyGroup>
<ItemGroup>
<RebuildingTestLine Include="true" />
</ItemGroup>
<WriteLinesToFile File="$(WalterlvDemoFolder)RebuildingTest.txt" Lines="@(RebuildingTestLine)" Overwrite="True" />
</Target>
上面的 Target 中,_WalterlvDemoRebuildingTest
是我給這個差量編譯測試 Target 取的名字,WalterlvDemoCoreTarget
是那個耗時的 Target。
根據我在 每次都要重新編譯?太慢!讓跨平臺的 MSBuild/dotnet build 的 Target 支持差量編譯 一文中的差量編譯的做法,我使用 $(MSBuildProjectFullPath)
也就是 csproj 文件的改變來決定差量檢測的輸入,用一個臨時的文件 RebuildingTest.txt
來決定差量編譯的輸出。
在這裏,我們一定需要一個文件來輸出,這樣 MSBuild 或者 Roslyn 檢測差量的時候才能正確完成。這樣,爲了得到這個文件,我們實際上需要通過這個 Target 真的寫一個文件出來,所以我們用了 WriteLinesToFile
。
實際上,我們真正需要的是 WalterlvDemoRebuildRequired
這個屬性。我們可以通過這個屬性判斷爲 true
來得知當前並非差量狀態,而是需要重新編譯。
後續使用
對於我們真實的耗時的 Target,則需要檢測這個 WalterlvDemoRebuildRequired
的值,進行不同的處理。
<Target Name="WalterlvDemoCoreTarget" BeforeTargets="CoreCompile">
<PropertyGroup>
<WalterlvDemoRebuildRequired Condition="'$(WalterlvDemoRebuildRequired)' == ''">false</WalterlvDemoRebuildRequired>
</PropertyGroup>
<Exec ConsoleToMSBuild="True" Command="WalterlvDemo.exe -r $(WalterlvDemoRebuildRequired)" />
</Target>
我們在覈心的 Target 裏面判斷 WalterlvDemoRebuildRequired
的值,如果沒有被設置,說明前面的 Target 沒有執行,也就是“被差量”了,我們就可以將之指定爲 false。
這樣,核心的 Target 裏面,也就是 WalterlvDemo.exe 執行參數中,就可以拿到正確的差量狀態了。true
表示正在重新編譯,而 false
表示正在差量編譯。