How do I customize my MSBuild script

Recently I started looking into MSBuild to create flexible build scripts for local and server builds (CI, Nightly, Weekly). Based on my experience, I knew that build scripts can be very awkward. Even in my company, with some guidance, it was painful to know all the goals and how they work together. Of course, it was a long process: you need something, you have little time, you start to get lazy and chaotic. But I asked myself: How can I structure my MSBuild script for extensibility and readability? Especially the three target relationships DependsOnTargets, BeforeTargets, AfterTargets were useful to shoot in the foot.

+3


source to share


2 answers


Ok, as I said, I had my own experiences :)

  • Each target goes into a single file , just like in object-oriented programming :) Also, common properties and groups of elements should remain in their own file (for example, Projects.conf with all projects to build; Environment.conf with all paths to tools and extension packages ). As you will see, this is very handy for different build sets (for example, local versus server build).
  • Define all paths, files and properties that you need. Don't follow the DRY principle. It is hard work, but in my experience it is difficult to build new values ​​around the already defined ones. So if you have a project with a .csproj and a .nuspec file, feel free to declare them explicitly.
  • Declare Init target . An explanation follows.
  • Declare some basic targets that need to be handled during build, like Clean, Build, Test, Package, Deploy, Archive, etc. Make them dependent (DependsOnTargets) from each other. Test and package depend on, for example, a Build object. They should all be dependent on the Init target.
  • Compliance Checks - Exceptions to Rule 1 . They belong to the same file where they are required. For example, the PackageCheck target will watch for the presence of .nuspec files and will also declare Init as AfterTargets. This allows the assembly to be completed quickly.
  • All other targets will be ordered using BeforeTargets, AfterTargets. I recommend avoiding DependsOnTargets unless you really need to, for example, if you need to process two targets before building, but also have order between them.
  • In server and local build scripts, just import whatever you need and what should be a public API. As I said, each target falls into one file (1). Now if you have an UpdateAssemblyVersion target, that should declare Build in AfterTargets (5). You can activate / deactivate this target simply by adding / removing imports.
  • Make use of MSBuildExtensionPack . They can be really helpful! But also don't be afraid to write your own problem !


So these are my rules. I would appreciate any comments or additions!

0


source


In my MSBuild book, I have a section based on how to create reusable items in MSBuild if you're interested. I'll also provide some comments here. This content is different from what the book has.

When creating MSBuild files, you must be careful to isolate what from how . To explain this a bit, let's take a look at how VS Managed Projects work out of the box (which is a great model for reusable items).

When you create a C # / VB project you get a .csproj file, this .csproj file contains mostly properties and items. You will not find any targets in this file. These files contain what will be generated (along with some build-related settings). At the bottom of the project file, you will find an import statement. This import includes the How project.

The imported files include:

  • Microsoft.CSharp / VisualBasic / FSharp.targets
  • Microsoft.common.targets

In this case, Microsoft.common.targets defines a common build process for all managed languages. Then Microsoft.CSharp.targets (or one of the other specific .targets lang file) fills in the gaps in how to handle specific language tools.

DependsOnTargets vs. Before / AfterTargets

In your answer above, you state "I recommend avoiding DependsOnTargets unless you really need it, for example two." I disagree with this. Here is my approach for the DependsOnTargets and Before / AfterTargets options.

Use DependsOnTargets when

  • When trying to create a workflow for goals to be executed
  • When a goal will not work without another goal (s) performing the first
  • When you need to enter different goals at specific stages based on the desired operation

Use Before / AfterTargets when



  • If you are not the owner of the file the target is in and it does not have a DependsOnTargets property that can be extended
  • You want a goal to execute before / after a specific goal no matter when it is executed.

To see the difference, take a quick look at web projects. For web projects, there are two workflows that .csproj / .vbproj runs:

  • Build
  • Publish

If I want to add a target to the list of targets to run before the Build object, I can dynamically update the BuildDependsOn property for publish scripts only. You cannot do this using the Before / After options.

In an ideal world, each target would have the following DependsOnTargets values.

  • All targets have a DependsOnTargets attribute, which is a feed using the property
  • Each DependsOnTargets always adds the existing value to the property definition

for example

<MyTargetDependsOn>
    $(MyTargetDependsOn);
    Target1;
    Target2
</MyTargetDependsOn>

      

Unfortunately, many targets don't fit this pattern, which is why DependsOnTargets is dead in the water for many cases.

When I create MSBuild scripts , I always use DependsOnTargets, unless there is a good reason why I had to use Before / AfterTargets . I feel like (I have no understanding of the real reasons behind the design as I was not with Microsoft at the time). Before / AfterTargets was really created to allow users to enter goals to be done before / after the target, and the creators did not use the template above.

+7


source







All Articles