// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Frozen; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Threading; using Microsoft.Build.BackEnd; using Microsoft.Build.Collections; using Microsoft.Build.Evaluation; using Microsoft.Build.Framework; using Microsoft.Build.Graph; using Microsoft.Build.Internal; using Microsoft.Build.ProjectCache; using Microsoft.Build.Shared; using Microsoft.Build.Shared.FileSystem; using ForwardingLoggerRecord = Microsoft.Build.Logging.ForwardingLoggerRecord; #nullable disable namespace Microsoft.Build.Execution { using Utilities = Microsoft.Build.Internal.Utilities; /// /// This class represents all of the settings which must be specified to start a build. /// public class BuildParameters : ITranslatable { /// /// The default thread stack size for threads owned by MSBuild. /// private const int DefaultThreadStackSize = 262144; // 256k /// /// The timeout for endpoints to shut down. /// private const int DefaultEndpointShutdownTimeout = 30 * 1000; // 30 seconds /// /// The timeout for the engine to shutdown. /// private const int DefaultEngineShutdownTimeout = Timeout.Infinite; /// /// The shutdown timeout for the logging thread. /// private const int DefaultLoggingThreadShutdownTimeout = 30 * 1000; // 30 seconds /// /// The shutdown timeout for the request builder. /// private const int DefaultRequestBuilderShutdownTimeout = Timeout.Infinite; /// /// The maximum number of idle request builders to retain before we start discarding them. /// private const int DefaultIdleRequestBuilderLimit = 2; /// /// The startup directory. /// private static string s_startupDirectory = Environment.CurrentDirectory; /// /// Indicates whether we should warn when a property is uninitialized when it is used. /// private static bool? s_warnOnUninitializedProperty; /// /// Indicates if we should dump string interning stats. /// private static bool? s_dumpStringInterningStats; /// /// Indicates if we should debug the expander. /// private static bool? s_debugExpansion; /// /// Indicates if we should keep duplicate target outputs. /// private static bool? s_keepDuplicateOutputs; /// /// Indicates if we should enable the build plan /// private static bool? s_enableBuildPlan; /// /// The maximum number of idle request builders we will retain. /// private static int? s_idleRequestBuilderLimit; /// /// Location that msbuild.exe was last successfully found at. /// private static string s_msbuildExeKnownToExistAt; /// /// The build id /// private int _buildId; /// /// The culture /// private CultureInfo _culture = CultureInfo.CurrentCulture; /// /// The default tools version. /// private string _defaultToolsVersion = "2.0"; /// /// Flag indicating whether node reuse should be enabled. /// By default, it is enabled. /// private bool _enableNodeReuse = true; private bool _enableRarNode; /// /// The original process environment. /// private FrozenDictionary _buildProcessEnvironment; /// /// The environment properties for the build. /// private PropertyDictionary _environmentProperties = new PropertyDictionary(); /// /// The forwarding logger records. /// private IEnumerable _forwardingLoggers; /// /// The build-global properties. /// private PropertyDictionary _globalProperties = new PropertyDictionary(); /// /// Properties passed from the command line (e.g. by using /p:). /// private ICollection _propertiesFromCommandLine; /// /// The loggers. /// private IEnumerable _loggers; /// /// The maximum number of nodes to use. /// private int _maxNodeCount = 1; /// /// The maximum amount of memory to use. /// private int _memoryUseLimit; // Default 0 = unlimited /// /// The location of the node exe. This is the full path including the exe file itself. /// private string _nodeExeLocation; /// /// Flag indicating if we should only log critical events. /// private bool _onlyLogCriticalEvents; private bool _enableTargetOutputLogging; /// /// The UI culture. /// private CultureInfo _uiCulture = CultureInfo.CurrentUICulture; /// /// The toolset provider /// private ToolsetProvider _toolsetProvider; /// /// Should the logging service be done Synchronously when the number of cps's is 1 /// private bool _useSynchronousLogging; /// /// Should the inprocess node be shutdown when the build finishes. By default this is false /// since visual studio needs to keep the inprocess node around after the build has finished. /// private bool _shutdownInProcNodeOnBuildFinish; /// /// When true, the in-proc node will not be available. /// private bool _disableInProcNode; /// /// When true, the build should log task inputs to the loggers. /// private bool _logTaskInputs; /// /// When true, the build should log the input parameters. Note - logging these is very expensive! /// private bool _logInitialPropertiesAndItems; private bool _question; private bool _isBuildCheckEnabled; private bool _isTelemetryEnabled; /// /// The settings used to load the project under build /// private ProjectLoadSettings _projectLoadSettings = ProjectLoadSettings.Default; private bool _interactive; /// /// When true, enables running build in multiple in-proc nodes. /// private bool _multiThreaded; private ProjectIsolationMode _projectIsolationMode; private string[] _inputResultsCacheFiles; private string _outputResultsCacheFile; private bool _reportFileAccesses; /// /// The configuration for allowed unknown attributes/elements during parsing. /// Loaded on the main node and serialized to worker nodes. /// private ParserIgnoreConfiguration _ParserIgnoreConfiguration = ParserIgnoreConfiguration.Empty; /// /// Constructor for those who intend to set all properties themselves. /// public BuildParameters() { Initialize(Utilities.GetEnvironmentProperties(makeReadOnly: false), new ProjectRootElementCache(false), null); } /// /// Creates BuildParameters from a ProjectCollection. /// /// The ProjectCollection from which the BuildParameters should populate itself. public BuildParameters(ProjectCollection projectCollection) { ArgumentNullException.ThrowIfNull(projectCollection); Initialize(new PropertyDictionary(projectCollection.EnvironmentProperties), projectCollection.ProjectRootElementCache, new ToolsetProvider(projectCollection.Toolsets)); _maxNodeCount = projectCollection.MaxNodeCount; _onlyLogCriticalEvents = projectCollection.OnlyLogCriticalEvents; _enableTargetOutputLogging = projectCollection.EnableTargetOutputLogging; ToolsetDefinitionLocations = projectCollection.ToolsetLocations; _defaultToolsVersion = projectCollection.DefaultToolsVersion; _globalProperties = new PropertyDictionary(projectCollection.GlobalPropertiesCollection); _propertiesFromCommandLine = projectCollection.PropertiesFromCommandLine; _ParserIgnoreConfiguration = projectCollection.ParserIgnoreConfiguration; } /// /// Private constructor for translation /// private BuildParameters(ITranslator translator) { ((ITranslatable)this).Translate(translator); } /// /// Copy constructor /// internal BuildParameters(BuildParameters other, bool resetEnvironment = false) { Assumed.NotNull(other); _buildId = other._buildId; _culture = other._culture; _defaultToolsVersion = other._defaultToolsVersion; _enableNodeReuse = other._enableNodeReuse; _enableRarNode = other._enableRarNode; _buildProcessEnvironment = resetEnvironment ? CommunicationsUtilities.GetEnvironmentVariables() : other._buildProcessEnvironment; _environmentProperties = other._environmentProperties != null ? new PropertyDictionary(other._environmentProperties) : null; _forwardingLoggers = other._forwardingLoggers != null ? new List(other._forwardingLoggers) : null; _globalProperties = other._globalProperties != null ? new PropertyDictionary(other._globalProperties) : null; _propertiesFromCommandLine = other._propertiesFromCommandLine != null ? new HashSet(other._propertiesFromCommandLine, StringComparer.OrdinalIgnoreCase) : null; HostServices = other.HostServices; _loggers = other._loggers != null ? new List(other._loggers) : null; _maxNodeCount = other._maxNodeCount; MultiThreaded = other.MultiThreaded; _memoryUseLimit = other._memoryUseLimit; _nodeExeLocation = other._nodeExeLocation; NodeId = other.NodeId; _onlyLogCriticalEvents = other._onlyLogCriticalEvents; BuildThreadPriority = other.BuildThreadPriority; _toolsetProvider = other._toolsetProvider; ToolsetDefinitionLocations = other.ToolsetDefinitionLocations; _toolsetProvider = other._toolsetProvider; _uiCulture = other._uiCulture; DetailedSummary = other.DetailedSummary; _shutdownInProcNodeOnBuildFinish = other._shutdownInProcNodeOnBuildFinish; ProjectRootElementCache = other.ProjectRootElementCache; ResetCaches = other.ResetCaches; LegacyThreadingSemantics = other.LegacyThreadingSemantics; SaveOperatingEnvironment = other.SaveOperatingEnvironment; _useSynchronousLogging = other._useSynchronousLogging; _disableInProcNode = other._disableInProcNode; _logTaskInputs = other._logTaskInputs; _logInitialPropertiesAndItems = other._logInitialPropertiesAndItems; WarningsAsErrors = other.WarningsAsErrors == null ? null : new HashSet(other.WarningsAsErrors, StringComparer.OrdinalIgnoreCase); WarningsNotAsErrors = other.WarningsNotAsErrors == null ? null : new HashSet(other.WarningsNotAsErrors, StringComparer.OrdinalIgnoreCase); WarningsAsMessages = other.WarningsAsMessages == null ? null : new HashSet(other.WarningsAsMessages, StringComparer.OrdinalIgnoreCase); _projectLoadSettings = other._projectLoadSettings; _interactive = other._interactive; _projectIsolationMode = other.ProjectIsolationMode; _inputResultsCacheFiles = other._inputResultsCacheFiles; _outputResultsCacheFile = other._outputResultsCacheFile; _reportFileAccesses = other._reportFileAccesses; DiscardBuildResults = other.DiscardBuildResults; LowPriority = other.LowPriority; Question = other.Question; IsBuildCheckEnabled = other.IsBuildCheckEnabled; IsTelemetryEnabled = other.IsTelemetryEnabled; ProjectCacheDescriptor = other.ProjectCacheDescriptor; _enableTargetOutputLogging = other.EnableTargetOutputLogging; _ParserIgnoreConfiguration = other._ParserIgnoreConfiguration; } /// /// Gets or sets the desired thread priority for building. /// public ThreadPriority BuildThreadPriority { get; set; } = ThreadPriority.Normal; /// /// By default if the number of processes is set to 1 we will use Asynchronous logging. However if we want to use synchronous logging when the number of cpu's is set to 1 /// this property needs to be set to true. /// public bool UseSynchronousLogging { get => _useSynchronousLogging; set => _useSynchronousLogging = value; } /// /// Properties passed from the command line (e.g. by using /p:). /// public ICollection PropertiesFromCommandLine => _propertiesFromCommandLine; /// /// Indicates whether to emit a default error if a task returns false without logging an error. /// public bool AllowFailureWithoutError { get; set; } = false; /// /// Gets the environment variables which were set when this build was created. /// public IDictionary BuildProcessEnvironment => BuildProcessEnvironmentInternal; internal void SetBuildProcessEnvironmentVariable(string name, string value) { Dictionary environment = new(BuildProcessEnvironmentInternal, CommunicationsUtilities.EnvironmentVariableComparer); if (value is null) { environment.Remove(name); } else { environment[name] = value; } _buildProcessEnvironment = environment.ToFrozenDictionary(CommunicationsUtilities.EnvironmentVariableComparer); } /// /// The name of the culture to use during the build. /// public CultureInfo Culture { get => _culture; set => _culture = value; } /// /// The default tools version for the build. /// public string DefaultToolsVersion { get => _defaultToolsVersion; set => _defaultToolsVersion = value; } /// /// When true, indicates that the build should emit a detailed summary at the end of the log. /// public bool DetailedSummary { get; set; } /// /// When true, indicates the in-proc node should not be used. /// public bool DisableInProcNode { get => _disableInProcNode; set => _disableInProcNode = value; } /// /// When true, indicates that the task parameters should be logged. /// public bool LogTaskInputs { get => _logTaskInputs; set => _logTaskInputs = value; } /// /// When true, indicates that the initial properties and items should be logged. /// public bool LogInitialPropertiesAndItems { get => _logInitialPropertiesAndItems; set => _logInitialPropertiesAndItems = value; } /// /// Indicates that the build should reset the configuration and results caches. /// public bool ResetCaches { get; set; } /// /// Flag indicating whether out-of-proc nodes should remain after the build and wait for further builds. /// public bool EnableNodeReuse { get => _enableNodeReuse; set => _enableNodeReuse = Environment.GetEnvironmentVariable("MSBUILDDISABLENODEREUSE") == "1" ? false : value; } /// /// When true, the ResolveAssemblyReferences task executes in an out-of-proc node which persists across builds. /// public bool EnableRarNode { get => _enableRarNode; set => _enableRarNode = value; } /// /// Gets an immutable collection of environment properties. /// /// /// This differs from the BuildProcessEnvironment in that there are certain MSBuild-specific properties which are added, and those environment variables which /// would not be valid as MSBuild properties are removed. /// public IDictionary EnvironmentProperties { get { return new ReadOnlyConvertingDictionary(_environmentProperties, instance => ((IProperty)instance).EvaluatedValueEscaped); } } /// /// The collection of forwarding logger descriptions. /// public IEnumerable ForwardingLoggers { get => _forwardingLoggers; set { if (value != null) { foreach (ForwardingLoggerRecord logger in value) { ErrorUtilities.VerifyThrowArgumentNull(logger, nameof(ForwardingLoggers), "NullLoggerNotAllowed"); } } _forwardingLoggers = value; } } /// /// Sets or retrieves an immutable collection of global properties. /// [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "Accessor returns a readonly collection, and the BuildParameters class is immutable.")] public IDictionary GlobalProperties { get { return new ReadOnlyConvertingDictionary(_globalProperties, instance => ((IProperty)instance).EvaluatedValueEscaped); } set { _globalProperties = new PropertyDictionary(value.Count); foreach (KeyValuePair property in value) { _globalProperties[property.Key] = ProjectPropertyInstance.Create(property.Key, property.Value); } } } /// /// Interface allowing the host to provide additional control over the build process. /// public HostServices HostServices { get; set; } /// /// Enables or disables legacy threading semantics /// /// /// Legacy threading semantics indicate that if a submission is to be built /// only on the in-proc node and the submission is executed synchronously, then all of its /// requests will be built on the thread which invoked the build rather than a /// thread owned by the BuildManager. /// public bool LegacyThreadingSemantics { get; set; } /// /// The collection of loggers to use during the build. /// public IEnumerable Loggers { get => _loggers; set { if (value != null) { foreach (ILogger logger in value) { ErrorUtilities.VerifyThrowArgumentNull(logger, "Loggers", "NullLoggerNotAllowed"); } } _loggers = value; } } /// /// The maximum number of nodes this build may use. /// public int MaxNodeCount { get => _maxNodeCount; set { ErrorUtilities.VerifyThrowArgument(value > 0, "InvalidMaxNodeCount"); _maxNodeCount = value; } } /// /// Enables running build in multiple in-proc nodes. /// public bool MultiThreaded { get => _multiThreaded; set => _multiThreaded = value; } /// /// The amount of memory the build should limit itself to using, in megabytes. /// public int MemoryUseLimit { get => _memoryUseLimit; set => _memoryUseLimit = value; } /// /// The location of the build node executable. /// public string NodeExeLocation { get => _nodeExeLocation; set => _nodeExeLocation = value; } /// /// Flag indicating if non-critical logging events should be discarded. /// public bool OnlyLogCriticalEvents { get => _onlyLogCriticalEvents; set => _onlyLogCriticalEvents = value; } /// /// When true, target outputs (and returns) are logged as well. /// public bool EnableTargetOutputLogging { get => _enableTargetOutputLogging; set => _enableTargetOutputLogging = value; } /// /// A list of warnings to treat as errors. To treat all warnings as errors, set this to an empty . /// public ISet WarningsAsErrors { get; set; } /// /// A list of warnings to not treat as errors. Only has any effect if WarningsAsErrors is empty. /// public ISet WarningsNotAsErrors { get; set; } /// /// A list of warnings to treat as low importance messages. /// public ISet WarningsAsMessages { get; set; } /// /// Locations to search for toolsets. /// public ToolsetDefinitionLocations ToolsetDefinitionLocations { get; set; } = ToolsetDefinitionLocations.Default; /// /// Returns all of the toolsets. /// /// /// toolsetProvider.Toolsets is already a readonly collection. /// public ICollection Toolsets => ToolsetProvider.Toolsets; /// /// The name of the UI culture to use during the build. /// public CultureInfo UICulture { get => _uiCulture; set => _uiCulture = value; } /// /// Flag indicating if the operating environment such as the current directory and environment be saved and restored between project builds and task invocations. /// This should be set to false for any other build managers running in the system so that we do not have two build managers trampling on each others environment. /// public bool SaveOperatingEnvironment { get; set; } = true; /// /// Shutdown the inprocess node when the build finishes. By default this is false /// since visual studio needs to keep the inprocess node around after the build finishes. /// public bool ShutdownInProcNodeOnBuildFinish { get => _shutdownInProcNodeOnBuildFinish; set => _shutdownInProcNodeOnBuildFinish = value; } /// /// Gets the internal msbuild thread stack size. /// internal static int ThreadStackSize => EnvironmentUtilities.GetValueAsInt32OrDefault("MSBUILDTHREADSTACKSIZE", DefaultThreadStackSize); /// /// Gets the endpoint shutdown timeout. /// internal static int EndpointShutdownTimeout => EnvironmentUtilities.GetValueAsInt32OrDefault("MSBUILDENDPOINTSHUTDOWNTIMEOUT", DefaultEndpointShutdownTimeout); /// /// Gets or sets the engine shutdown timeout. /// internal static int EngineShutdownTimeout => EnvironmentUtilities.GetValueAsInt32OrDefault("MSBUILDENGINESHUTDOWNTIMEOUT", DefaultEngineShutdownTimeout); /// /// Gets the maximum number of idle request builders to retain. /// internal static int IdleRequestBuilderLimit => s_idleRequestBuilderLimit ??= EnvironmentUtilities.GetValueAsInt32OrDefault("MSBUILDIDLEREQUESTBUILDERLIMIT", DefaultIdleRequestBuilderLimit); /// /// Gets the logging thread shutdown timeout. /// internal static int LoggingThreadShutdownTimeout => EnvironmentUtilities.GetValueAsInt32OrDefault("MSBUILDLOGGINGTHREADSHUTDOWNTIMEOUT", DefaultLoggingThreadShutdownTimeout); /// /// Gets the request builder shutdown timeout. /// internal static int RequestBuilderShutdownTimeout => EnvironmentUtilities.GetValueAsInt32OrDefault("MSBUILDREQUESTBUILDERSHUTDOWNTIMEOUT", DefaultRequestBuilderShutdownTimeout); /// /// Gets the startup directory. /// It is current directory from which MSBuild command line was recently invoked. /// It is communicated to working nodes as part of NodeConfiguration deserialization once the node manager acquires a particular node. /// This deserialization assign this value to static backing field making it accessible from rest of build thread. /// In MSBuild server node, this value is set once is received. /// internal static string StartupDirectory { get { return s_startupDirectory; } set { s_startupDirectory = value; } } /// /// Indicates whether the build plan is enabled or not. /// internal static bool EnableBuildPlan => s_enableBuildPlan ??= EnvironmentUtilities.ValueExistsOrDefault("MSBUILDENABLEBUILDPLAN", false); /// /// Indicates whether we should warn when a property is uninitialized when it is used. /// internal static bool WarnOnUninitializedProperty { get => s_warnOnUninitializedProperty ??= EnvironmentUtilities.ValueExistsOrDefault("MSBUILDWARNONUNINITIALIZEDPROPERTY", false); set => s_warnOnUninitializedProperty = value; } /// /// Indicates whether we should dump string interning stats /// internal static bool DumpOpportunisticInternStats => s_dumpStringInterningStats ??= EnvironmentUtilities.ValueExistsOrDefault("MSBUILDDUMPOPPORTUNISTICINTERNSTATS", false); /// /// Indicates whether we should dump debugging information about the expander /// internal static bool DebugExpansion => s_debugExpansion ??= EnvironmentUtilities.ValueExistsOrDefault("MSBUILDDEBUGEXPANSION", false); /// /// Indicates whether we should keep duplicate target outputs /// internal static bool KeepDuplicateOutputs => s_keepDuplicateOutputs ??= EnvironmentUtilities.ValueExistsOrDefault("MSBUILDKEEPDUPLICATEOUTPUTS", false); /// /// Gets or sets the build id. /// internal int BuildId { get => _buildId; set => _buildId = value; } internal FrozenDictionary BuildProcessEnvironmentInternal => _buildProcessEnvironment ?? FrozenDictionary.Empty; /// /// Gets or sets the environment properties. /// /// /// This is not the same as BuildProcessEnvironment. See EnvironmentProperties. These properties are those which /// are used during evaluation of a project, and exclude those properties which would not be valid MSBuild properties /// because they contain invalid characters (such as 'Program Files (x86)'). /// internal PropertyDictionary EnvironmentPropertiesInternal { get => _environmentProperties; set { Assumed.NotNull(value, valueExpression: "EnvironmentPropertiesInternal"); _environmentProperties = value; } } /// /// Gets the global properties. /// internal PropertyDictionary GlobalPropertiesInternal => _globalProperties; /// /// Gets or sets the node id. /// internal int NodeId { get; set; } /// /// Gets the toolset provider. /// internal IToolsetProvider ToolsetProvider { get { EnsureToolsets(); return _toolsetProvider; } } /// /// The one and only project root element cache to be used for the build. /// internal ProjectRootElementCacheBase ProjectRootElementCache { get; set; } #if FEATURE_APPDOMAIN /// /// Information for configuring child AppDomains. /// internal AppDomainSetup AppDomainSetup { get; set; } #endif /// /// (for diagnostic use) Whether or not this is out of proc /// internal bool IsOutOfProc { get; set; } /// public ProjectLoadSettings ProjectLoadSettings { get => _projectLoadSettings; set => _projectLoadSettings = value; } /// /// Gets or sets the configuration for allowed unknown attributes/elements during parsing. /// When set, this configuration is used for parsing and evaluation. /// internal ParserIgnoreConfiguration ParserIgnoreConfiguration { get => _ParserIgnoreConfiguration; set => _ParserIgnoreConfiguration = value; } /// /// Gets or sets a value indicating if the build is allowed to interact with the user. /// public bool Interactive { get => _interactive; set => _interactive = value; } /// /// Gets or sets a value indicating the isolation mode to use. /// /// /// Kept for API backwards compatibility. /// public bool IsolateProjects { get => ProjectIsolationMode == ProjectIsolationMode.True; set => ProjectIsolationMode = value ? ProjectIsolationMode.True : ProjectIsolationMode.False; } /// /// Gets or sets a value indicating the isolation mode to use. /// public ProjectIsolationMode ProjectIsolationMode { get => _projectIsolationMode; set => _projectIsolationMode = value; } /// /// Input cache files that MSBuild will use to read build results from. /// If the isolation mode is set to , /// this sets the isolation mode to . /// public string[] InputResultsCacheFiles { get => _inputResultsCacheFiles; set => _inputResultsCacheFiles = value; } /// /// Output cache file where MSBuild will write the contents of its build result caches during EndBuild. /// If the isolation mode is set to , /// this sets the isolation mode to . /// public string OutputResultsCacheFile { get => _outputResultsCacheFile; set => _outputResultsCacheFile = value; } #if FEATURE_REPORTFILEACCESSES /// /// Gets or sets a value indicating whether file accesses should be reported to any configured project cache plugins. /// public bool ReportFileAccesses { get => _reportFileAccesses; set => _reportFileAccesses = value; } #endif /// /// Determines whether MSBuild will save the results of builds after EndBuild to speed up future builds. /// public bool DiscardBuildResults { get; set; } = false; /// /// Gets or sets a value indicating whether the build process should run as low priority. /// public bool LowPriority { get; set; } /// /// Gets or sets a value that will error when the build process fails an incremental check. /// public bool Question { get => _question; set => _question = value; } /// /// Gets or sets an indication of build check enablement. /// public bool IsBuildCheckEnabled { get => _isBuildCheckEnabled; set => _isBuildCheckEnabled = value; } /// /// Gets or sets an indication if telemetry is enabled. /// This is reserved for future usage - we will likely add a whole dictionary of enablement per telemetry namespace /// as we plan to have variable sampling rate per various sources. /// internal bool IsTelemetryEnabled { get => _isTelemetryEnabled; set => _isTelemetryEnabled = value; } /// /// Gets or sets the project cache description to use for all or /// in addition to any potential project caches described in each project. /// /// /// This property had the type "Experimental.ProjectCache.ProjectCacheDescriptor" until 17.14 (inclusive). /// public ProjectCacheDescriptor ProjectCacheDescriptor { get; set; } /// /// Retrieves a toolset. /// public Toolset GetToolset(string toolsVersion) { EnsureToolsets(); return _toolsetProvider.GetToolset(toolsVersion); } /// /// Creates a clone of this BuildParameters object. This creates a clone of the logger collections, but does not deep clone /// the loggers within. /// public BuildParameters Clone() { return new BuildParameters(this); } internal bool UsesCachedResults() => UsesInputCaches() || UsesOutputCache(); internal bool UsesOutputCache() => OutputResultsCacheFile != null; internal bool UsesInputCaches() => InputResultsCacheFiles != null; internal bool SkippedResultsDoNotCauseCacheMiss() => ProjectIsolationMode == ProjectIsolationMode.True; /// /// Implementation of the serialization mechanism. /// void ITranslatable.Translate(ITranslator translator) { translator.Translate(ref _buildId); /* No build thread priority during translation. We specifically use the default (which is ThreadPriority.Normal) */ translator.TranslateDictionary(ref _buildProcessEnvironment, StringComparer.OrdinalIgnoreCase); translator.TranslateCulture(ref _culture); translator.Translate(ref _defaultToolsVersion); translator.Translate(ref _disableInProcNode); translator.Translate(ref _enableNodeReuse); translator.Translate(ref _enableRarNode); translator.TranslateProjectPropertyInstanceDictionary(ref _environmentProperties); /* No forwarding logger information sent here - that goes with the node configuration */ translator.TranslateProjectPropertyInstanceDictionary(ref _globalProperties); /* No host services during translation */ /* No loggers during translation */ translator.Translate(ref _maxNodeCount); translator.Translate(ref _memoryUseLimit); translator.Translate(ref _nodeExeLocation); /* No node id during translation */ translator.Translate(ref _onlyLogCriticalEvents); translator.Translate(ref s_startupDirectory); translator.TranslateCulture(ref _uiCulture); translator.Translate(ref _toolsetProvider, Evaluation.ToolsetProvider.FactoryForDeserialization); translator.Translate(ref _useSynchronousLogging); translator.Translate(ref _shutdownInProcNodeOnBuildFinish); translator.Translate(ref _logTaskInputs); translator.Translate(ref _logInitialPropertiesAndItems); translator.TranslateEnum(ref _projectLoadSettings, (int)_projectLoadSettings); translator.Translate(ref _interactive); translator.Translate(ref _question); translator.Translate(ref _isBuildCheckEnabled); translator.Translate(ref _isTelemetryEnabled); translator.TranslateEnum(ref _projectIsolationMode, (int)_projectIsolationMode); translator.Translate(ref _reportFileAccesses); translator.Translate(ref _enableTargetOutputLogging); translator.Translate(ref _multiThreaded); translator.Translate(ref _ParserIgnoreConfiguration, ParserIgnoreConfiguration.FactoryForDeserialization); // ProjectRootElementCache is not transmitted. // ResetCaches is not transmitted. // LegacyThreadingSemantics is not transmitted. // InputResultsCacheFiles and OutputResultsCacheFile are not transmitted, as they are only used by the BuildManager // DiscardBuildResults is not transmitted. // LowPriority is passed as an argument to new nodes, so it doesn't need to be transmitted here. } #region INodePacketTranslatable Members /// /// The class factory for deserialization. /// internal static BuildParameters FactoryForDeserialization(ITranslator translator) { return new BuildParameters(translator); } #endregion /// /// Centralization of the common parts of construction. /// private void Initialize(PropertyDictionary environmentProperties, ProjectRootElementCacheBase projectRootElementCache, ToolsetProvider toolsetProvider) { _buildProcessEnvironment = CommunicationsUtilities.GetEnvironmentVariables(); _environmentProperties = environmentProperties; ProjectRootElementCache = projectRootElementCache; ResetCaches = true; _toolsetProvider = toolsetProvider; if (Environment.GetEnvironmentVariable("MSBUILDDISABLENODEREUSE") == "1") // For example to disable node reuse within Visual Studio { _enableNodeReuse = false; } if (Environment.GetEnvironmentVariable("MSBUILDDETAILEDSUMMARY") == "1") // For example to get detailed summary within Visual Studio { DetailedSummary = true; } _nodeExeLocation = FindMSBuildExe(); } /// /// Loads the toolsets if we don't have them already. /// private void EnsureToolsets() { if (_toolsetProvider != null) { return; } _toolsetProvider = new ToolsetProvider(DefaultToolsVersion, _environmentProperties, _globalProperties, ToolsetDefinitionLocations); } /// /// This method determines where MSBuild.Exe is and sets the NodeExePath to that by default. /// private string FindMSBuildExe() { string location = _nodeExeLocation; // Use the location specified by the user in code. if (!string.IsNullOrEmpty(location) && CheckMSBuildExeExistsAt(location)) { return location; } // Try what we think is the current executable path. return BuildEnvironmentHelper.Instance.CurrentMSBuildExePath; } /// /// Helper to avoid doing an expensive disk check for MSBuild.exe when /// we already checked in a previous build. /// This File.Exists otherwise can show up in profiles when there's a lot of /// design time builds going on. /// private static bool CheckMSBuildExeExistsAt(string path) { if (s_msbuildExeKnownToExistAt != null && string.Equals(path, s_msbuildExeKnownToExistAt, StringComparison.OrdinalIgnoreCase)) { // We found it there last time: it must exist there. return true; } if (FileSystems.Default.FileExists(path)) { s_msbuildExeKnownToExistAt = path; return true; } return false; } } }