private static int Main()

in Sharpmake.Application/Program.cs [149:387]


        private static int Main()
        {
            if (CommandLine.ContainParameter("breakintodebugger"))
            {
                Console.WriteLine("Debugger requested. Please attach a debugger and press ENTER to continue");
                while (Console.ReadKey(true).Key != ConsoleKey.Enter)
                {
                    Console.WriteLine("Press ENTER to continue");
                }
                Debugger.Break();
            }
            // This GC gives a little bit better results than the other ones. "LowLatency" is giving really bad results(twice slower than the other ones).
            System.Runtime.GCSettings.LatencyMode = System.Runtime.GCLatencyMode.SustainedLowLatency;
            Trace.Assert(System.Runtime.GCSettings.IsServerGC, "Server GC is not active! Sharpmake will be much slower!");

            AppDomain currentDomain = AppDomain.CurrentDomain;

            Mutex oneInstanceMutex = null;
            Argument parameters = new Argument();
            ExitCode exitCode = ExitCode.Success;
            try
            {
                DebugEnable = CommandLine.ContainParameter("verbose") || CommandLine.ContainParameter("debug") || CommandLine.ContainParameter("diagnostics");

                GetAssemblyInfo(Assembly.GetExecutingAssembly(), out var _, out var version, out var versionString, out var _);
  
                LogWriteLine($"sharpmake {versionString}");
                LogWriteLine("  arguments: {0}", CommandLine.GetProgramCommandLine());
                LogWriteLine("  directory: {0}", Directory.GetCurrentDirectory());
                LogWriteLine("  platform: {0} - {1}", Util.GetExecutingPlatform().ToString(), RuntimeInformation.OSDescription);
                LogWriteLine("  compiled with framework: {0}", Util.FrameworkDisplayName());
                LogWriteLine("  running on framework: {0}", RuntimeInformation.FrameworkDescription);
                LogWriteLine(string.Empty);

                // display help if wanted and quit
                if ((CommandLine.GetProgramCommandLine().Length == 0) || CommandLine.ContainParameter("help"))
                {
                    LogWriteLine(CommandLine.GetCommandLineHelp(typeof(Argument), false));
                    return CommandLine.ContainParameter("help") ? (int)ExitCode.Success : (int)ExitCode.Error;
                }

                AppDomain.CurrentDomain.AssemblyLoad += AppDomain_AssemblyLoad;

                // Log warnings and errors from builder
                Assembler.EventOutputError += ErrorWrite;
                Assembler.EventOutputWarning += WarningWrite;

                CommandLine.ExecuteOnObject(parameters);

                if (parameters.Exit)
                    return (int)ExitCode.Success;

                const string sharpmakeSymbolPrefix = "_SHARPMAKE";
                List<string> invalidSymbols = parameters.Defines.Where(define => define.StartsWith(sharpmakeSymbolPrefix)).ToList();
                if (invalidSymbols.Any())
                {
                    string invalidSymbolsString = string.Join(", ", invalidSymbols);
                    throw new Error($"Only Sharpmake process can define symbols starting with {sharpmakeSymbolPrefix}. Invalid symbols defined: {invalidSymbolsString}");
                }

                parameters.Defines.Add(sharpmakeSymbolPrefix); // A generic sharpmake define to allow scripts to exclude part of code if not used with sharpmake
                parameters.Defines.Add($"{sharpmakeSymbolPrefix}_{version.Major}_{version.Minor}_X");
                parameters.Defines.Add($"{sharpmakeSymbolPrefix}_{version.Major}_{version.Minor}_{version.Build}");

                parameters.Validate();

                // CommonPlatforms.dll is always loaded by default because those are shipped with
                // the Sharpmake package.
                PlatformRegistry.RegisterExtensionAssembly(typeof(Windows.Win32Platform).Assembly);

                // If any platform declares its own command line options, execute and validate
                // them as well.
                IEnumerable<Platform> platformsCmdLines = PlatformRegistry.GetAvailablePlatforms<ICommandLineInterface>();
                foreach (var platform in platformsCmdLines)
                {
                    var platformCmdLine = PlatformRegistry.Get<ICommandLineInterface>(platform);
                    CommandLine.ExecuteOnObject(platformCmdLine);
                    platformCmdLine.Validate();
                }

                bool oneInstanceMutexCreated;
                string mutexName = string.Format("SharpmakeSingleInstanceMutex{0}", parameters.MutexSuffix); // Allow custom mutex name suffix. Useful to debug concurrently multiple sharpmake running from different branches
                oneInstanceMutex = new Mutex(true, mutexName, out oneInstanceMutexCreated);

                if (!oneInstanceMutexCreated)
                {
                    try
                    {
                        if (!oneInstanceMutex.WaitOne(0))
                        {
                            LogWriteLine("wait for another instance(s) of sharpmake to terminate...");
                            oneInstanceMutex.WaitOne();
                        }
                    }
                    catch (AbandonedMutexException)
                    {
                        // This occurs if another sharpmake is killed in the debugger
                    }
                    finally
                    {
                        LogWriteLine("waiting done.");
                    }
                }

                if (parameters.RegexMatchCacheEnabled)
                {
                    GlobalRegexMatchCache.Init(parameters.RegexMatchCacheInitialCapacity);
                }

                switch (parameters.TestOption)
                {
                    case TestOptions.Regression:
                        {
                            var regressionTest = new BuildContext.RegressionTest(parameters.OutputDirectory, parameters.ReferenceDirectory, parameters.RemapRoot);
                            GenerateAll(regressionTest, parameters);
                            exitCode = ExitCode.Success;

                            var regressions = regressionTest.GetRegressions().ToList();
                            if (regressions.Count > 0)
                            {
                                exitCode = ExitCode.Error;
                                DebugWriteLine($"{regressions.Count} Regressions detected:");
                                List<BuildContext.RegressionTest.OutputInfo> fileChanges = regressions.Where(x => x.FileStatus == BuildContext.RegressionTest.FileStatus.Different).ToList();
                                LogFileChanges(fileChanges, parameters.RegressionDiff);

                                var fileMissing = regressions.Where(x => x.FileStatus == BuildContext.RegressionTest.FileStatus.NotGenerated).Select(x => x.ReferencePath).ToList();
                                if (fileMissing.Count > 0)
                                {
                                    fileMissing.Sort();
                                    DebugWriteLine($"  {fileMissing.Count} files are missing from the output:");
                                    fileMissing.ForEach(x => DebugWriteLine($"    {x}"));
                                }
                            }
                        }
                        break;
                    case TestOptions.QuickConfigure:
                        {
                            exitCode = AnalyzeConfigureOrder(parameters, true);
                        }
                        break;
                    case TestOptions.Configure:
                        {
                            exitCode = AnalyzeConfigureOrder(parameters, false);
                        }
                        break;
                    case TestOptions.None:
                    default:
                        {
                            if (parameters.OutputDirectory != null)
                            {
                                // output redirect mode
                                var redirectOutput = new BuildContext.RedirectOutput(parameters.OutputDirectory, parameters.RemapRoot);
                                GenerateAll(redirectOutput, parameters);
                                exitCode = ExitCode.Success;
                            }
                            else
                            {
                                var generateAll = new BuildContext.GenerateAll(parameters.DebugLog, parameters.WriteFiles);
                                GenerateAll(generateAll, parameters);
                                exitCode = ExitCode.Success;

                                Util.ExecuteFilesAutoCleanup();
                            }
                        }
                        break;
                }

                if (CSproj.AllCsProjSubTypesInfos.Any())
                    Util.SerializeAllCsprojSubTypes(CSproj.AllCsProjSubTypesInfos);

                if (parameters.RegexMatchCacheEnabled)
                {
                    int regexMatchCacheInitialCapacity = parameters.RegexMatchCacheInitialCapacity;
                    int regexMatchCacheSize = GlobalRegexMatchCache.Count;
                    if (regexMatchCacheInitialCapacity < regexMatchCacheSize)
                    {
                        WarningWriteLine("Warning (perf): Consider increasing regex match cache initial capacity from {0} to at least {1} ( /regexMatchCacheInitialCapacity({1}) ).", regexMatchCacheInitialCapacity, regexMatchCacheSize);
                    }

                    GlobalRegexMatchCache.UnInit();
                }
            }
            catch (Error e)
            {
                // Log error message
                Exception innerException = e;
                while (innerException.InnerException != null)
                    innerException = innerException.InnerException;
                ErrorWriteLine(Environment.NewLine + "Error:" + Environment.NewLine + innerException.Message);

                // Then log details
                LogWriteLine(Util.GetCompleteExceptionMessage(e, "\t"));
                exitCode = ExitCode.Error;
            }
            catch (InternalError e)
            {
                ErrorWriteLine(Environment.NewLine + "Internal Error:");
                LogWriteLine(Util.GetCompleteExceptionMessage(e, "\t"));
                exitCode = ExitCode.InternalError;
            }
            catch (Exception e)
            {
                LogWriteLine(Environment.NewLine + "Exception Error:");
                LogWriteLine(Util.GetCompleteExceptionMessage(e, "\t"));
                exitCode = ExitCode.UnknownError;
            }
            finally
            {
                if (oneInstanceMutex != null)
                {
                    oneInstanceMutex.ReleaseMutex();
                    GC.KeepAlive(oneInstanceMutex);
                }

                if (parameters.Debug)
                {
                    Console.WriteLine("DEBUG Sharpmake.Application: Press any key to exit...");
                    Console.ReadKey();
                }
            }

            if (exitCode <= ExitCode.Error) // Do not display summary in case of unknown exception or internal error
                LogWriteLine(@"{0} errors, {1} warnings", s_errorCount, s_warningCount);
            if (s_errorCount != 0)
            {
                if (Debugger.IsAttached)
                {
                    LogWriteLine("Please look at the errors.");
                    Debugger.Break();
                }
            }

            // Always return the same error code no matter the number of errors.
            if (exitCode == ExitCode.Success && s_errorCount != 0)
            {
                exitCode = ExitCode.GenerationError;
            }
            return (int)exitCode;
        }