Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MSBuild: Ensure a target is run before any other build steps

Tags:

c#

msbuild

I am trying to have the AssemblyInfo.cs file updated to reflect the next Publish version of the project BEFORE any other build steps occur.

in my project file i added before the end:

<Import Project="$(ProjectDir)Properties\PublishVersion.proj" />

PublishVersion.proj looks like this:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<Target Name="BeforeBuild">
    <FormatVersion Version="$(ApplicationVersion)" Revision="$(ApplicationRevision)">
        <Output TaskParameter="OutputVersion" PropertyName="SetVersion" />
    </FormatVersion>
    <FileUpdate Files="$(ProjectDir)Properties\AssemblyInfo.cs"
       Regex="\d+\.\d+\.\d+\.\d+"
       ReplacementText="$(SetVersion)" />
</Target>
</Project>

Now it does execute somewhere before building completes but definitely not before it starts, because when i look at the generated exe it has a file version that was in AssemblyInfo.cs BEFORE build started but the .application file and manifest file have various references to the new version.

resulting manifest file(1.0.0.0 before build start, 1.0.0.4 after build):

<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly ...>
  <asmv1:assemblyIdentity name="BHTechSupport.exe" version="1.0.0.4" ... />
  ...
  <entryPoint>
    <assemblyIdentity name="BHTechSupport" version="1.0.0.0" ... />
    ...
  </entryPoint>
  ...
  <dependency>
    <dependentAssembly ... codebase="BHTechSupport.exe" ...>
      <assemblyIdentity name="BHTechSupport" version="1.0.0.0" ... />
      ...
    </dependentAssembly>
  </dependency>
  ...
</asmv1:assembly>

so how do i ensure that my target gets executed before EVERYTHING else?

making changes to PublishVersion.proj sometimes seem to not take effect and i need to clean the solution and restart visual studio before effecting.

like image 352
Lawrence Ward Avatar asked Nov 09 '11 15:11

Lawrence Ward


2 Answers

If you want a target to run at the beginning of every build regardless of what end-goal target is called (Clean, Restore, Build, Publish) you can use the InitialTargets attribute of the Project element.

like image 51
TheXenocide Avatar answered Oct 20 '22 03:10

TheXenocide


Maybe you have to use BeforeBuild target.

so how do i ensure that my target gets executed before EVERYTHING else?

To check your target execution, you can change the MSBuild project build output verbosity to Diagnostic. Find it under the Tools > Options > Projects and Solutions > Build and Run. Then build the project and find your target in the output window.

making changes to PublishVersion.proj sometimes seem to not take effect and i need to clean the solution and restart visual studio before effecting.

AFAIK, the Visual Studio loads target files once, so you have to reload your project to see the result.

Update I don't know your versioning system, whereas it's not important. Anyway, I tried to provide a simple example for you.

using System;
using System.IO;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;

namespace Foo.Build.Tasks {

    public sealed class GenerateVersion : Task {

        [Output]
        public ITaskItem[] GeneratedFiles { get; private set; }

        public override bool Execute() {
            string objPath = Path.Combine(Path.GetDirectoryName(this.BuildEngine3.ProjectFileOfTaskNode), "obj");
            string path = Path.Combine(objPath, "VersionInfo.cs");

            File.WriteAllText(path, @"using System.Reflection;
[assembly: AssemblyVersion(""2.0.0"")]");

            GeneratedFiles = new[] { new TaskItem(path) };

            return true;
        }

    }

}

The preceding task generates a file that contains AssemblyVersion metadata or everything you want.

At last, you have to change your project file as follows:

<UsingTask TaskName="Foo.Build.Tasks.GenerateVersion" AssemblyFile="Foo.Build.Tasks.dll" />

<Target Name="BeforeBuild">
  <GenerateVersion>
    <Output TaskParameter="GeneratedFiles" ItemName="Compile" />
  </GenerateVersion>
</Target>
like image 29
Mehdi Golchin Avatar answered Oct 20 '22 02:10

Mehdi Golchin