Running Msbuild Programmatically

Running MSBuild programmatically

I would recommend stronlgy to go the official route via classes/interfaces in Microsoft.Build namespace. Microsoft uses this all over the place, so this should count for something...

Esp. the class Microsoft.Build.Execution.BuildManager and the Singleton Microsoft.Build.Execution.BuildManager.DefaultBuildManager is what you are after to run a build task... source code examples:

  • http://social.msdn.microsoft.com/Forums/en-US/msbuild/thread/ec95c513-f972-45ad-b108-5fcfd27f39bc/
  • Logging Build messages with MSBuild 4.0

Building msbuild 15 project programmatically

I had similar needs for my team and I wrote a Builder library for C# that supports several versions of Visual Studio.
I could not make the Project.Build function work properly, so I went for executing MsBuild.exe directly.

How I built it:

Use Microsoft.Build.Framework from NuGet

Create a new Project object with 1 target called Build

Define the right ToolsVersion

Of the Project according to the Visual Studio version:

  • 2010, 2012 => 4.0
  • 2013 => 12.0
  • 2015 => 14.0
  • 2017 => 15.0

Add a new task of type MsBuild

With Projects property containing all the project I need to build

Define the ToolsVersion

of the MsBuild task with same value as for the Project

Serialize the Project into a temporary file

Find the right MsBuild.exe according to the ToolsVersion

4.0, 12.0, 14.0

Found in the registry:

Registry.LocalMachine.OpenSubKey($@"SOFTWARE\Microsoft\MSBuild\ToolsVersions\{msBuildVersion}")

15.0

Not anymore in the registry, you need to use the Nuget package Microsoft.VisualStudio.Setup.Configuration.Interop

        var query = new SetupConfiguration();

var query2 = (ISetupConfiguration2)query;

var e = query2.EnumAllInstances();

var helper = (ISetupHelper)query;

int fetched;

var instances = new ISetupInstance[1];

do
{
e.Next(1, instances, out fetched);
if (fetched > 0)
{
var instance = instances[0];

var instance2 = (ISetupInstance2)instance;

var state = instance2.GetState();

// Skip non-complete instance, I guess?
// Skip non-local instance, I guess?
// Skip unregistered products?
if (state != InstanceState.Complete
|| (state & InstanceState.Local) != InstanceState.Local
|| (state & InstanceState.Registered) != InstanceState.Registered)
{
continue;
}

var msBuildComponent =
instance2.GetPackages()
.FirstOrDefault(
p =>
p.GetId()
.Equals("Microsoft.Component.MSBuild",
StringComparison.InvariantCultureIgnoreCase));

if (msBuildComponent == null)
{
continue;
}

var instanceRootDirectory = instance2.GetInstallationPath();

var msbuildPathInInstance = Path.Combine(instanceRootDirectory, "MSBuild", msBuildVersion, "Bin", "msbuild.exe");

if (File.Exists(msbuildPathInInstance))
{
return msbuildPathInInstance;
}
}
} while (fetched > 0);

Execute MsBuild.exe

And build the serialized Project using a custom XML Logger - you can use the one provided by MsBuildExtensionPack

Read the result summary

Deserialize the result summary from Xml and use it to determine if build failed or not, which errors and warnings occurred etc.

how to execute msbuild.exe command using winform c#?

  System.Diagnostics.Process.Start(@"C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe");

How do I build a solution programmatically in C#?

Most of the answers are providing ways to do it by calling external commands, but there is an API, Microsoft.Build.Framework, to build via C#.


Code from blog post:

using Microsoft.Build.BuildEngine;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

public class SolutionBuilder
{
BasicFileLogger b;
public SolutionBuilder() { }

[STAThread]
public string Compile(string solution_name,string logfile)
{
b = new BasicFileLogger();
b.Parameters = logfile;
b.register();
Microsoft.Build.BuildEngine.Engine.GlobalEngine.BuildEnabled = true;
Project p = new Project (Microsoft.Build.BuildEngine.Engine.GlobalEngine);
p.BuildEnabled = true;
p.Load(solution_name);
p.Build();
string output = b.getLogoutput();
output += “nt” + b.Warningcount + ” Warnings. “;
output += “nt” + b.Errorcount + ” Errors. “;
b.Shutdown();
return output;
}
}
// The above class is used and compilation is initiated by the following code,
static void Main(string[] args)
{
SolutionBuilder builder = new SolutionBuilder();
string output = builder.Compile(@”G:CodesTestingTesting2web1.sln”, @”G:CodesTestingTesting2build_log.txt”);
Console.WriteLine(output);
Console.ReadKey();
}

Note the code in that blog post works, but it is a little dated. The

Microsoft.Build.BuildEngine

has been broken up into some pieces.

Microsoft.Build.Construction

Microsoft.Build.Evaluation

Microsoft.Build.Execution

How can I use an SLN file with MSBuild programmatically from C#?

I figured it out after more searching. Finding good examples online is a little difficult because of the two different versions of the MSBuild API, and the popularity of just running MSBuild from the command line.

Here is the code that is now working for me, using the newer MSBuild API:

var pc = new ProjectCollection();

var parameters = new BuildParameters(pc)
{
Loggers = new[] { _logger } //Instance of ILogger instantiated earlier
};

var request = new BuildRequestData(
projectFullPath: pathToMySlnFile, //Solution file path
globalProperties: myPropertyDictionary,
toolsVersion: null,
targetsToBuild: myTargetsArray,
hostServices: null,
flags: BuildRequestDataFlags.ProvideProjectStateAfterBuild);

var buildResult = BuildManager.DefaultBuildManager.Build(parameters, request);

How to call MSBuild from C#

Yes, add a reference to Microsoft.Build.Engine and use the Engine class.

PS: Take care to reference the right version. There are 2.0 and 3.5 assemblies and you'll have to make sure that everyone gets the right one.

Delphi 11: Find correct toolsversion for MSBuild programmatically

Assuming that rsvars.bat has been run,

FOR %%v IN ("%frameworkdir%") DO SET "toolsversion=%%~nv"
ECHO msbuild ...blah... /toolsversion:%toolsversion:~1%

The variable frameworkdir will be set by rsvars.bat. The for command parses its value (eg. C:\Windows\Microsoft.NET\Framework\v4.0.30319 as though it is a filename, and picks v4.0 as the "filename" (~n modifier [filename] of the metavariable %%v)

Then use the value assigned to toolsversion, starting at character 1 (where the first character is "character 0")

--- Given more info in comment

FOR %%v IN ("%frameworkdir%") DO ECHO %%~nxv|FINDSTR /R ".*\..*\.">nul&IF ERRORLEVEL 1 (SET "toolsversion=%%~nxv") ELSE SET "toolsversion=%%~nv"

Oh ye of little faith :)



Related Topics



Leave a reply



Submit