in src/MSBuild/XMake.cs [473:767]
public static ExitType Execute(
#if FEATURE_GET_COMMANDLINE
string commandLine
#else
string [] commandLine
#endif
)
{
// Indicate to the engine that it can toss extraneous file content
// when it loads microsoft.*.targets. We can't do this in the general case,
// because tasks in the build can (and occasionally do) load MSBuild format files
// with our OM and modify and save them. They'll never do this for Microsoft.*.targets, though,
// and those form the great majority of our unnecessary memory use.
Environment.SetEnvironmentVariable("MSBuildLoadMicrosoftTargetsReadOnly", "true");
switch (Environment.GetEnvironmentVariable("MSBUILDDEBUGONSTART"))
{
#if FEATURE_DEBUG_LAUNCH
case "1":
Debugger.Launch();
break;
#endif
case "2":
// Sometimes easier to attach rather than deal with JIT prompt
Process currentProcess = Process.GetCurrentProcess();
Console.WriteLine($"Waiting for debugger to attach ({currentProcess.MainModule.FileName} PID {currentProcess.Id}). Press enter to continue...");
Console.ReadLine();
break;
}
#if FEATURE_GET_COMMANDLINE
ErrorUtilities.VerifyThrowArgumentLength(commandLine, "commandLine");
#endif
ExitType exitType = ExitType.Success;
ConsoleCancelEventHandler cancelHandler = Console_CancelKeyPress;
try
{
#if (!STANDALONEBUILD)
// Enable CodeMarkers for MSBuild.exe
CodeMarkers.Instance.InitPerformanceDll(CodeMarkerApp.MSBUILDPERF, String.Format(CultureInfo.InvariantCulture, @"Software\Microsoft\MSBuild\{0}", MSBuildConstants.CurrentProductVersion));
#endif
#if MSBUILDENABLEVSPROFILING
string startMSBuildExe = String.Format(CultureInfo.CurrentCulture, "Running MSBuild.exe with command line {0}", commandLine);
DataCollection.CommentMarkProfile(8800, startMSBuildExe);
#endif
Console.CancelKeyPress += cancelHandler;
// check the operating system the code is running on
VerifyThrowSupportedOS();
// Setup the console UI.
SetConsoleUI();
// reset the application state for this new build
ResetBuildState();
// process the detected command line switches -- gather build information, take action on non-build switches, and
// check for non-trivial errors
string projectFile = null;
string[] targets = { };
string toolsVersion = null;
Dictionary<string, string> globalProperties = null;
ILogger[] loggers = { };
LoggerVerbosity verbosity = LoggerVerbosity.Normal;
List<DistributedLoggerRecord> distributedLoggerRecords = null;
#if FEATURE_XML_SCHEMA_VALIDATION
bool needToValidateProject = false;
string schemaFile = null;
#endif
int cpuCount = 1;
#if FEATURE_NODE_REUSE
bool enableNodeReuse = true;
#else
bool enableNodeReuse = false;
#endif
TextWriter preprocessWriter = null;
bool debugger = false;
bool detailedSummary = false;
ISet<string> warningsAsErrors = null;
ISet<string> warningsAsMessages = null;
CommandLineSwitches switchesFromAutoResponseFile;
CommandLineSwitches switchesNotFromAutoResponseFile;
GatherAllSwitches(commandLine, out switchesFromAutoResponseFile, out switchesNotFromAutoResponseFile);
if (ProcessCommandLineSwitches(
switchesFromAutoResponseFile,
switchesNotFromAutoResponseFile,
ref projectFile,
ref targets,
ref toolsVersion,
ref globalProperties,
ref loggers,
ref verbosity,
ref distributedLoggerRecords,
#if FEATURE_XML_SCHEMA_VALIDATION
ref needToValidateProject,
ref schemaFile,
#endif
ref cpuCount,
#if FEATURE_NODE_REUSE
ref enableNodeReuse,
#endif
ref preprocessWriter,
ref debugger,
ref detailedSummary,
ref warningsAsErrors,
ref warningsAsMessages,
recursing: false
))
{
// Unfortunately /m isn't the default, and we are not yet brave enough to make it the default.
// However we want to give a hint to anyone who is building single proc without realizing it that there
// is a better way.
if (cpuCount == 1 && FileUtilities.IsSolutionFilename(projectFile) && verbosity > LoggerVerbosity.Minimal)
{
Console.WriteLine(ResourceUtilities.FormatResourceString("PossiblyOmittedMaxCPUSwitch"));
}
if (preprocessWriter != null || debugger)
{
// Indicate to the engine that it can NOT toss extraneous file content: we want to
// see that in preprocessing/debugging
Environment.SetEnvironmentVariable("MSBUILDLOADALLFILESASWRITEABLE", "1");
}
DateTime t1 = DateTime.Now;
// If the primary file passed to MSBuild is a .binlog file, play it back into passed loggers
// as if a build is happening
if (FileUtilities.IsBinaryLogFilename(projectFile))
{
ReplayBinaryLog(projectFile, loggers, distributedLoggerRecords, cpuCount);
}
else // regular build
{
#if !STANDALONEBUILD
if (Environment.GetEnvironmentVariable("MSBUILDOLDOM") != "1")
#endif
{
// if everything checks out, and sufficient information is available to start building
if (!BuildProject(projectFile, targets, toolsVersion, globalProperties, loggers, verbosity, distributedLoggerRecords.ToArray(),
#if FEATURE_XML_SCHEMA_VALIDATION
needToValidateProject, schemaFile,
#endif
cpuCount, enableNodeReuse, preprocessWriter, debugger, detailedSummary, warningsAsErrors, warningsAsMessages))
{
exitType = ExitType.BuildError;
}
}
#if !STANDALONEBUILD
else
{
exitType = OldOMBuildProject(exitType, projectFile, targets, toolsVersion, globalProperties, loggers, verbosity, needToValidateProject, schemaFile, cpuCount);
}
#endif
} // end of build
DateTime t2 = DateTime.Now;
TimeSpan elapsedTime = t2.Subtract(t1);
string timerOutputFilename = Environment.GetEnvironmentVariable("MSBUILDTIMEROUTPUTS");
if (!String.IsNullOrEmpty(timerOutputFilename))
{
AppendOutputFile(timerOutputFilename, (long)elapsedTime.TotalMilliseconds);
}
}
else
{
// if there was no need to start the build e.g. because /help was triggered
// do nothing
}
}
/**********************************************************************************************************************
* WARNING: Do NOT add any more catch blocks below! Exceptions should be caught as close to their point of origin as
* possible, and converted into one of the known exceptions. The code that causes an exception best understands the
* reason for the exception, and only that code can provide the proper error message. We do NOT want to display
* messages from unknown exceptions, because those messages are most likely neither localized, nor composed in the
* canonical form with the correct prefix.
*********************************************************************************************************************/
// handle switch errors
catch (CommandLineSwitchException e)
{
Console.WriteLine(e.Message);
Console.WriteLine();
// prompt user to display help for proper switch usage
ShowHelpPrompt();
exitType = ExitType.SwitchError;
}
// handle configuration exceptions: problems reading toolset information from msbuild.exe.config or the registry
catch (InvalidToolsetDefinitionException e)
{
// Brief prefix to indicate that it's a configuration failure, and provide the "error" indication
Console.WriteLine(ResourceUtilities.FormatResourceString("ConfigurationFailurePrefixNoErrorCode", e.ErrorCode, e.Message));
exitType = ExitType.InitializationError;
}
// handle initialization failures
catch (InitializationException e)
{
Console.WriteLine(e.Message);
exitType = ExitType.InitializationError;
}
// handle polite logger failures: don't dump the stack or trigger watson for these
catch (LoggerException e)
{
// display the localized message from the outer exception in canonical format
if (null != e.ErrorCode)
{
// Brief prefix to indicate that it's a logger failure, and provide the "error" indication
Console.WriteLine(ResourceUtilities.FormatResourceString("LoggerFailurePrefixNoErrorCode", e.ErrorCode, e.Message));
}
else
{
// Brief prefix to indicate that it's a logger failure, adding a generic error code to make sure
// there's something for the user to look up in the documentation
Console.WriteLine(ResourceUtilities.FormatResourceString("LoggerFailurePrefixWithErrorCode", e.Message));
}
if (null != e.InnerException)
{
// write out exception details -- don't bother triggering Watson, because most of these exceptions will be coming
// from buggy loggers written by users
Console.WriteLine(e.InnerException.ToString());
}
exitType = ExitType.LoggerAbort;
}
// handle logger failures (logger bugs)
catch (InternalLoggerException e)
{
if (!e.InitializationException)
{
// display the localized message from the outer exception in canonical format
Console.WriteLine("MSBUILD : error " + e.ErrorCode + ": " + e.Message);
#if DEBUG
Console.WriteLine("This is an unhandled exception from a logger -- PLEASE OPEN A BUG AGAINST THE LOGGER OWNER.");
#endif
// write out exception details -- don't bother triggering Watson, because most of these exceptions will be coming
// from buggy loggers written by users
Console.WriteLine(e.InnerException.ToString());
exitType = ExitType.LoggerFailure;
}
else
{
Console.WriteLine("MSBUILD : error " + e.ErrorCode + ": " + e.Message +
(e.InnerException != null ? " " + e.InnerException.Message : ""));
exitType = ExitType.InitializationError;
}
}
catch (BuildAbortedException e)
{
Console.WriteLine("MSBUILD : error " + e.ErrorCode + ": " + e.Message +
(e.InnerException != null ? " " + e.InnerException.Message : String.Empty));
exitType = ExitType.Unexpected;
}
// handle fatal errors
catch (Exception e)
{
// display a generic localized message for the user
Console.WriteLine("{0}\r\n{1}", AssemblyResources.GetString("FatalError"), e.ToString());
#if DEBUG
Console.WriteLine("This is an unhandled exception in MSBuild Engine -- PLEASE OPEN A BUG AGAINST THE MSBUILD TEAM.\r\n{0}", e.ToString());
#endif
// rethrow, in case Watson is enabled on the machine -- if not, the CLR will write out exception details
// allow the build lab to set an env var to avoid jamming the build
if (Environment.GetEnvironmentVariable("MSBUILDDONOTLAUNCHDEBUGGER") != "1")
{
throw;
}
}
finally
{
s_buildComplete.Set();
Console.CancelKeyPress -= cancelHandler;
// Wait for any pending cancel, so that we get any remaining messages
s_cancelComplete.WaitOne();
#if (!STANDALONEBUILD)
// Turn off codemarkers
CodeMarkers.Instance.UninitializePerformanceDLL(CodeMarkerApp.MSBUILDPERF);
#endif
}
/**********************************************************************************************************************
* WARNING: Do NOT add any more catch blocks above!
*********************************************************************************************************************/
return exitType;
}