I'm adding a custom .tt
template generation target to my project to run before CoreBuild
, and there appear to be 2 ways of doing it:
<Project...>
<Target Name="TransformOnBuild" AfterTargets="BeforeBuild">
</Project>
and
<Project...>
<Target Name="TransformOnBuild" BeforeTargets="CoreBuild">
</Project>
If my target should run before my project is built, as the project relies on it, would it be better for me to use the latter? I've seen the former used to do things like generate text templates, but it seems like an unreliable way to do it because it might get run after CoreBuild
, which is too late. Or is there some reason why AfterTargets="BeforeBuild"
is still guaranteed to run before the core build?
I've also seen BeforeTargets="BeforeBuild"
which will build even earlier. Is this a better place to put a `.tt text generation target?
Update 2
Based on the documentation from Microsoft:
This is the Target Build Order
These are the answers to your questions:
If my target should run before my project is built, as the project relies on it, would it be better for me to use the latter?
Or is there some reason why AfterTargets="BeforeBuild" is still guaranteed to run before the core build?
I've also seen BeforeTargets="BeforeBuild" which will build even earlier. Is this a better place to put a `.tt text generation target?
Running a target before the CoreBuild?
You should use the specific built in targets (BeforeBuild or AfterBuild) for this purpose. Thisis the mechanism provided by Microsoft to safely extend the build process when using projects that depends on Microsoft.Common.targets
If you have only one target to run before CoreBuild, you can do this:
If you have more than one target to run before CoreBuild, you can define a property with all the targets that needs to be called in the required order of execution:
UPDATE:
Based on the fragment provided by @stijn:
AfterTargets="BeforeBuild" will insert/execute the custom target like this: (Depends on BeforeBuild
BeforeTargets="CoreBuild" will insert/execute the custom like this (Depends on CoreBuild):
So the "template generation target" will be executed in the same place (Between BeforeBuild and CoreBuild, but depending on different targets, that's why the apropriate Target to be used should be BeforeBuild inline or with dependencies.
Now regarding the 3rd party issue comment, the BeforeBuild/AfterBuild targets are intended for final users, the third party providers should implement their scripts without affect the basic workflow. These are some of the options a 3rd party should use to avoid breaking the regular flow:
Considering this as the base:
Option 1: This will inject your custom 3rd party script before BeforeBuild without affect the default BuildDependsOn sequence, that still allows the final user to use the BeforeBuild target without.
Option 2: If the 3rd party script needs to be executed after the BeforeBuild target, this can be done like this:
NOTE: In order for this to work properly, you must add the PropertyGroup and targets AFTER the Microsoft.CSharp.targets import.
This way you will be able to use multiple 3rd party scripts respecting the general workflow.
You can obviously use a combination of these options depending on the situation. But you should follow these general rules:
These should be considered when you are using the default visual studio generated build scripts (Projects like .csproj, .vbproj, etc). If you are implementing your own scripts for other languajes or purposes, you can use BeforeTargets and AfterTargets wherever you want, but why don't you follow the good practices based on the existing scripts?
From Microsoft.Common.CurrentVersion.targets, the Build target is basically:
So using
BeforeTargets="CoreBuild"
will run before CoreBuild indeed, but that is after all it's dependent targets ran, so after all actual build steps. That's usually not what you want, instead if you want to run something before compilation etc, useBeforeTargets="PrepareForBuild"
or indeedAfterTargets="BeforeBuild"
or evenBeforeTargets="BeforeBuild"
.Building on @stjin's answer, a good solution seems to be using
which is what the .net sdk (new-style csproj for .net core / standard projects) is doing for automatic AssemblyInfo.cs generation.
It uses the following comment to explain why:
Note that the "intermediate directory" (
obj/[TargetFramework]
in this case) is where the output.cs
file is placed in this case which may also be what you might want to do.