Determine if MSBuild CoreCompile will start and invoke a custom target

It seems obvious what needs to be done, but I pulled out most of my hair, trying to find any examples on the Internet or do it myself.

I have a C # solution with 19 projects and a Jenkins build server that is building a script to manage MSBuild on. MSBuild, of course, will determine what to do and does not need to compile based on inputs and outputs.

I am trying to create a custom target for conditionally updating AssemblyInfo.cs of those projects that MSBuild is going to compile to increase file versions. Of course, I want to leave projects not compiled alone.

I know how to enter a target before CoreBuild, which starts every time, so if there is some kind of variable that I can check to see if compilation will happen, which might work. I also know how to determine if the compiler ran and therefore conditionally performs some post-processing, which is possible, but not perfect.

How can I customize the build process for this?

Since it seems that there is no direct answer to the question, does anyone know how to follow the same logic as MSBuild to determine which projects need to be restored?

+6
source share
4 answers

In the end, the solution was a combination of the Sayed Ibrahim Hashimi blog entry and the information from the MSDN forum entry 'Complete the goal when the (core) compilation completes' .

I basically used the Sayed injection method so that my goal is to run "extend-corecompile.proj" for all projects without having to edit each proj file, but replaced it with the contents of the override for "CoreCompileDependsOn", which points to a custom target that accepts the same the very inputs and outputs as the purpose of the "CoreCompile". The end result is a goal that runs only when the "CoreCompile" is executed under centralized control in the build script.

Thanks to everyone for their contribution and here is the skeleton code that I used in 'extend-corecompile.proj':

<!--The following property group adds our custom post-target to the post compile call list --> <PropertyGroup> <TargetsTriggeredByCompilation> $(TargetsTriggeredByCompilation); CustomPostTarget </TargetsTriggeredByCompilation> </PropertyGroup> <!--The following property group adds our custom pre-target to CoreCompileDependsOn to ensure it is called before CoreCompile --> <PropertyGroup> <CoreCompileDependsOn> $(CoreCompileDependsOn); CustomPreTarget </CoreCompileDependsOn> </PropertyGroup> <!-- The following custom pre-target has the same inputs and outputs as CoreCompile so that it will only run when CoreCompile runs. Because we have injected this file and Targets are resolved in sequence we know this Target will fire before CoreCompile.--> <Target Name="CustomPreTarget" Inputs="$(MSBuildAllProjects); @(Compile); @(_CoreCompileResourceInputs); $(ApplicationIcon); $(AssemblyOriginatorKeyFile); @(ReferencePath); @(CompiledLicenseFile); @(EmbeddedDocumentation); $(Win32Resource); $(Win32Manifest); @(CustomAdditionalCompileInputs)" Outputs="@(DocFileItem); @(IntermediateAssembly); @(_DebugSymbolsIntermediatePath); $(NonExistentFile); @(CustomAdditionalCompileOutputs)"> <!--Do pre-compilation processing here--> </Target> <!--This target will be called by CoreCompile--> <Target Name="CustomPostTarget" > <!--Do post-compilation processing here--> </Target> 

Not sure what will happen if CoreCompile fails, doesn't it still name our target? I think we will find out over time :)

+9
source

I just wrote the answer to this question http://sedodream.com/2012/07/28/MSBuildHowToExecuteATargetAfterCoreCompilePart2.aspx , but I inserted this solution below.

A few months ago, I wrote an MSBuild blog post about how to complete a task after CoreCompile , in which I describe how you can accomplish a goal, if the goal of CoreCompile is fulfilled, if CoreCompile is skipped, then your other goal. The rollback of the approach that I outlined in a previous post was that it required you to edit the .csproj / .vbproj / etc file yourself. Therefore, if you had a script to create several projects, you will have to edit all the project files. In this post, I describe how you can perform the same setup without editing the project file itself.

Before we get to the solution for this particular case, let me describe the extensibility hook that C # and VB projects have. Most of the logic for building C # and VB projects is captured in the MSBuild targets file in C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ Microsoft.Common.targets. If you look in this file, you will see an import at the top similar to the one below.

 <Import Project="$(CustomBeforeMicrosoftCommonTargets)" Condition="'$(CustomBeforeMicrosoftCommonTargets)' != '' and Exists('$(CustomBeforeMicrosoftCommonTargets)')"/> 

This statement will import the file (located by value for CustomBeforeMicrosoftCommonTargets) if the property is not empty and the file exists. The default value for CustomBeforeMicrosoftCommonTargets is C: \ Program Files (x86) \ MSBuild \ v4.0 \ Custom.Before.Microsoft.Common.targets. Therefore, if you delete the MSBuild file at this location, it will change the build process for each C # / VB project built on this computer. Alternatively, if you do not want (or cannot because of the ACL), you can delete the file elsewhere and then specify its location by overriding the CustomBeforeMicrosoftCommonTargets property. This is the approach that I will take here. I created a sample solution consisting of two projects, ProjA and ProjB. I also have a build script, build.proj to automate the build for this. Below is the full contents of build.proj.

build.proj

 <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <FileToInject Condition=" '$(FileToInject)'=='' ">$(MSBuildThisFileDirectory)extend-corecompile.proj</FileToInject> </PropertyGroup> <ItemGroup> <ProjectsToBuild Include="ProjA\ProjA.csproj"/> <ProjectsToBuild Include="ProjB\ProjB.csproj"/> </ItemGroup> <Target Name="Build"> <MSBuild Projects="@(ProjectsToBuild)" Properties="CustomBeforeMicrosoftCommonTargets=$(FileToInject)" /> </Target> <Target Name="Clean"> <MSBuild Projects="@(ProjectsToBuild)" Targets="Clean"/> </Target> <Target Name="Rebuild" DependsOnTargets="Clean;Build"/> </Project> 

In the Build task above, I use the MSBuild task to create both ProjA and ProjB. As you can see, I am passing the CustomBeforeMicrosoftCommonTargets = $ (FileToInject) property, which points to the extension-corecompile.proj. Passing this property when building ProjA and ProjB, it automatically imports the extend-corecompile.proj file for the build process. Below you can see the contents of extend-corecompile.proj.

extend-corecompile.proj

 <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <TargetsTriggeredByCompilation> $(TargetsTriggeredByCompilation); MyCustomTarget </TargetsTriggeredByCompilation> </PropertyGroup> <Target Name="MyCustomTarget"> <Message Text="MyCustomTarget called" Importance ="high"/> </Target> </Project> 

This project file uses the method described in my previous blog post to execute MyCustomTarget only if CoreCompile is running.

Note. You can get the latest version of this example at https://github.com/sayedihashimi/sayed-samples/tree/master/ExtBuildMultiple .

+6
source

Even if you have a list of projects that need to be compiled, if you update the assemblyinfo.cs of one of them, it can cause a change that starts compiling the other project.

Thus, the easiest way is to generate all AssemblyInfo.cs files according to the revision number of the source code. You can even get the latest version number for each project directory, effectively knowing when the last modification of this project was.

See this question: How can I change AssemblyProduct, AssemblyTitle using MSBuild?

According to your comment, have you looked at BeforeBuild and AfterBuild objects (at the end of your csproj file):

  <Target Name="BeforeBuild"> </Target> <Target Name="AfterBuild"> </Target> 
0
source

Alternatively, you can use one automatically generated VersionInfo.cs file, which all projects link to. To use this technique, turn off the attributes of the version, company information, etc. From the AssemblyInfo.cs file of your project (yes, this is a pain, but you only need to do it once), as well as the batch command, spit out the VersionInfo.cs file based on the template. To link to a shared file in Visual Studio, you select "Add an existing item" in the project context menu, and after you navigate to the VersionInfo.cs file in the file browser, click the drop-down arrow next to "Add" and select " Add as Link.

The following is an example of one of them. This script is tested on our SCC system and executed at the beginning of the build, supplying% BUILD_NUMBER% script.

 SET BUILD=%1 @echo using System.Reflection; > "%~p0Version.cs" @echo [assembly: AssemblyCompany("MyCompany, Inc.")] >> "%~p0Version.cs" @echo [assembly: AssemblyProduct("MyProduct")] >> "%~p0Version.cs" @echo [assembly: AssemblyCopyright("Copyright © 2012 MyCompany, Inc.")] >> "%~p0Version.cs" @echo [assembly: AssemblyTrademark("")]@echo [assembly: AssemblyVersion("1.0.%BUILD%.0")] >> "%~p0Version.cs" @echo [assembly: AssemblyFileVersion("1.0.%BUILD%.0")] >> "%~p0Version.cs" @echo ^<Include xmlns="http://schemas.microsoft.com/wix/2006/wi"^> > "%~p0Version.wxi" @echo ^<?define VersionBuild="%BUILD%"?^> >> "%~p0Version.wxi" @echo ^</Include^> >> "%~p0\Version.wxi" 
0
source

Source: https://habr.com/ru/post/921388/


All Articles