取消

Write a MSBuild Target to detect whether the project is rebuilding or not

MSBuild or the dotnet build command both supports Incremental Building for compiling performance. You can read How to: Build Incrementally - Visual Studio - Microsoft Docs to lean more about incremental building. When a target supports increment building and the project is rebuilding for the moment, the Target will not execute. So if it affects followed other Targets, it cannot be set to incremental building.

But how can I detect a incremental building behavior and do something different things if my Target affects followed other Targets? In this post, I’ll talk about that.


The Problem

SourceFusion is a pre-compile framework and allows you to change you code during the compiling. You can visit dotnet-campus/SourceFusion: SourceFusion is a pre-compile framework based on Roslyn. It helps you to build high-performance .NET code. to view the open-source project.

The Target in the SourceFusion takes long time and affects followed Targets such as the CoreCompile Target. If it use a completely incremental building, the Target will be skipped when building and no more source code will be added or removed before the CoreCompile Target. So nothing will happen during a incremental building and the SourceFusion changes nothing.

The Solution

We can write another Target helps us to detect rebuilding behavior. We can define a property to tell us whether it is a incremental building or not.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<Target Name="_WalterlvDemoRebuildingTest" BeforeTargets="WalterlvDemoCoreTarget"
        Inputs="$(MSBuildProjectFullPath)" Outputs="$(WalterlvDemoFolder)RebuildingTest.txt">
  <ItemGroup>
    <RebuildingTestLine Include="true" />
  </ItemGroup>
  <CallTarget Targets="_WalterlvDemoRebuildingTestInitialize" />
  <WriteLinesToFile File="$(WalterlvDemoFolder)RebuildingTest.txt" Lines="@(RebuildingTestLine)" Overwrite="True" />
</Target>

<Target Name="_WalterlvDemoRebuildingTestInitialize">
  <PropertyGroup>
    <WalterlvDemoRebuildRequired>true</SourceFusionRebuildRequired>
  </PropertyGroup>
</Target>

In this code, I write two Targets and the second one doesn’t define any BeforeTargets or AfterTargets attributes. So this Target will not be executed automatically unless you call it explicitly. I define a property named SourceFusionRebuildRequired in it to flag the rebuilding status.

I call this separated Target in the first target which defines Inputs and Outputs attributes. We can know that if a Target want to support incremental building the two attributes are important. So this Target supports that.

These are the three mentioned Targets:

  • _WalterlvDemoRebuildingTest The Target that supports the incremental building
  • _WalterlvDemoRebuildingTestInitialize The Target to assign a value to property SourceFusionRebuildRequired
  • WalterlvDemoCoreTarget The long-time Target that will use the incremental building test value

I use a csproj file as a input file and another temp file as a output file. Then if a project file changed and a rebuilding will happen. To generate a temp output file I should use WriteLinesToFile Task to write one.

I need WalterlvDemoRebuildRequired property to detect the rebuilding behavior. If the project is rebuilding the property will be assigned because the _WalterlvDemoRebuildingTestInitialize is called and if the project is incremental building the property will not be assigned.

Then we can check the value of WalterlvDemoRebuildRequired to detect a rebuilding or incremental building.

How to use this property

For the long-time Target WalterlvDemoCoreTarget, it should detect the property and do something different.

1
2
3
4
5
6
<Target Name="WalterlvDemoCoreTarget" BeforeTargets="CoreCompile">
  <PropertyGroup>
    <WalterlvDemoRebuildRequired Condition="'$(WalterlvDemoRebuildRequired)' == ''">false</WalterlvDemoRebuildRequired>
  </PropertyGroup>
  <Exec ConsoleToMSBuild="True" Command="WalterlvDemo.exe -r $(WalterlvDemoRebuildRequired)" />
</Target>

We define the same property only if it is not been assigned. But we assign it as a false value which is different to the _WalterlvDemoRebuildingTestInitialize Target.

Then pass the property value to the core Task, and the Task will know whether it is completely rebuilding or incremental building.


References

本文会经常更新,请阅读原文: https://blog.walterlv.com/post/detecting-rebuild-switch-using-msbuild-target-en.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

知识共享许可协议

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected])

登录 GitHub 账号进行评论