public static bool PopulateAndValidateConfiguration()

in Public/Src/Engine/Dll/Engine.cs [867:1310]


        public static bool PopulateAndValidateConfiguration(
            ConfigurationImpl mutableConfig,
            ICommandLineConfiguration initialCommandLineConfiguration,
            PathTable pathTable,
            LoggingContext loggingContext)
        {
            bool success = true;

            foreach (var property in initialCommandLineConfiguration.Startup.Properties)
            {
                EngineEnvironmentSettings.SetVariable(property.Key, property.Value);
            }

            // Customer builds may involve a lot of large strings that can fill up the string table.
            // Adding a non-zero overflow buffer count increases the capacity of the string table.
            // Large string buffer is a secondary table used when the strings are large. By adjusting the threshold for
            // the string size, some of the large strings that used to go to the string table can go to the large string buffer.
            StringTable.OverrideStringTableDefaults(EngineEnvironmentSettings.LargeStringBufferThresholdBytes);

            if (mutableConfig.Export.SnapshotFile.IsValid && mutableConfig.Export.SnapshotMode != SnapshotMode.None)
            {
                // Note: the /CleanOnly also overrides the Phase. In this case it is safe. An evaluation snapshot 'can' work with the 'schedule' phase in case both are set.
                mutableConfig.Engine.Phase = mutableConfig.Export.SnapshotMode == SnapshotMode.Full
                    ? EnginePhases.Schedule
                    : EnginePhases.Evaluate;

                // TODO: Snapshot mode does not work when loading cached graph. Can input tracker be used to capture/load the same information as
                // the snapshot collector so snapshot works with graph caching.
                mutableConfig.Cache.CacheGraph = false;
            }

            // The /cleanonly option should override the phase to only schedule and not perform execution
            if (mutableConfig.Engine.CleanOnly)
            {
                // Note: the snapshot option also sets the phase. In this case it is safe. An evaluation snapshot 'can' work with the 'schedule' phase in case both are set.
                mutableConfig.Engine.Phase = EnginePhases.Schedule;
            }

            // Distribution overrides
            if (mutableConfig.Distribution.BuildRole.IsOrchestrator())
            {
                if (!mutableConfig.Distribution.BuildWorkers.Any())
                {
                    // Disable the distribution if no remote worker is given.
                    mutableConfig.Distribution.BuildRole = DistributedBuildRoles.None;
                    mutableConfig.Distribution.LowWorkersWarningThreshold = 0;
                }
                else
                {
                    var remoteWorkerCount = mutableConfig.Distribution.BuildWorkers.Count;

                    if (mutableConfig.Distribution.LowWorkersWarningThreshold == null)
                    {
                        mutableConfig.Distribution.LowWorkersWarningThreshold = remoteWorkerCount/2;
                    }
                    else
                    {
                        mutableConfig.Distribution.LowWorkersWarningThreshold = Math.Min(remoteWorkerCount + 1, mutableConfig.Distribution.LowWorkersWarningThreshold.Value);
                    }

                    // Force graph caching because the orchestrator needs to communicate it to the worker.
                    mutableConfig.Cache.CacheGraph = true;
                }
            }
            else
            {
                mutableConfig.Distribution.LowWorkersWarningThreshold = 0;
            }

            if (!mutableConfig.Distribution.BuildRole.IsOrchestrator() || mutableConfig.Schedule.ModuleAffinityEnabled())
            {
                // No additional choose worker threads needed in single machine builds, workers, or orchestrators when module affinity is enabled
                mutableConfig.Schedule.MaxChooseWorkerCpu = 1;
                mutableConfig.Schedule.MaxChooseWorkerCacheLookup = 1;
            }

            // Caching overrides
            if (mutableConfig.Cache.CachedGraphLastBuildLoad)
            {
                mutableConfig.Cache.CachedGraphPathToLoad = mutableConfig.Layout.EngineCacheDirectory;
                mutableConfig.Cache.CachedGraphLastBuildLoad = false;
            }

            // Cache config file path.
            if (!mutableConfig.Cache.CacheConfigFile.IsValid)
            {
                // Use default cache config file if nothing is specified.
                Assembly executingAssembly = Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly();
                var executingAssemblyDirectory = Path.GetDirectoryName(AssemblyHelper.GetAssemblyLocation(executingAssembly));
                Contract.Assert(!string.IsNullOrEmpty(executingAssemblyDirectory));

                var defaultCacheConfigFile = AbsolutePath.Create(pathTable, Path.Combine(executingAssemblyDirectory, DefaultCacheConfigFileName));
                mutableConfig.Cache.CacheConfigFile = defaultCacheConfigFile;
            }

            // There is funny handling in the configuration for these two settings in conjuction with allowlist settings:
            //  * Turning off UnexpectedFileAccessesAreErrors (this code), or
            //  * Declaring a allowlist in config.
            // (story 169157) Tracks cleaning this up.
            mutableConfig.Sandbox.FailUnexpectedFileAccesses = mutableConfig.Sandbox.UnsafeSandboxConfiguration.UnexpectedFileAccessesAreErrors;

            // New semantics of /unsafe_DisableDetours --> fully disables sandboxing and runs processes using the plain .NET Process class.
            // This effectively means that MonitorFileAccesses should be disabled.
            if (mutableConfig.Sandbox.UnsafeSandboxConfiguration.DisableDetours())
            {
                mutableConfig.Sandbox.UnsafeSandboxConfigurationMutable.MonitorFileAccesses = false;
            }

            foreach (var variable in mutableConfig.AllowedEnvironmentVariables)
            {
                if (DisallowedTempVariables.Contains(variable))
                {
                    Logger.Log.EnvironmentValueForTempDisallowed(
                        loggingContext,
                        mutableConfig.Layout.PrimaryConfigFile.ToString(pathTable),
                        0,
                        0,
                        variable);
                    success = false;
                }
            }

            mutableConfig.Location = new LocationData(mutableConfig.Layout.PrimaryConfigFile, 0, 0);

            // Validate the global module configuration from the config file
            success &= ValidateModuleConfig(mutableConfig, pathTable, loggingContext, mutableConfig.Sandbox);

            foreach (var moduleConfiguration in mutableConfig.ModulePolicies.Values)
            {
                // Validate the module specific configurations
                success &= ValidateModuleConfig(moduleConfiguration, pathTable, loggingContext, mutableConfig.Sandbox);
            }

            // Directory translation.
            success &= ValidateSubstAndDirectoryTranslation(mutableConfig, pathTable, loggingContext);

            // Configure Ide Generation if it is enabled
            if (mutableConfig.Ide.IsEnabled)
            {
                IdeGenerator.Configure(mutableConfig, initialCommandLineConfiguration.Startup, pathTable);
            }

            var frontEndConfig = mutableConfig.FrontEnd;

            // Incremental frontend is turned off for office.
            if (frontEndConfig.UseLegacyOfficeLogic == true)
            {
                frontEndConfig.EnableIncrementalFrontEnd = false;
            }

            // Reusing ast and public facade implies that the binding fingerprint is saved
            // It also implies that we need to partially reload the engine state, since consistent
            // tables across builds are needed
            if (frontEndConfig.UseSpecPublicFacadeAndAstWhenAvailable())
            {
                frontEndConfig.ConstructAndSaveBindingFingerprint = true;
                frontEndConfig.ReloadPartialEngineStateWhenPossible = true;
            }

            if (mutableConfig.Schedule.ForceSkipDependencies != ForceSkipDependenciesMode.Disabled)
            {
                // Lazy materialization is not compatible with force skip dependencies
                mutableConfig.Schedule.EnableLazyOutputMaterialization = false;
            }

            if (mutableConfig.Schedule.AdaptiveIO)
            {
                Contract.Assert(mutableConfig.Logging.LogCounters, "AdaptiveIO requires the logCounters flag");

                // If the adaptive IO is enabled and the user does not pass a custom maxIO value, then use the number of processors as the IO limit.
                mutableConfig.Schedule.MaxIO = Environment.ProcessorCount;

                // If the adaptive IO is enabled and the user does not pass a custom statusFrequencyMs, then use 1000ms as a statusFrequency.
                // In the interval of 1000ms, both status messages will be printed on console and the maximum limit for the IO will be adjusted.
                if (mutableConfig.Logging.StatusFrequencyMs == 0)
                {
                    mutableConfig.Logging.StatusFrequencyMs = 1000;
                }
            }

            if (!mutableConfig.Logging.FailPipOnFileAccessError)
            {
                mutableConfig.Sandbox.UnsafeSandboxConfigurationMutable.UnexpectedFileAccessesAreErrors = false;
            }

            if (mutableConfig.Schedule.UnsafeLazySODeletion &&
                mutableConfig.Sandbox.UnsafeSandboxConfigurationMutable.SandboxKind == SandboxKind.None)
            {
                mutableConfig.Schedule.UnsafeLazySODeletion = false;
            }

            if (mutableConfig.Schedule.UnsafeLazySODeletion)
            {
                // must compute static fingerprints when using lazy shared opaque output deletion
                mutableConfig.Schedule.ComputePipStaticFingerprints = true;
            }

            // Turn off incremental scheduling when incompatible features are enabled.
            if (mutableConfig.Schedule.IncrementalScheduling)
            {
                if (!mutableConfig.Cache.Incremental)
                {
                    // If incremental is turned off, incremental scheduling should be too. Don't bother logging.
                    mutableConfig.Schedule.IncrementalScheduling = false;
                }

                if (!mutableConfig.Engine.ScanChangeJournal)
                {
                    // If scan change journal is turned off, incremental scheduling should be too. Don't bother logging.
                    mutableConfig.Schedule.IncrementalScheduling = false;
                }

                if (mutableConfig.Cache.FileChangeTrackingExclusionRoots.Count != 0)
                {
                    mutableConfig.Schedule.IncrementalScheduling = false;
                    Logger.Log.ConfigIncompatibleIncrementalSchedulingDisabled(loggingContext, "/fileChangeTrackingExclusionRoot");
                }

                if (mutableConfig.Cache.FileChangeTrackingInclusionRoots.Count != 0)
                {
                    mutableConfig.Schedule.IncrementalScheduling = false;
                    Logger.Log.ConfigIncompatibleIncrementalSchedulingDisabled(loggingContext, "/fileChangeTrackingInclusionRoot");
                }

                if (mutableConfig.Schedule.SkipHashSourceFile)
                {
                    mutableConfig.Schedule.IncrementalScheduling = false;
                    Logger.Log.ConfigIncompatibleIncrementalSchedulingDisabled(loggingContext, "/skipHashSourceFile");
                }

                // If incremental scheduling is still on, then we need to compute the static fingerprints.
                if (mutableConfig.Schedule.IncrementalScheduling)
                {
                    mutableConfig.Schedule.ComputePipStaticFingerprints = true;
                }
            }

            // Environment-specific defaults/behaviors
            mutableConfig.Schedule.EnvironmentFingerprint = I($"RunningEnvironment:{mutableConfig.Logging.Environment}|InCloudBuild:{mutableConfig.InCloudBuild()}");

            // Distributed build overrides (including all CB builds because one worker CB builds are configured as distributed)
            if (mutableConfig.Distribution.BuildRole != DistributedBuildRoles.None)
            {
                mutableConfig.Schedule.ScheduleMetaPips = false;

                if (!mutableConfig.Schedule.StoreOutputsToCache)
                {
                    mutableConfig.Schedule.StoreOutputsToCache = true;
                    Logger.Log.ConfigIncompatibleOptionWithDistributedBuildWarn(
                        loggingContext,
                        "/storeOutputsToCache",
                        mutableConfig.Schedule.StoreOutputsToCache.ToString(CultureInfo.InvariantCulture),
                        true.ToString(CultureInfo.InvariantCulture));
                }

                if (mutableConfig.Sandbox.UnsafeSandboxConfiguration.PreserveOutputs != PreserveOutputsMode.Disabled)
                {
                    mutableConfig.Sandbox.UnsafeSandboxConfigurationMutable.PreserveOutputs = PreserveOutputsMode.Disabled;
                    Logger.Log.ConfigIncompatibleOptionWithDistributedBuildWarn(
                        loggingContext,
                        "/unsafe_PreserveOutputs",
                        mutableConfig.Sandbox.UnsafeSandboxConfiguration.PreserveOutputs.ToString(),
                        PreserveOutputsMode.Disabled.ToString());
                }
            }

            if (mutableConfig.Sandbox.UnsafeSandboxConfiguration.IgnorePreserveOutputsPrivatization
                && mutableConfig.Sandbox.UnsafeSandboxConfiguration.PreserveOutputs != PreserveOutputsMode.Disabled
                && mutableConfig.Schedule.StoreOutputsToCache)
            {
                Logger.Log.ConfigIncompatibleOptionIgnorePreserveOutputsPrivatization(loggingContext);
                success = false;
            }

            // CloudBuild overrides
            if (mutableConfig.InCloudBuild())
            {
                if (mutableConfig.Schedule.MinimumDiskSpaceForPipsGb == null)
                {
                    mutableConfig.Schedule.MinimumDiskSpaceForPipsGb = 5;
                }

                if (mutableConfig.Distribution.NumRetryFailedPipsOnAnotherWorker == null)
                {
                    mutableConfig.Distribution.NumRetryFailedPipsOnAnotherWorker = 3;
                }

                // Enable fail fast for null reference exceptions caught by
                // ExceptionUtilities.IsUnexpectedException
                EngineEnvironmentSettings.FailFastOnNullReferenceException.Value = true;
                EngineEnvironmentSettings.SkipExtraneousPins.TrySet(true);

                mutableConfig.Engine.ScanChangeJournal = false;
                mutableConfig.Schedule.IncrementalScheduling = false;

                // lazy scrubbing is only meant for speeding up single-machine dev builds
                mutableConfig.Schedule.UnsafeLazySODeletion = false;

                // Disable viewer
                mutableConfig.Viewer = ViewerMode.Disable;

                // Enable historic ram and CPU based throttling in CloudBuild by default if it is not explicitly disabled.
                mutableConfig.Schedule.UseHistoricalRamUsageInfo = initialCommandLineConfiguration.Schedule.UseHistoricalRamUsageInfo ?? true;

                mutableConfig.Schedule.UseHistoricalCpuUsageInfo = initialCommandLineConfiguration.Schedule.UseHistoricalCpuUsageInfo ?? true;

                mutableConfig.Cache.FileContentTableEntryTimeToLive = mutableConfig.Cache.FileContentTableEntryTimeToLive ?? 100;

                // Minimize output materialization in cloudbuild
                mutableConfig.Schedule.EnableLazyWriteFileMaterialization = true;
                mutableConfig.Schedule.WriteIpcOutput = false;
                if (!mutableConfig.Logging.ReplayWarnings.HasValue)
                {
                    mutableConfig.Logging.ReplayWarnings = false;
                }

                // Use compression for graph files to greatly reduce the size
                mutableConfig.Engine.CompressGraphFiles = true;

                // Ensure that historic perf data is retrieved from cache because engine cache
                // can be reused for multiple locations
                mutableConfig.Schedule.ForceUseEngineInfoFromCache = true;
                mutableConfig.Cache.HistoricMetadataCache = initialCommandLineConfiguration.Cache.HistoricMetadataCache ?? true;

                // In CB we don't actually want this to become a parameter that is actively used, so make it large enough
                mutableConfig.Schedule.MinimumTotalAvailableRamMb = initialCommandLineConfiguration.Schedule.MinimumTotalAvailableRamMb ?? 100000000;
                mutableConfig.Schedule.ScheduleMetaPips = false;

                // In CloudBuild always place EngineCache under object directory
                mutableConfig.Layout.EngineCacheDirectory = mutableConfig.Layout.ObjectDirectory.Combine(pathTable, Strings.Layout_DefaultEngineCacheFolderName);

                // Add additional context to environment fingerprint
                foreach (var entry in mutableConfig.Logging.TraceInfo)
                {
                    if (entry.Key.Equals(TraceInfoExtensions.CustomFingerprint, StringComparison.OrdinalIgnoreCase))
                    {
                        mutableConfig.Schedule.EnvironmentFingerprint += I($"|{TraceInfoExtensions.CustomFingerprint}:{entry.Value}");
                    }
                    else if (entry.Key.Equals(TraceInfoExtensions.CloudBuildQueue, StringComparison.OrdinalIgnoreCase))
                    {
                        mutableConfig.Schedule.EnvironmentFingerprint += I($"|{TraceInfoExtensions.CloudBuildQueue}:{entry.Value}");
                    }
                }

                if (mutableConfig.Logging.CacheMissAnalysisOption.Mode == CacheMissMode.Local)
                {
                    // BuildXL should not use local fingerprintstore for cache miss analysis.
                    // Because you do not know how old is that fingerprintstore, the data is not really useful.
                    mutableConfig.Logging.CacheMissAnalysisOption.Mode = CacheMissMode.Disabled;
                }

                mutableConfig.Logging.StoreFingerprints = initialCommandLineConfiguration.Logging.StoreFingerprints ?? false;
                mutableConfig.Sandbox.RetryOnAzureWatsonExitCode = true;

                // Spec cache is disabled as most builds are happening on SSDs.
                mutableConfig.Cache.CacheSpecs = SpecCachingOption.Disabled;

                if (mutableConfig.Logging.Environment == ExecutionEnvironment.OsgLab)
                {
                    // For Cosine builds in CloudBuild, enable delayedCacheLookup by default.
                    if (mutableConfig.Schedule.DelayedCacheLookupMaxMultiplier == null &&
                        mutableConfig.Schedule.DelayedCacheLookupMinMultiplier == null)
                    {
                        mutableConfig.Schedule.DelayedCacheLookupMaxMultiplier = 2;
                        mutableConfig.Schedule.DelayedCacheLookupMinMultiplier = 1;
                    }

                    // For Cosine builds, IsObsoleteCheck is very expensive, so we disable it.
                    // Cosine specs are automatically generated, so that check was not necessary.
                    mutableConfig.FrontEnd.DisableIsObsoleteCheckDuringConversion = true;

                    // Early worker release gives very small benefit (1-2%) to Cosine builds, 
                    // so it is disabled.
                    mutableConfig.Distribution.EarlyWorkerRelease = false;
                }

                if (mutableConfig.Schedule.ManageMemoryMode == null)
                {
                    // If ManageMemoryMode is unset for CB builds, we use EmptyWorkingSet option due to the large page file size in CB machines.
                    mutableConfig.Schedule.ManageMemoryMode = ManageMemoryMode.EmptyWorkingSet;
                }

                // Since VFS lives inside BXL process currently. Disallow on office enlist and meta build because
                // they materialize files which would be needed by subsequent invocations and thus requires VFS to
                // span multiple invocations. Just starting at Product build is sufficient.
                if (mutableConfig.Logging.Environment == ExecutionEnvironment.OfficeMetaBuildLab
                    || mutableConfig.Logging.Environment == ExecutionEnvironment.OfficeEnlistmentBuildLab)
                {
                    mutableConfig.Cache.VfsCasRoot = AbsolutePath.Invalid;
                }

                // Unless otherwise specified, distributed metabuilds in CloudBuild should replicate outputs to all machines
                // TODO: Remove this once reduced metabuild materialization is fully tested
                if (mutableConfig.Distribution.ReplicateOutputsToWorkers == null
                    && mutableConfig.Logging.Environment == ExecutionEnvironment.OfficeMetaBuildLab
                    && mutableConfig.Distribution.BuildRole.IsOrchestrator())
                {
                    mutableConfig.Distribution.ReplicateOutputsToWorkers = true;
                }

                // When running in cloudbuild we want to ignore the user setting the interactive flag
                // and force it to be false since we never want to pop up UI there.
                mutableConfig.Interactive = false;

                // Fire forget materialize output is enabled by default in CloudBuild as it improves the perf during meta build.
                mutableConfig.Distribution.FireForgetMaterializeOutput = initialCommandLineConfiguration.Distribution.FireForgetMaterializeOutput ?? true;
            }
            else
            {
                mutableConfig.Logging.StoreFingerprints = initialCommandLineConfiguration.Logging.StoreFingerprints ?? true;
            }

            // If graph patching is requested, we need to reload the engine state when possible
            if (frontEndConfig.UseGraphPatching())
            {
                frontEndConfig.ReloadPartialEngineStateWhenPossible = true;
            }

            // If incremental is turned off, HistoricMetadataCache should also be turned off.
            if (!mutableConfig.Cache.Incremental)
            {
                mutableConfig.Cache.HistoricMetadataCache = false;
            }

            // If runtime cache miss analysis is enabled, the fingerprint store is required.
            if (mutableConfig.Logging.CacheMissAnalysisOption.Mode != CacheMissMode.Disabled)
            {
                mutableConfig.Logging.StoreFingerprints = true;
            }

            // When replicating outputs to workers, workers cannot be released early.
            if (mutableConfig.Distribution.ReplicateOutputsToWorkers == true)
            {
                mutableConfig.Distribution.EarlyWorkerRelease = false;
            }

            if (mutableConfig.Cache.VfsCasRoot.IsValid)
            {
                // VFS CAS root should be untracked for purposes of sandboxing.
                mutableConfig.Sandbox.GlobalUnsafeUntrackedScopes.Add(mutableConfig.Cache.VfsCasRoot);
            }

            return success;
        }