Running target before CoreBuild?

I am adding a custom template generation template .tt

for my project to run before CoreBuild

and there seem to be two ways to do this:

<Project...>
    <Target Name="TransformOnBuild" AfterTargets="BeforeBuild">
</Project>

      

and

<Project...>
    <Target Name="TransformOnBuild" BeforeTargets="CoreBuild">
</Project>

      

If my target is to be launched before my project is built, since the project relies on it, would it be better if I used the latter? I've seen the first use things like generating text templates, but this seems like an unreliable way of doing it because it might start after CoreBuild

, which is too late. Or is there some reason it AfterTargets="BeforeBuild"

is still guaranteed to run before the kernel is built?

I have also seen BeforeTargets="BeforeBuild"

to be built even earlier. Is this the best place to put the .tt text generation target?

+3


source to share


3 answers


From Microsoft.Common.CurrentVersion.targets the build target is basically:

<BuildDependsOn>
  BeforeBuild;
  CoreBuild;
  AfterBuild
</BuildDependsOn>
<Target Name="Build" DependsOnTargets="$(BuildDependsOn)"/>

<PropertyGroup>
  <CoreBuildDependsOn>
    PrepareForBuild;
    PreBuildEvent;
    ...
    Compile;
    ...
    PostBuildEvent
  </CoreBuildDependsOn>
</PropertyGroup>
<Target Name="CoreBuild" DependsOnTargets="$(CoreBuildDependsOn)">

      



Thus, the use BeforeTargets="CoreBuild"

will be performed before CoreBuild, but these are all depending on it, therefore after all the real build steps. This is usually not what you want, instead if you want to run something before compiling, etc., use BeforeTargets="PrepareForBuild"

either really AfterTargets="BeforeBuild"

or even BeforeTargets="BeforeBuild"

.

+2


source


Based on @ stjin answer, a good solution seems to be using

BeforeTargets="CoreCompile" DependsOnTargets="PrepareForBuild"

      

this is what the .net sdk (new csproj style for .net core / standard projects) does to automatically generate AssemblyInfo.cs .



He uses the following comment to explain why:

Note that this must be done before every call to CoreCompile to ensure that all compiler runs see the generated assembly information. There is at least one Xaml-enabled script where CoreCompile is called without other potential hooks like Compile or CoreBuild, etc., so we are connecting directly to CoreCompile. Also, we have to work after PrepareForBuild to make sure the staging directory is created.

Note that in this case the "staging directory" ( obj/[TargetFramework]

) is where the output file is placed in this case .cs

, which might also be what you might want to do.

+2


source


Update 2

Based on documentation from Microsoft :

This is the Build Target Order

  • The InitialTargets tasks are running.
  • Targets specified on the command line with / target are launched. If you do not specify any targets on the command line, the DefaultTargets targets will be executed. If none of these are present, the first target encountered is executed.
  • The Condition attribute of the target is evaluated. If the Condition attribute is present and evaluates to false, the target is not executed and does not affect the assembly.
  • DependsOnTargets targets are executed before the target is executed.
  • Any target that lists it in the BeforeTargets attribute runs before the target is executed.
  • The Inputs and Outputs attribute is compared before the goal is executed. If MSBuild determines that any output files are out of date relative to the corresponding input file or files, then MSBuild fulfills the target. Otherwise MSBuild misses the target.
  • After a target is completed or skipped, any target that lists it in the AfterTargets attribute is fired.

Here are the answers to your questions:

If my target is to be launched before my project is built, since the project relies on it, would it be better if I used the latter?

  • No, because all CoreBuild dependencies will run before the template is assigned, and it will be too late.

Or is there some reason why AfterTargets = "BeforeBuild" is still guaranteed to run before the kernel is built?

  • AfterTargets = "BeforeBuild" ensures that your target is completed on time because it will be completed before all CoreBuild dependencies.

I've also seen BeforeTargets = "BeforeBuild" being built even earlier. This is the best place to put the .tt text generation target.

  • In both cases, AfterTargets = "BeforeBuild" or BeforeTargets = "BeforeBuild" your target will be executed before all CoreBuild dependencies, however, in both cases, you can still influence the results of your target template generation depending on what you have to do in BeforeBuild. Once you have this under control, you can safely use any of these options.

Running target before CoreBuild?

> there appear to be 2 ways of doing it.

    There are more options to achieve this. Please review below.

      


For this purpose, you should use specific built-in objects (BeforeBuild or AfterBuild). It is a mechanism provided by Microsoft to safely extend the build process when using projects that depend on Microsoft.Common.targets

If you only have one target to run before CoreBuild, you can do this:

<Target Name="BeforeBuild">
    <!-- add your tasks here -->
</Target>

      

If you have multiple targets to run before CoreBuild, you can define a property with all targets to be called in the order of execution you want:

<PropertyGroup>
    <BeforeBuildDependsOn>
      CustomTarget1;
      CustomTarget2;
      CustomTarget3
    </BeforeBuildDependsOn>
</PropertyGroup>

<Target Name="BeforeBuild" DependsOnTargets="$(BeforeBuildDependsOn)"/>

      

UPDATE:

Based on the snippet provided by @stijn:

AfterTargets = "BeforeBuild" will insert / execute a custom target like this: (depends on BeforeBuild

<BuildDependsOn>
  BeforeBuild;
       |-> Custom Target


  CoreBuild;
  AfterBuild
</BuildDependsOn>

      

BeforeTargets = "CoreBuild" will insert / execute custom style (depends on CoreBuild):

<BuildDependsOn>
  BeforeBuild;


       |-> Custom Target
  CoreBuild;
  AfterBuild
</BuildDependsOn>

      

This way the "template creation target" will run in the same place (between BeforeBuild and CoreBuild, but depending on different targets, so a suitable target should be inline or PreBuild dependent.

Now, referring to the third party comment, PreBuild / AfterBuild targets are for end users, third party vendors should implement their scripts without affecting the main workflow. These are some of the options that a third party should use to avoid disrupting the regular flow:

Considering this as a basis:

<PropertyGroup>
    <BuildDependsOn>
      BeforeBuild;
      CoreBuild;
      AfterBuild
    </BuildDependsOn>
</PropertyGroup>

<Target Name="Build" DependsOnTargets="$(BuildDependsOn)"/>

      

Option 1: . This will cause the custom third party script to be loaded before BeforeBuild without affecting the default BuildDependsOn sequence which still allows the end user to target BeforeBuild.

<PropertyGroup>
    <BuildDependsOn>
      MyCustomThirdParty;
      $(BuildDependsOn);
    </BuildDependsOn>
</PropertyGroup>

<PropertyGroup>
    <MyCustomThirdPartyDependsOn>
      BeforeMyCustomThirdParty;
      CustomStep1;
      CustomStep2;
      CustomStep1;
      AfterMyCustomThirdParty
    </MyCustomThirdPartyDependsOn>
</PropertyGroup>

<Target Name="MyCustomThirdParty" DependsOnTargets="$(MyCustomThirdPartyDependsOn)"/>

      

Option 2: If a third party script needs to be executed after the BeforeBuild target, it can be done like this:

<PropertyGroup>
    <BuildDependsOn>
      BeforeBuild;
      MyCustomThirdParty;
      CoreBuild;
      AfterBuild
    </BuildDependsOn>
</PropertyGroup>

      

NOTE. For this to work correctly, you must add PropertyGroup and Targets AFTER importing Microsoft.CSharp.targets.

This way you will be able to use multiple third party scripts according to the overall workflow.

Obviously, you can use a combination of these options depending on your situation. But you must follow these general rules:

  • Respect the default workflow (BeforeBuild, CoreBuild, AfterBuild).
  • Include before / after targets for a third party script so that the end user can enter anything before or after the third party script is executed.

This should be considered if you are using the default Visual Studio build scripts (projects such as .csproj, .vbproj, etc.). If you are using your own scripts for other languages ​​or targets, you can use BeforeTargets and AfterTargets wherever you want, but why not follow the guidelines based on existing scripts?

+2


source







All Articles