I'm using BuildEngine as a step to create a one click build environment. The code is the following:
Engine engine = new Engine();
FileLogger logger = new FileLogger { Parameters = #"logfile=C:\builds\build.log" };
engine.RegisterLogger(logger);
var project = new Project(engine);
project.Load("Example.csproj");
project.SetProperty("Configuration", "Release");
bool success = project.Build();
And he seems to build project Example with release configuration. But when I look at the build.log, all of the dependencies of Example project were build as debug.
Is there any way to force it to build all dependencies on Release?
Set the global properties on the engine:
BuildPropertyGroup bpg = new BuildPropertyGroup ();
bpg.SetProperty ("Configuration", "Release");
engine.GlobalProperties = bpg;
These will override the properties set by the project themselves.
Engine class is obsolete.
Use Microsoft.Build.Evaluation.ProjectCollection instead.
It enables to pass global properties as you do when calling msbuild from command line.
I should warn you that msbuild eats a lot memory. I have a bot on a build machine working as a service. When it recieves command to build it creates new process and calles Build(). Sometimes memory usage reaches 2GB (our build is huge). When you call MSBuild from command line it releases memory much more effective.
Try to test 2 implementations - throw API and throw calling MSBuild.exe - in a loop. May be in MSBuild 4.0 MS solved those memory problems.
Related
In a console application I have been trying to get OpenSolutionAsync to work for a couple of weeks now without success.
Finally I remembered to look at the roslyn-sdk repository which contains samples. I locally run the sample called SolutionExplorer and it works perfectly. I can choose a solution file and it can open the solution.
Given that this sample works, I decided to make my console app similar to it. So I copied the MSBuildService and WorkspaceService (just changing the logging behavior) to my console application. Changed my console app to target v4.6.1 of .NET Framework. Referenced the exact same nuget packages. I made sure to delete the bin folders and also compared the bin folder from the sample with the bin folder generated for my project. They are the same.
And yet, when I hit the line to OpenSolutionAsync(), my console application just exits the process.
What am I doing wrong?
More info:
I copied the project here to make it easily reachable for you. Please provide two parameters to run the project e.g:
callerid.scanner.exe -p "<path to some solution>" -d "<documentNameToFindInSolution>"
It exits the process on line 97 of WorkspaceService
A few things, sorry it VB but you should get the idea. The important thing is to get the right instance of MSBuild and trap the errors.
Property MSBuildInstance As VisualStudioInstance
' Get all instances of MSBuild
Private ReadOnly visualStudioInstances() As VisualStudioInstance = MSBuildLocator.QueryVisualStudioInstances().ToArray()
' Pick the instance of MSBuild you want
MSBuildInstance = visualStudioInstances(???)
MSBuildLocator.RegisterInstance(MSBuildInstance)
Using Workspace As MSBuildWorkspace = MSBuildWorkspace.Create()
AddHandler Workspace.WorkspaceFailed, AddressOf MSBuildWorkspaceFailed
Dim currentProject As Project = Workspace.OpenProjectAsync(FileName).Result
' Do something with the project
End Using
' Print message for WorkspaceFailed event to help diagnosing project load failures.
Private Sub MSBuildWorkspaceFailed(_1 As Object, e1 As WorkspaceDiagnosticEventArgs)
If MsgBox(e1.Diagnostic.Message, MsgBoxStyle.AbortRetryIgnore, "MSBuild Failed") = MsgBoxResult.Abort Then
End
End If
End Sub
You need to register a msbuild location with the MSBuildLocator class. This will allow the MSBuildWorkspace to open solutions and projects. Long story short: it needs to know where msbuild is because it uses it to load projects.
I would place the following code in the constructor of your service
// Attempt to set the version of MSBuild.
var visualStudioInstances = MSBuildLocator.QueryVisualStudioInstances().ToArray();
var instance = visualStudioInstances.Length == 1
// If there is only one instance of MSBuild on this machine, set that as the one to use.
? visualStudioInstances[0]
// Handle selecting the version of MSBuild you want to use.
: SelectVisualStudioInstance(visualStudioInstances);
_logger.WriteLine($"Using MSBuild at '{instance.MSBuildPath}' to load projects.");
// NOTE: Be sure to register an instance with the MSBuildLocator
// before calling MSBuildWorkspace.Create()
// otherwise, MSBuildWorkspace won't MEF compose.
MSBuildLocator.RegisterInstance(instance);
Found the problem.
I was using nuget package CommandLineParser. It has to do with usage of async while triggering the action with CommandLineParser. When I removed async and called OpenSolutionAsync().Result instead, it works.
It seems like CommandLineParser has no support for async implementation. Then OpenSolutionAsync just quits the process when called with await within CommandLineParser's WithParsed method.
This cost me weeks to figure out..
Thanks for your answers anyways, #Jonathon Marolf and #Paul Cohen.
I am trying to create a custom MSBuild script in C#, using the newer Microsoft.Build.Evaluation API. The problem I have is that this newer API does not support .sln files. The older deprecated Microsoft.Build.Engine API does support .sln files, but I'd like to use the newer one because 1) it's not deprecated and 2) there seems to be more online documentation and usage to reference. I've seen that MSBuild can create a .metaproj file when is successfully compiles a solution, when this assignment is made in CMD: set MSBuildEmitSolution=1. I need the .metaproj file to be able to compile the solution in the first place. Is there anything in the API for converting .sln to .metaproj? Is there any library out there for parsing .sln files?
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);
I am trying to analyse a solution with Roslyn, with MSBuildWorkspace.
The solution is a new solution, with 2 class library projects in them, one referencing the other.
They are created in Visual Studio 2017, .Net 4.6.2.
When I open the solution, I receive two generic errors in workspace.Diagnostics, both are :
Msbuild failed when processing the file 'PathToProject'
There is nothing more in the diagnostics or output window, to indicate WHY it failed to process the project file.
The code for opening the solution:
namespace RoslynAnalyse
{
class Program
{
static void Main(string[] args)
{
LocalAnalysis();
}
private static void LocalAnalysis()
{
var workspace = MSBuildWorkspace.Create();
var solution = workspace.OpenSolutionAsync(#"D:\Code\Roslyn\RoslynAnalyse\SolutionToAnalyse\SolutionToAnalyse.sln").Result;
var workspaceDiagnostics = workspace.Diagnostics;
}
}
}
The version of Microsoft.CodeAnalysis is 2.0.0.0.
Does anybody have any idea why MSBuild failed, how I can get more information ?
When MSBuildWorkspace fails to open a project or solution this way, it is almost always because the application using MSBuildWorkspace does not include the same binding redirects that msbuild.exe.config has in it.
MSBuild uses binding redirects to allow tasks (typically already compiled C# code using possibly different versions of msbuild API libraries) to all use the current msbuild API's. Otherwise, msbuild gets runtime load failures.
The solution is to add an app.config file to your project and copy the binding redirects (the assemblyBinding section of the msbuild.exe.config file) into your file.
On compilation errors in one of my projects, the build results page on TFS is significantly less informative than I'd hoped; I only get this:
I had hoped more for something like this (from a different project built the same way):
What do I need to do to get TFS to show the specific errors?
I build both projects using Cake build with the following target definition:
Task("Build")
.IsDependentOn("Update version")
.Does(() =>
{
Information("Verbosity: {0}", verbosity);
MSBuild(solutionPath, settings =>
{
settings.SetConfiguration(configuration);
settings.SetVerbosity(verbosity);
});
});
This sounds like it could be solved by using a custom MSBuild logger. Currently we do not have one built into Cake, but if you add an issue to Cake's issue tracker we can take this into consideration for a future release.
As a temporary solution, you could write a custom logger and provide it to the MSBuild alias using the ArgumentCustomization property on the MSBuild tool settings.
If TFS provides a MSBuild logger out of the box, you should be able to reference that one.
I have a bunch of legacy web projects that are compiled using a custom build application that we wrote. This because the depedencies were complex and the code... is... less than optimal. On the plus side it has recently been upgraded to .NET 4.5 and we are using Visual Studio 2013.
I recently started using code contracts in one of our other projects and really like the SoC it provides. I want to implement this in the legacy code that we are maintaining for new features (without doing a complete re-write). In development I have gotten it to work as long as I do a build from within VS and copy the compiled DLL files into the BIN folder of the web application (aps.net 32bit latest IIS).
I want to include the contracts in our release build as well using our Build tool. Otherwise I would have to use the tool and then use VS to create a release which is a 2 step process. I have complete source control over the tool (which is executed locally on my DEV PC) but I cannot get it to produce output with the code contracts. I read the Code Contract documentation and they mention the build script Microsoft.CodeContracts.targets and I have tried to add this into the build code without success. Admittedly my knowledge of the build process, build scripts, etc. is lacking at best. Any help / pointers in how to get this to work would be greatly appreciated. I would still like to normally compile my code in VS and have contracts work as well as use the build tool and and contracts work.
(i have not manually changed any of the CSPROJ files)
Build Code:
Build code is done using Microsoft.Build and Microsoft.Build.Framework assemblies.
var pc = new ProjectCollection();
var buildLogger = new FileLogger();
var logFilePath = #"MyLog.log";
buildLogger.Parameters = string.Format("logfile={0}", logFilePath);
var binDirectory = Path.Combine(outputWebDir, "Bin");
var globalProperty = new Dictionary<string, string>();
globalProperty.Add("OutputPath", binDirectory);
globalProperty.Add("Configuration", publishParams.ReleaseMode);
globalProperty.Add("Platform", publishParams.PlatformMode);
if (projectFileToPublish.IndexOf("SOTAQ.WebPoint.Web.csproj", StringComparison.OrdinalIgnoreCase) < 0)
globalProperty.Add("SolutionDir", publishParams.SparcoSolutionPath);
if (isWebSite)
{
globalProperty.Add("WebProjectOutputDir", outputWebDir);
globalProperty.Add("DeployOnBuild", "True");
}
globalProperty.Add("CodeContractsInstallDir", #"C:\Program Files (x86)\Microsoft\Contracts\");
globalProperty.Add("CodeContractRewriteCommand", #"C:\Program Files (x86)\Microsoft\Contracts\Bin\ccrewrite.exe");
globalProperty.Add("CodeContractAnalysisTargets", #"C:\Program Files (x86)\Microsoft\Contracts\MsBuild\v4.0\Microsoft.CodeContractAnalysis.targets");
globalProperty.Add("CodeContractsCCDocgenCommand", #"C:\Program Files (x86)\Microsoft\Contracts\Bin\ccdocgen.exe");
globalProperty.Add("CodeContractsCCRefgenCommand", #"C:\Program Files (x86)\Microsoft\Contracts\Bin\ccrefgen.exe");
string[] targets;
if (isWebSite)
targets= new[] { "Build", "ResolveReferences", "_CopyWebApplication" };
else
targets = new[] { "Build", "ResolveReferences" };
var buildRequestData = new BuildRequestData(projectFileToPublish, globalProperty, null, targets, null);
var buildParams = new BuildParameters(pc);
buildParams.Loggers = new[] {buildLogger};
BuildResult buildResult = BuildManager.DefaultBuildManager.Build(buildParams, buildRequestData);
Any help is greatly appreciated!!
Thanks in advance,
-Igor
After reading and re-reading the diagnostic output from Visual Studio and comparing it to my build project and trying many various possible solutions I found online the answer was to add the variable CodeContractsEnableRuntimeChecking with value true.
globalProperty.Add("CodeContractsEnableRuntimeChecking", "true");
Once that was added everything worked as expected.
-Igor