|
// 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.Generic;
using System.Collections.ObjectModel;
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.Experimental;
using Microsoft.Build.Experimental.BuildCheck;
using Microsoft.Build.Experimental.ProjectCache;
using Microsoft.Build.Framework;
using Microsoft.Build.Graph;
using Microsoft.Build.Internal;
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;
/// <summary>
/// This class represents all of the settings which must be specified to start a build.
/// </summary>
public class BuildParameters : ITranslatable
{
/// <summary>
/// The default thread stack size for threads owned by MSBuild.
/// </summary>
private const int DefaultThreadStackSize = 262144; // 256k
/// <summary>
/// The timeout for endpoints to shut down.
/// </summary>
private const int DefaultEndpointShutdownTimeout = 30 * 1000; // 30 seconds
/// <summary>
/// The timeout for the engine to shutdown.
/// </summary>
private const int DefaultEngineShutdownTimeout = Timeout.Infinite;
/// <summary>
/// The shutdown timeout for the logging thread.
/// </summary>
private const int DefaultLoggingThreadShutdownTimeout = 30 * 1000; // 30 seconds
/// <summary>
/// The shutdown timeout for the request builder.
/// </summary>
private const int DefaultRequestBuilderShutdownTimeout = Timeout.Infinite;
/// <summary>
/// The maximum number of idle request builders to retain before we start discarding them.
/// </summary>
private const int DefaultIdleRequestBuilderLimit = 2;
/// <summary>
/// The startup directory.
/// </summary>
private static string s_startupDirectory = NativeMethodsShared.GetCurrentDirectory();
/// <summary>
/// Indicates whether we should warn when a property is uninitialized when it is used.
/// </summary>
private static bool? s_warnOnUninitializedProperty;
/// <summary>
/// Indicates if we should dump string interning stats.
/// </summary>
private static bool? s_dumpStringInterningStats;
/// <summary>
/// Indicates if we should debug the expander.
/// </summary>
private static bool? s_debugExpansion;
/// <summary>
/// Indicates if we should keep duplicate target outputs.
/// </summary>
private static bool? s_keepDuplicateOutputs;
/// <summary>
/// Indicates if we should enable the build plan
/// </summary>
private static bool? s_enableBuildPlan;
/// <summary>
/// The maximum number of idle request builders we will retain.
/// </summary>
private static int? s_idleRequestBuilderLimit;
/// <summary>
/// Location that msbuild.exe was last successfully found at.
/// </summary>
private static string s_msbuildExeKnownToExistAt;
/// <summary>
/// The build id
/// </summary>
private int _buildId;
/// <summary>
/// The culture
/// </summary>
private CultureInfo _culture = CultureInfo.CurrentCulture;
/// <summary>
/// The default tools version.
/// </summary>
private string _defaultToolsVersion = "2.0";
/// <summary>
/// Flag indicating whether node reuse should be enabled.
/// By default, it is enabled.
/// </summary>
#if FEATURE_NODE_REUSE
private bool _enableNodeReuse = true;
#else
private bool _enableNodeReuse = false;
#endif
/// <summary>
/// The original process environment.
/// </summary>
private Dictionary<string, string> _buildProcessEnvironment;
/// <summary>
/// The environment properties for the build.
/// </summary>
private PropertyDictionary<ProjectPropertyInstance> _environmentProperties = new PropertyDictionary<ProjectPropertyInstance>();
/// <summary>
/// The forwarding logger records.
/// </summary>
private IEnumerable<ForwardingLoggerRecord> _forwardingLoggers;
/// <summary>
/// The build-global properties.
/// </summary>
private PropertyDictionary<ProjectPropertyInstance> _globalProperties = new PropertyDictionary<ProjectPropertyInstance>();
/// <summary>
/// The loggers.
/// </summary>
private IEnumerable<ILogger> _loggers;
/// <summary>
/// The maximum number of nodes to use.
/// </summary>
private int _maxNodeCount = 1;
/// <summary>
/// The maximum amount of memory to use.
/// </summary>
private int _memoryUseLimit; // Default 0 = unlimited
/// <summary>
/// The location of the node exe. This is the full path including the exe file itself.
/// </summary>
private string _nodeExeLocation;
/// <summary>
/// Flag indicating if we should only log critical events.
/// </summary>
private bool _onlyLogCriticalEvents;
/// <summary>
/// The UI culture.
/// </summary>
private CultureInfo _uiCulture = CultureInfo.CurrentUICulture;
/// <summary>
/// The toolset provider
/// </summary>
private ToolsetProvider _toolsetProvider;
/// <summary>
/// Should the logging service be done Synchronously when the number of cps's is 1
/// </summary>
private bool _useSynchronousLogging;
/// <summary>
/// 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.
/// </summary>
private bool _shutdownInProcNodeOnBuildFinish;
/// <summary>
/// When true, the in-proc node will not be available.
/// </summary>
private bool _disableInProcNode;
/// <summary>
/// When true, the build should log task inputs to the loggers.
/// </summary>
private bool _logTaskInputs;
/// <summary>
/// When true, the build should log the input parameters. Note - logging these is very expensive!
/// </summary>
private bool _logInitialPropertiesAndItems;
private bool _question;
private bool _isBuildCheckEnabled;
/// <summary>
/// The settings used to load the project under build
/// </summary>
private ProjectLoadSettings _projectLoadSettings = ProjectLoadSettings.Default;
private bool _interactive;
private ProjectIsolationMode _projectIsolationMode;
private string[] _inputResultsCacheFiles;
private string _outputResultsCacheFile;
private bool _reportFileAccesses;
/// <summary>
/// Constructor for those who intend to set all properties themselves.
/// </summary>
public BuildParameters()
{
Initialize(Utilities.GetEnvironmentProperties(makeReadOnly: false), new ProjectRootElementCache(false), null);
}
/// <summary>
/// Creates BuildParameters from a ProjectCollection.
/// </summary>
/// <param name="projectCollection">The ProjectCollection from which the BuildParameters should populate itself.</param>
public BuildParameters(ProjectCollection projectCollection)
{
ErrorUtilities.VerifyThrowArgumentNull(projectCollection);
Initialize(new PropertyDictionary<ProjectPropertyInstance>(projectCollection.EnvironmentProperties), projectCollection.ProjectRootElementCache, new ToolsetProvider(projectCollection.Toolsets));
_maxNodeCount = projectCollection.MaxNodeCount;
_onlyLogCriticalEvents = projectCollection.OnlyLogCriticalEvents;
ToolsetDefinitionLocations = projectCollection.ToolsetLocations;
_defaultToolsVersion = projectCollection.DefaultToolsVersion;
_globalProperties = new PropertyDictionary<ProjectPropertyInstance>(projectCollection.GlobalPropertiesCollection);
}
/// <summary>
/// Private constructor for translation
/// </summary>
private BuildParameters(ITranslator translator)
{
((ITranslatable)this).Translate(translator);
}
/// <summary>
/// Copy constructor
/// </summary>
internal BuildParameters(BuildParameters other, bool resetEnvironment = false)
{
ErrorUtilities.VerifyThrowInternalNull(other);
_buildId = other._buildId;
_culture = other._culture;
_defaultToolsVersion = other._defaultToolsVersion;
_enableNodeReuse = other._enableNodeReuse;
_buildProcessEnvironment = resetEnvironment
? CommunicationsUtilities.GetEnvironmentVariables()
: other._buildProcessEnvironment != null
? new Dictionary<string, string>(other._buildProcessEnvironment)
: null;
_environmentProperties = other._environmentProperties != null ? new PropertyDictionary<ProjectPropertyInstance>(other._environmentProperties) : null;
_forwardingLoggers = other._forwardingLoggers != null ? new List<ForwardingLoggerRecord>(other._forwardingLoggers) : null;
_globalProperties = other._globalProperties != null ? new PropertyDictionary<ProjectPropertyInstance>(other._globalProperties) : null;
HostServices = other.HostServices;
_loggers = other._loggers != null ? new List<ILogger>(other._loggers) : null;
_maxNodeCount = other._maxNodeCount;
_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<string>(other.WarningsAsErrors, StringComparer.OrdinalIgnoreCase);
WarningsNotAsErrors = other.WarningsNotAsErrors == null ? null : new HashSet<string>(other.WarningsNotAsErrors, StringComparer.OrdinalIgnoreCase);
WarningsAsMessages = other.WarningsAsMessages == null ? null : new HashSet<string>(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;
ProjectCacheDescriptor = other.ProjectCacheDescriptor;
}
/// <summary>
/// Gets or sets the desired thread priority for building.
/// </summary>
public ThreadPriority BuildThreadPriority { get; set; } = ThreadPriority.Normal;
/// <summary>
/// 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.
/// </summary>
public bool UseSynchronousLogging
{
get => _useSynchronousLogging;
set => _useSynchronousLogging = value;
}
/// <summary>
/// Indicates whether to emit a default error if a task returns false without logging an error.
/// </summary>
public bool AllowFailureWithoutError { get; set; } = false;
/// <summary>
/// Gets the environment variables which were set when this build was created.
/// </summary>
public IDictionary<string, string> BuildProcessEnvironment => new ReadOnlyDictionary<string, string>(
_buildProcessEnvironment ?? new Dictionary<string, string>(0));
/// <summary>
/// The name of the culture to use during the build.
/// </summary>
public CultureInfo Culture
{
get => _culture;
set => _culture = value;
}
/// <summary>
/// The default tools version for the build.
/// </summary>
public string DefaultToolsVersion
{
get => _defaultToolsVersion;
set => _defaultToolsVersion = value;
}
/// <summary>
/// When true, indicates that the build should emit a detailed summary at the end of the log.
/// </summary>
public bool DetailedSummary { get; set; }
/// <summary>
/// When true, indicates the in-proc node should not be used.
/// </summary>
public bool DisableInProcNode
{
get => _disableInProcNode;
set => _disableInProcNode = value;
}
/// <summary>
/// When true, indicates that the task parameters should be logged.
/// </summary>
public bool LogTaskInputs
{
get => _logTaskInputs;
set => _logTaskInputs = value;
}
/// <summary>
/// When true, indicates that the initial properties and items should be logged.
/// </summary>
public bool LogInitialPropertiesAndItems
{
get => _logInitialPropertiesAndItems;
set => _logInitialPropertiesAndItems = value;
}
/// <summary>
/// Indicates that the build should reset the configuration and results caches.
/// </summary>
public bool ResetCaches
{
get;
set;
}
/// <summary>
/// Flag indicating whether out-of-proc nodes should remain after the build and wait for further builds.
/// </summary>
public bool EnableNodeReuse
{
get => _enableNodeReuse;
set => _enableNodeReuse = Environment.GetEnvironmentVariable("MSBUILDDISABLENODEREUSE") == "1" ? false : value;
}
/// <summary>
/// Gets an immutable collection of environment properties.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public IDictionary<string, string> EnvironmentProperties
{
get
{
return new ReadOnlyConvertingDictionary<string, ProjectPropertyInstance, string>(_environmentProperties,
instance => ((IProperty)instance).EvaluatedValueEscaped);
}
}
/// <summary>
/// The collection of forwarding logger descriptions.
/// </summary>
public IEnumerable<ForwardingLoggerRecord> ForwardingLoggers
{
get => _forwardingLoggers;
set
{
if (value != null)
{
foreach (ForwardingLoggerRecord logger in value)
{
ErrorUtilities.VerifyThrowArgumentNull(logger, nameof(ForwardingLoggers), "NullLoggerNotAllowed");
}
}
_forwardingLoggers = value;
}
}
/// <summary>
/// Sets or retrieves an immutable collection of global properties.
/// </summary>
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification =
"Accessor returns a readonly collection, and the BuildParameters class is immutable.")]
public IDictionary<string, string> GlobalProperties
{
get
{
return new ReadOnlyConvertingDictionary<string, ProjectPropertyInstance, string>(_globalProperties,
instance => ((IProperty)instance).EvaluatedValueEscaped);
}
set
{
_globalProperties = new PropertyDictionary<ProjectPropertyInstance>(value.Count);
foreach (KeyValuePair<string, string> property in value)
{
_globalProperties[property.Key] = ProjectPropertyInstance.Create(property.Key, property.Value);
}
}
}
/// <summary>
/// Interface allowing the host to provide additional control over the build process.
/// </summary>
public HostServices HostServices { get; set; }
/// <summary>
/// Enables or disables legacy threading semantics
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public bool LegacyThreadingSemantics { get; set; }
/// <summary>
/// The collection of loggers to use during the build.
/// </summary>
public IEnumerable<ILogger> Loggers
{
get => _loggers;
set
{
if (value != null)
{
foreach (ILogger logger in value)
{
ErrorUtilities.VerifyThrowArgumentNull(logger, "Loggers", "NullLoggerNotAllowed");
}
}
_loggers = value;
}
}
/// <summary>
/// The maximum number of nodes this build may use.
/// </summary>
public int MaxNodeCount
{
get => _maxNodeCount;
set
{
ErrorUtilities.VerifyThrowArgument(value > 0, "InvalidMaxNodeCount");
_maxNodeCount = value;
}
}
/// <summary>
/// The amount of memory the build should limit itself to using, in megabytes.
/// </summary>
public int MemoryUseLimit
{
get => _memoryUseLimit;
set => _memoryUseLimit = value;
}
/// <summary>
/// The location of the build node executable.
/// </summary>
public string NodeExeLocation
{
get => _nodeExeLocation;
set => _nodeExeLocation = value;
}
/// <summary>
/// Flag indicating if non-critical logging events should be discarded.
/// </summary>
public bool OnlyLogCriticalEvents
{
get => _onlyLogCriticalEvents;
set => _onlyLogCriticalEvents = value;
}
/// <summary>
/// A list of warnings to treat as errors. To treat all warnings as errors, set this to an empty <see cref="HashSet{String}"/>.
/// </summary>
public ISet<string> WarningsAsErrors { get; set; }
/// <summary>
/// A list of warnings to not treat as errors. Only has any effect if WarningsAsErrors is empty.
/// </summary>
public ISet<string> WarningsNotAsErrors { get; set; }
/// <summary>
/// A list of warnings to treat as low importance messages.
/// </summary>
public ISet<string> WarningsAsMessages { get; set; }
/// <summary>
/// Locations to search for toolsets.
/// </summary>
public ToolsetDefinitionLocations ToolsetDefinitionLocations { get; set; } = ToolsetDefinitionLocations.Default;
/// <summary>
/// Returns all of the toolsets.
/// </summary>
/// <comments>
/// toolsetProvider.Toolsets is already a readonly collection.
/// </comments>
public ICollection<Toolset> Toolsets => ToolsetProvider.Toolsets;
/// <summary>
/// The name of the UI culture to use during the build.
/// </summary>
public CultureInfo UICulture
{
get => _uiCulture;
set => _uiCulture = value;
}
/// <summary>
/// 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.
/// </summary>
public bool SaveOperatingEnvironment { get; set; } = true;
/// <summary>
/// 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.
/// </summary>
public bool ShutdownInProcNodeOnBuildFinish
{
get => _shutdownInProcNodeOnBuildFinish;
set => _shutdownInProcNodeOnBuildFinish = value;
}
/// <summary>
/// Gets the internal msbuild thread stack size.
/// </summary>
internal static int ThreadStackSize => CommunicationsUtilities.GetIntegerVariableOrDefault(
"MSBUILDTHREADSTACKSIZE", DefaultThreadStackSize);
/// <summary>
/// Gets the endpoint shutdown timeout.
/// </summary>
internal static int EndpointShutdownTimeout => CommunicationsUtilities.GetIntegerVariableOrDefault(
"MSBUILDENDPOINTSHUTDOWNTIMEOUT", DefaultEndpointShutdownTimeout);
/// <summary>
/// Gets or sets the engine shutdown timeout.
/// </summary>
internal static int EngineShutdownTimeout => CommunicationsUtilities.GetIntegerVariableOrDefault(
"MSBUILDENGINESHUTDOWNTIMEOUT", DefaultEngineShutdownTimeout);
/// <summary>
/// Gets the maximum number of idle request builders to retain.
/// </summary>
internal static int IdleRequestBuilderLimit => GetStaticIntVariableOrDefault("MSBUILDIDLEREQUESTBUILDERLIMIT",
ref s_idleRequestBuilderLimit, DefaultIdleRequestBuilderLimit);
/// <summary>
/// Gets the logging thread shutdown timeout.
/// </summary>
internal static int LoggingThreadShutdownTimeout => CommunicationsUtilities.GetIntegerVariableOrDefault(
"MSBUILDLOGGINGTHREADSHUTDOWNTIMEOUT", DefaultLoggingThreadShutdownTimeout);
/// <summary>
/// Gets the request builder shutdown timeout.
/// </summary>
internal static int RequestBuilderShutdownTimeout => CommunicationsUtilities.GetIntegerVariableOrDefault(
"MSBUILDREQUESTBUILDERSHUTDOWNTIMEOUT", DefaultRequestBuilderShutdownTimeout);
/// <summary>
/// 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 <see cref="ServerNodeBuildCommand"></see> is received.
/// </summary>
internal static string StartupDirectory
{
get { return s_startupDirectory; }
set { s_startupDirectory = value; }
}
/// <summary>
/// Indicates whether the build plan is enabled or not.
/// </summary>
internal static bool EnableBuildPlan => GetStaticBoolVariableOrDefault("MSBUILDENABLEBUILDPLAN",
ref s_enableBuildPlan, false);
/// <summary>
/// Indicates whether we should warn when a property is uninitialized when it is used.
/// </summary>
internal static bool WarnOnUninitializedProperty
{
get => GetStaticBoolVariableOrDefault("MSBUILDWARNONUNINITIALIZEDPROPERTY",
ref s_warnOnUninitializedProperty, false);
set => s_warnOnUninitializedProperty = value;
}
/// <summary>
/// Indicates whether we should dump string interning stats
/// </summary>
internal static bool DumpOpportunisticInternStats => GetStaticBoolVariableOrDefault(
"MSBUILDDUMPOPPORTUNISTICINTERNSTATS", ref s_dumpStringInterningStats, false);
/// <summary>
/// Indicates whether we should dump debugging information about the expander
/// </summary>
internal static bool DebugExpansion => GetStaticBoolVariableOrDefault("MSBUILDDEBUGEXPANSION",
ref s_debugExpansion, false);
/// <summary>
/// Indicates whether we should keep duplicate target outputs
/// </summary>
internal static bool KeepDuplicateOutputs => GetStaticBoolVariableOrDefault("MSBUILDKEEPDUPLICATEOUTPUTS",
ref s_keepDuplicateOutputs, false);
/// <summary>
/// Gets or sets the build id.
/// </summary>
internal int BuildId
{
get => _buildId;
set => _buildId = value;
}
/// <summary>
/// Gets or sets the environment properties.
/// </summary>
/// <remarks>
/// 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)').
/// </remarks>
internal PropertyDictionary<ProjectPropertyInstance> EnvironmentPropertiesInternal
{
get => _environmentProperties;
set
{
ErrorUtilities.VerifyThrowInternalNull(value, "EnvironmentPropertiesInternal");
_environmentProperties = value;
}
}
/// <summary>
/// Gets the global properties.
/// </summary>
internal PropertyDictionary<ProjectPropertyInstance> GlobalPropertiesInternal => _globalProperties;
/// <summary>
/// Gets or sets the node id.
/// </summary>
internal int NodeId { get; set; }
/// <summary>
/// Gets the toolset provider.
/// </summary>
internal IToolsetProvider ToolsetProvider
{
get
{
EnsureToolsets();
return _toolsetProvider;
}
}
/// <summary>
/// The one and only project root element cache to be used for the build.
/// </summary>
internal ProjectRootElementCacheBase ProjectRootElementCache { get; set; }
#if FEATURE_APPDOMAIN
/// <summary>
/// Information for configuring child AppDomains.
/// </summary>
internal AppDomainSetup AppDomainSetup { get; set; }
#endif
/// <summary>
/// (for diagnostic use) Whether or not this is out of proc
/// </summary>
internal bool IsOutOfProc { get; set; }
/// <nodoc/>
public ProjectLoadSettings ProjectLoadSettings
{
get => _projectLoadSettings;
set => _projectLoadSettings = value;
}
/// <summary>
/// Gets or sets a value indicating if the build is allowed to interact with the user.
/// </summary>
public bool Interactive
{
get => _interactive;
set => _interactive = value;
}
/// <summary>
/// Gets or sets a value indicating the isolation mode to use.
/// </summary>
/// <remarks>
/// Kept for API backwards compatibility.
/// </remarks>
public bool IsolateProjects
{
get => ProjectIsolationMode == ProjectIsolationMode.True;
set => ProjectIsolationMode = value ? ProjectIsolationMode.True : ProjectIsolationMode.False;
}
/// <summary>
/// Gets or sets a value indicating the isolation mode to use.
/// </summary>
public ProjectIsolationMode ProjectIsolationMode { get => _projectIsolationMode; set => _projectIsolationMode = value; }
/// <summary>
/// Input cache files that MSBuild will use to read build results from.
/// If the isolation mode is set to <see cref="ProjectIsolationMode.False"/>,
/// this sets the isolation mode to <see cref="ProjectIsolationMode.True"/>.
/// </summary>
public string[] InputResultsCacheFiles
{
get => _inputResultsCacheFiles;
set => _inputResultsCacheFiles = value;
}
/// <summary>
/// Output cache file where MSBuild will write the contents of its build result caches during EndBuild.
/// If the isolation mode is set to <see cref="ProjectIsolationMode.False"/>,
/// this sets the isolation mode to <see cref="ProjectIsolationMode.True"/>.
/// </summary>
public string OutputResultsCacheFile
{
get => _outputResultsCacheFile;
set => _outputResultsCacheFile = value;
}
#if FEATURE_REPORTFILEACCESSES
/// <summary>
/// Gets or sets a value indicating whether file accesses should be reported to any configured project cache plugins.
/// </summary>
public bool ReportFileAccesses
{
get => _reportFileAccesses;
set => _reportFileAccesses = value;
}
#endif
/// <summary>
/// Determines whether MSBuild will save the results of builds after EndBuild to speed up future builds.
/// </summary>
public bool DiscardBuildResults { get; set; } = false;
/// <summary>
/// Gets or sets a value indicating whether the build process should run as low priority.
/// </summary>
public bool LowPriority { get; set; }
/// <summary>
/// Gets or sets a value that will error when the build process fails an incremental check.
/// </summary>
public bool Question
{
get => _question;
set => _question = value;
}
/// <summary>
/// Gets or sets an indication of build check enablement.
/// </summary>
public bool IsBuildCheckEnabled
{
get => _isBuildCheckEnabled;
set => _isBuildCheckEnabled = value;
}
/// <summary>
/// Gets or sets the project cache description to use for all <see cref="BuildSubmission"/> or <see cref="GraphBuildSubmission"/>
/// in addition to any potential project caches described in each project.
/// </summary>
public ProjectCacheDescriptor ProjectCacheDescriptor { get; set; }
/// <summary>
/// Retrieves a toolset.
/// </summary>
public Toolset GetToolset(string toolsVersion)
{
EnsureToolsets();
return _toolsetProvider.GetToolset(toolsVersion);
}
/// <summary>
/// Creates a clone of this BuildParameters object. This creates a clone of the logger collections, but does not deep clone
/// the loggers within.
/// </summary>
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;
/// <summary>
/// Implementation of the serialization mechanism.
/// </summary>
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.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.TranslateEnum(ref _projectIsolationMode, (int)_projectIsolationMode);
translator.Translate(ref _reportFileAccesses);
// 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
/// <summary>
/// The class factory for deserialization.
/// </summary>
internal static BuildParameters FactoryForDeserialization(ITranslator translator)
{
return new BuildParameters(translator);
}
#endregion
/// <summary>
/// Gets the value of a boolean environment setting which is not expected to change.
/// </summary>
private static bool GetStaticBoolVariableOrDefault(string environmentVariable, ref bool? backing, bool @default)
{
if (!backing.HasValue)
{
backing = !String.IsNullOrEmpty(Environment.GetEnvironmentVariable(environmentVariable)) || @default;
}
return backing.Value;
}
/// <summary>
/// Gets the value of an integer environment variable, or returns the default if none is set or it cannot be converted.
/// </summary>
private static int GetStaticIntVariableOrDefault(string environmentVariable, ref int? backingValue, int defaultValue)
{
if (!backingValue.HasValue)
{
string environmentValue = Environment.GetEnvironmentVariable(environmentVariable);
if (String.IsNullOrEmpty(environmentValue))
{
backingValue = defaultValue;
}
else
{
backingValue = Int32.TryParse(environmentValue, out var parsedValue) ? parsedValue : defaultValue;
}
}
return backingValue.Value;
}
/// <summary>
/// Centralization of the common parts of construction.
/// </summary>
private void Initialize(PropertyDictionary<ProjectPropertyInstance> 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();
}
/// <summary>
/// Loads the toolsets if we don't have them already.
/// </summary>
private void EnsureToolsets()
{
if (_toolsetProvider != null)
{
return;
}
_toolsetProvider = new ToolsetProvider(DefaultToolsVersion, _environmentProperties, _globalProperties, ToolsetDefinitionLocations);
}
/// <summary>
/// This method determines where MSBuild.Exe is and sets the NodeExePath to that by default.
/// </summary>
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;
}
/// <summary>
/// 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.
/// </summary>
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;
}
}
}
|