1 // Copyright (c) Microsoft. All rights reserved. 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 //----------------------------------------------------------------------- 4 // </copyright> 5 // <summary>Class holding the parameters and settings which are global to the build.</summary> 6 //----------------------------------------------------------------------- 7 8 using System; 9 using System.Collections.Generic; 10 using System.Collections.ObjectModel; 11 using System.Diagnostics.CodeAnalysis; 12 using System.IO; 13 using System.Threading; 14 using System.Globalization; 15 using Microsoft.Build.BackEnd; 16 using Microsoft.Build.Collections; 17 using Microsoft.Build.Evaluation; 18 using Microsoft.Build.Framework; 19 using Microsoft.Build.Internal; 20 using Microsoft.Build.Shared; 21 using ForwardingLoggerRecord = Microsoft.Build.Logging.ForwardingLoggerRecord; 22 23 namespace Microsoft.Build.Execution 24 { 25 using Utilities = Microsoft.Build.Internal.Utilities; 26 27 /// <summary> 28 /// This class represents all of the settings which must be specified to start a build. 29 /// </summary> 30 public class BuildParameters : INodePacketTranslatable 31 { 32 /// <summary> 33 /// The default thread stack size for threads owned by MSBuild. 34 /// </summary> 35 private const int DefaultThreadStackSize = 262144; // 256k 36 37 /// <summary> 38 /// The timeout for endpoints to shut down. 39 /// </summary> 40 private const int DefaultEndpointShutdownTimeout = 30 * 1000; // 30 seconds 41 42 /// <summary> 43 /// The timeout for the engine to shutdown. 44 /// </summary> 45 private const int DefaultEngineShutdownTimeout = Timeout.Infinite; 46 47 /// <summary> 48 /// The shutdown timeout for the logging thread. 49 /// </summary> 50 private const int DefaultLoggingThreadShutdownTimeout = 30 * 1000; // 30 seconds 51 52 /// <summary> 53 /// The shutdown timeout for the request builder. 54 /// </summary> 55 private const int DefaultRequestBuilderShutdownTimeout = Timeout.Infinite; 56 57 /// <summary> 58 /// The maximum number of idle request builders to retain before we start discarding them. 59 /// </summary> 60 private const int DefaultIdleRequestBuilderLimit = 2; 61 62 /// <summary> 63 /// The startup directory. 64 /// </summary> 65 private static string s_startupDirectory = NativeMethodsShared.GetCurrentDirectory(); 66 67 /// <summary> 68 /// Indicates whether we should warn when a property is uninitialized when it is used. 69 /// </summary> 70 private static bool? s_warnOnUninitializedProperty; 71 72 /// <summary> 73 /// Indicates if we should dump string interning stats. 74 /// </summary> 75 private static bool? s_dumpOpportunisticInternStats; 76 77 /// <summary> 78 /// Indicates if we should debug the expander. 79 /// </summary> 80 private static bool? s_debugExpansion; 81 82 /// <summary> 83 /// Indicates if we should keep duplicate target outputs. 84 /// </summary> 85 private static bool? s_keepDuplicateOutputs; 86 87 /// <summary> 88 /// Indicates if we should enable the build plan 89 /// </summary> 90 private static bool? s_enableBuildPlan; 91 92 /// <summary> 93 /// The maximum number of idle request builders we will retain. 94 /// </summary> 95 private static int? s_idleRequestBuilderLimit; 96 97 /// <summary> 98 /// Location that msbuild.exe was last successfully found at. 99 /// </summary> 100 private static string s_msbuildExeKnownToExistAt; 101 102 /// <summary> 103 /// The build id 104 /// </summary> 105 private int _buildId = 0; 106 107 /// <summary> 108 /// The culture 109 /// </summary> 110 private CultureInfo _culture = CultureInfo.CurrentCulture; 111 112 /// <summary> 113 /// The default tools version. 114 /// </summary> 115 private string _defaultToolsVersion = "2.0"; 116 117 /// <summary> 118 /// When true, causes the build to emit a summary of project build information 119 /// </summary> 120 private bool _detailedSummary; 121 122 /// <summary> 123 /// Flag indicating whether node reuse should be enabled. 124 /// By default, it is enabled. 125 /// </summary> 126 #if FEATURE_NODE_REUSE 127 private bool _enableNodeReuse = true; 128 #else 129 private bool _enableNodeReuse = false; 130 #endif 131 132 /// <summary> 133 /// The original process environment. 134 /// </summary> 135 private Dictionary<string, string> _buildProcessEnvironment; 136 137 /// <summary> 138 /// The environment properties for the build. 139 /// </summary> 140 private PropertyDictionary<ProjectPropertyInstance> _environmentProperties = new PropertyDictionary<ProjectPropertyInstance>(); 141 142 /// <summary> 143 /// The forwarding logger records. 144 /// </summary> 145 private IEnumerable<ForwardingLoggerRecord> _forwardingLoggers; 146 147 /// <summary> 148 /// The build-global properties. 149 /// </summary> 150 private PropertyDictionary<ProjectPropertyInstance> _globalProperties = new PropertyDictionary<ProjectPropertyInstance>(); 151 152 /// <summary> 153 /// The host services object. 154 /// </summary> 155 private HostServices _hostServices; 156 157 /// <summary> 158 /// The loggers. 159 /// </summary> 160 private IEnumerable<ILogger> _loggers; 161 162 /// <summary> 163 /// The maximum number of nodes to use. 164 /// </summary> 165 private int _maxNodeCount = 1; 166 167 /// <summary> 168 /// The maximum amount of memory to use. 169 /// </summary> 170 private int _memoryUseLimit = 0; // Unlimited 171 172 /// <summary> 173 /// The location of the node exe. This is the full path including the exe file itself. 174 /// </summary> 175 private string _nodeExeLocation; 176 177 /// <summary> 178 /// Flag indicating if we should only log critical events. 179 /// </summary> 180 private bool _onlyLogCriticalEvents = false; 181 182 /// <summary> 183 /// A list of warnings to treat as errors. 184 /// </summary> 185 private ISet<string> _warningsAsErrors; 186 187 /// <summary> 188 /// A list of warnings to treat as low importance messages. 189 /// </summary> 190 private ISet<string> _warningsAsMessages; 191 192 /// <summary> 193 /// The location of the toolset definitions. 194 /// </summary> 195 private ToolsetDefinitionLocations _toolsetDefinitionLocations = ToolsetDefinitionLocations.Default; 196 197 /// <summary> 198 /// The UI culture. 199 /// </summary> 200 private CultureInfo _uiCulture = CultureInfo.CurrentUICulture; 201 202 /// <summary> 203 /// The toolset provider 204 /// </summary> 205 private ToolsetProvider _toolsetProvider; 206 207 /// <summary> 208 /// Should the operating environment such as the current directory and environment be saved and restored between project builds and task invocations 209 /// This should be defaulted to true as we should normally do this. This should be set to false for GlobalDTAR which could run at the same time in a different build manager. 210 /// </summary> 211 private bool _saveOperatingEnvironment = true; 212 213 /// <summary> 214 /// Should the logging service be done Synchronously when the number of cps's is 1 215 /// </summary> 216 private bool _useSynchronousLogging = false; 217 218 /// <summary> 219 /// Should the inprocess node be shutdown when the build finishes. By default this is false 220 /// since visual studio needs to keep the inprocess node around after the build has finished. 221 /// </summary> 222 private bool _shutdownInProcNodeOnBuildFinish = false; 223 224 /// <summary> 225 /// When true, the in-proc node will not be available. 226 /// </summary> 227 private bool _disableInProcNode = false; 228 229 /// <summary> 230 /// When true, the build should log task inputs to the loggers. 231 /// </summary> 232 private bool _logTaskInputs = false; 233 234 /// <summary> 235 /// When true, the build should log the input parameters. Note - logging these is very expensive! 236 /// </summary> 237 private bool _logInitialPropertiesAndItems = false; 238 239 /// <summary> 240 /// The settings used to load the project under build 241 /// </summary> 242 private ProjectLoadSettings _projectLoadSettings = ProjectLoadSettings.Default; 243 244 /// <summary> 245 /// Constructor for those who intend to set all properties themselves. 246 /// </summary> BuildParameters()247 public BuildParameters() 248 { 249 Initialize(Utilities.GetEnvironmentProperties(), new ProjectRootElementCache(false), null); 250 } 251 252 /// <summary> 253 /// Creates BuildParameters from a ProjectCollection. 254 /// </summary> 255 /// <param name="projectCollection">The ProjectCollection from which the BuildParameters should populate itself.</param> BuildParameters(ProjectCollection projectCollection)256 public BuildParameters(ProjectCollection projectCollection) 257 { 258 ErrorUtilities.VerifyThrowArgumentNull(projectCollection, "projectCollection"); 259 260 Initialize(new PropertyDictionary<ProjectPropertyInstance>(projectCollection.EnvironmentProperties), projectCollection.ProjectRootElementCache, new ToolsetProvider(projectCollection.Toolsets)); 261 262 _maxNodeCount = projectCollection.MaxNodeCount; 263 _onlyLogCriticalEvents = projectCollection.OnlyLogCriticalEvents; 264 _toolsetDefinitionLocations = projectCollection.ToolsetLocations; 265 _defaultToolsVersion = projectCollection.DefaultToolsVersion; 266 267 _globalProperties = new PropertyDictionary<ProjectPropertyInstance>(projectCollection.GlobalPropertiesCollection); 268 } 269 270 /// <summary> 271 /// Private constructor for translation 272 /// </summary> BuildParameters(INodePacketTranslator translator)273 private BuildParameters(INodePacketTranslator translator) 274 { 275 ((INodePacketTranslatable)this).Translate(translator); 276 } 277 278 /// <summary> 279 /// Copy constructor 280 /// </summary> BuildParameters(BuildParameters other)281 private BuildParameters(BuildParameters other) 282 { 283 ErrorUtilities.VerifyThrowInternalNull(other, "other"); 284 285 _buildId = other._buildId; 286 _culture = other._culture; 287 _defaultToolsVersion = other._defaultToolsVersion; 288 _enableNodeReuse = other._enableNodeReuse; 289 _buildProcessEnvironment = other._buildProcessEnvironment != null ? new Dictionary<string, string>(other._buildProcessEnvironment) : null; 290 _environmentProperties = other._environmentProperties != null ? new PropertyDictionary<ProjectPropertyInstance>(other._environmentProperties) : null; 291 _forwardingLoggers = other._forwardingLoggers != null ? new List<ForwardingLoggerRecord>(other._forwardingLoggers) : null; 292 _globalProperties = other._globalProperties != null ? new PropertyDictionary<ProjectPropertyInstance>(other._globalProperties) : null; 293 _hostServices = other._hostServices; 294 _loggers = other._loggers != null ? new List<ILogger>(other._loggers) : null; 295 _maxNodeCount = other._maxNodeCount; 296 _memoryUseLimit = other._memoryUseLimit; 297 _nodeExeLocation = other._nodeExeLocation; 298 NodeId = other.NodeId; 299 _onlyLogCriticalEvents = other._onlyLogCriticalEvents; 300 #if FEATURE_THREAD_PRIORITY 301 BuildThreadPriority = other.BuildThreadPriority; 302 #endif 303 _toolsetProvider = other._toolsetProvider; 304 _toolsetDefinitionLocations = other._toolsetDefinitionLocations; 305 _toolsetProvider = other._toolsetProvider; 306 _uiCulture = other._uiCulture; 307 _detailedSummary = other._detailedSummary; 308 _shutdownInProcNodeOnBuildFinish = other._shutdownInProcNodeOnBuildFinish; 309 ProjectRootElementCache = other.ProjectRootElementCache; 310 ResetCaches = other.ResetCaches; 311 LegacyThreadingSemantics = other.LegacyThreadingSemantics; 312 _saveOperatingEnvironment = other._saveOperatingEnvironment; 313 _useSynchronousLogging = other._useSynchronousLogging; 314 _disableInProcNode = other._disableInProcNode; 315 _logTaskInputs = other._logTaskInputs; 316 _logInitialPropertiesAndItems = other._logInitialPropertiesAndItems; 317 _warningsAsErrors = other._warningsAsErrors == null ? null : new HashSet<string>(other._warningsAsErrors, StringComparer.OrdinalIgnoreCase); 318 _warningsAsMessages = other._warningsAsMessages == null ? null : new HashSet<string>(other._warningsAsMessages, StringComparer.OrdinalIgnoreCase); 319 _projectLoadSettings = other._projectLoadSettings; 320 } 321 322 #if FEATURE_THREAD_PRIORITY 323 /// <summary> 324 /// Gets or sets the desired thread priority for building. 325 /// </summary> 326 public ThreadPriority BuildThreadPriority { get; set; } = ThreadPriority.Normal; 327 328 #endif 329 330 /// <summary> 331 /// 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 332 /// this property needs to be set to true. 333 /// </summary> 334 public bool UseSynchronousLogging 335 { 336 get => _useSynchronousLogging; 337 set => _useSynchronousLogging = value; 338 } 339 340 /// <summary> 341 /// Gets the environment variables which were set when this build was created. 342 /// </summary> 343 public IDictionary<string, string> BuildProcessEnvironment => new ReadOnlyDictionary<string, string>( 344 _buildProcessEnvironment ?? new Dictionary<string, string>(0)); 345 346 /// <summary> 347 /// The name of the culture to use during the build. 348 /// </summary> 349 public CultureInfo Culture 350 { 351 get => _culture; 352 set => _culture = value; 353 } 354 355 /// <summary> 356 /// The default tools version for the build. 357 /// </summary> 358 public string DefaultToolsVersion 359 { 360 get => _defaultToolsVersion; 361 set => _defaultToolsVersion = value; 362 } 363 364 /// <summary> 365 /// When true, indicates that the build should emit a detailed summary at the end of the log. 366 /// </summary> 367 public bool DetailedSummary 368 { 369 get => _detailedSummary; 370 set => _detailedSummary = value; 371 } 372 373 /// <summary> 374 /// When true, indicates the in-proc node should not be used. 375 /// </summary> 376 public bool DisableInProcNode 377 { 378 get => _disableInProcNode; 379 set => _disableInProcNode = value; 380 } 381 382 /// <summary> 383 /// When true, indicates that the task parameters should be logged. 384 /// </summary> 385 public bool LogTaskInputs 386 { 387 get => _logTaskInputs; 388 set => _logTaskInputs = value; 389 } 390 391 /// <summary> 392 /// When true, indicates that the initial properties and items should be logged. 393 /// </summary> 394 public bool LogInitialPropertiesAndItems 395 { 396 get => _logInitialPropertiesAndItems; 397 set => _logInitialPropertiesAndItems = value; 398 } 399 400 /// <summary> 401 /// Indicates that the build should reset the configuration and results caches. 402 /// </summary> 403 public bool ResetCaches 404 { 405 get; 406 set; 407 } 408 409 /// <summary> 410 /// Flag indicating whether out-of-proc nodes should remain after the build and wait for further builds. 411 /// </summary> 412 public bool EnableNodeReuse 413 { 414 get => _enableNodeReuse; 415 set => _enableNodeReuse = value; 416 } 417 418 /// <summary> 419 /// Gets an immutable collection of environment properties. 420 /// </summary> 421 /// <remarks> 422 /// This differs from the BuildProcessEnvironment in that there are certain MSBuild-specific properties which are added, and those environment variables which 423 /// would not be valid as MSBuild properties are removed. 424 /// </remarks> 425 public IDictionary<string, string> EnvironmentProperties 426 { 427 get 428 { 429 return new ReadOnlyConvertingDictionary<string, ProjectPropertyInstance, string>(_environmentProperties, 430 instance => ((IProperty) instance).EvaluatedValueEscaped); 431 } 432 } 433 434 /// <summary> 435 /// The collection of forwarding logger descriptions. 436 /// </summary> 437 public IEnumerable<ForwardingLoggerRecord> ForwardingLoggers 438 { 439 get => _forwardingLoggers; 440 441 set 442 { 443 if (value != null) 444 { 445 foreach (ForwardingLoggerRecord logger in value) 446 { 447 ErrorUtilities.VerifyThrowArgumentNull(logger, "ForwardingLoggers", "NullLoggerNotAllowed"); 448 } 449 } 450 451 _forwardingLoggers = value; 452 } 453 } 454 455 /// <summary> 456 /// Sets or retrieves an immutable collection of global properties. 457 /// </summary> 458 [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = 459 "Accessor returns a readonly collection, and the BuildParameters class is immutable.")] 460 public IDictionary<string, string> GlobalProperties 461 { 462 get 463 { 464 return new ReadOnlyConvertingDictionary<string, ProjectPropertyInstance, string>(_globalProperties, 465 instance => ((IProperty) instance).EvaluatedValueEscaped); 466 } 467 468 set 469 { 470 _globalProperties = new PropertyDictionary<ProjectPropertyInstance>(value.Count); 471 foreach (KeyValuePair<string, string> property in value) 472 { 473 _globalProperties[property.Key] = ProjectPropertyInstance.Create(property.Key, property.Value); 474 } 475 } 476 } 477 478 /// <summary> 479 /// Interface allowing the host to provide additional control over the build process. 480 /// </summary> 481 public HostServices HostServices 482 { 483 get => _hostServices; 484 set => _hostServices = value; 485 } 486 487 /// <summary> 488 /// Enables or disables legacy threading semantics 489 /// </summary> 490 /// <remarks> 491 /// Legacy threading semantics indicate that if a submission is to be built 492 /// only on the in-proc node and the submission is executed synchronously, then all of its 493 /// requests will be built on the thread which invoked the build rather than a 494 /// thread owned by the BuildManager. 495 /// </remarks> 496 public bool LegacyThreadingSemantics 497 { 498 get; 499 set; 500 } 501 502 /// <summary> 503 /// The collection of loggers to use during the build. 504 /// </summary> 505 public IEnumerable<ILogger> Loggers 506 { 507 get => _loggers; 508 509 set 510 { 511 if (value != null) 512 { 513 foreach (ILogger logger in value) 514 { 515 ErrorUtilities.VerifyThrowArgumentNull(logger, "Loggers", "NullLoggerNotAllowed"); 516 } 517 } 518 519 _loggers = value; 520 } 521 } 522 523 /// <summary> 524 /// The maximum number of nodes this build may use. 525 /// </summary> 526 public int MaxNodeCount 527 { 528 get => _maxNodeCount; 529 530 set 531 { 532 ErrorUtilities.VerifyThrowArgument(value > 0, "InvalidMaxNodeCount"); 533 _maxNodeCount = value; 534 } 535 } 536 537 /// <summary> 538 /// The amount of memory the build should limit itself to using, in megabytes. 539 /// </summary> 540 public int MemoryUseLimit 541 { 542 get => _memoryUseLimit; 543 set => _memoryUseLimit = value; 544 } 545 546 /// <summary> 547 /// The location of the build node executable. 548 /// </summary> 549 public string NodeExeLocation 550 { 551 get => _nodeExeLocation; 552 set => _nodeExeLocation = value; 553 } 554 555 /// <summary> 556 /// Flag indicating if non-critical logging events should be discarded. 557 /// </summary> 558 public bool OnlyLogCriticalEvents 559 { 560 get => _onlyLogCriticalEvents; 561 set => _onlyLogCriticalEvents = value; 562 } 563 564 /// <summary> 565 /// A list of warnings to treat as errors. To treat all warnings as errors, set this to an empty <see cref="HashSet{String}"/>. 566 /// </summary> 567 public ISet<string> WarningsAsErrors 568 { 569 get => _warningsAsErrors; 570 set => _warningsAsErrors = value; 571 } 572 573 /// <summary> 574 /// A list of warnings to treat as low importance messages. 575 /// </summary> 576 public ISet<string> WarningsAsMessages 577 { 578 get => _warningsAsMessages; 579 set => _warningsAsMessages = value; 580 } 581 582 /// <summary> 583 /// Locations to search for toolsets. 584 /// </summary> 585 public ToolsetDefinitionLocations ToolsetDefinitionLocations 586 { 587 get => _toolsetDefinitionLocations; 588 set => _toolsetDefinitionLocations = value; 589 } 590 591 /// <summary> 592 /// Returns all of the toolsets. 593 /// </summary> 594 /// <comments> 595 /// toolsetProvider.Toolsets is already a readonly collection. 596 /// </comments> 597 public ICollection<Toolset> Toolsets => _toolsetProvider.Toolsets; 598 599 /// <summary> 600 /// The name of the UI culture to use during the build. 601 /// </summary> 602 public CultureInfo UICulture 603 { 604 get => _uiCulture; 605 set => _uiCulture = value; 606 } 607 608 /// <summary> 609 /// Flag indicating if the operating environment such as the current directory and environment be saved and restored between project builds and task invocations. 610 /// 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. 611 /// </summary> 612 public bool SaveOperatingEnvironment 613 { 614 get => _saveOperatingEnvironment; 615 set => _saveOperatingEnvironment = value; 616 } 617 618 /// <summary> 619 /// Shutdown the inprocess node when the build finishes. By default this is false 620 /// since visual studio needs to keep the inprocess node around after the build finishes. 621 /// </summary> 622 public bool ShutdownInProcNodeOnBuildFinish 623 { 624 get => _shutdownInProcNodeOnBuildFinish; 625 set => _shutdownInProcNodeOnBuildFinish = value; 626 } 627 628 /// <summary> 629 /// Gets the internal msbuild thread stack size. 630 /// </summary> 631 internal static int ThreadStackSize => CommunicationsUtilities.GetIntegerVariableOrDefault( 632 "MSBUILDTHREADSTACKSIZE", DefaultThreadStackSize); 633 634 /// <summary> 635 /// Gets the endpoint shutdown timeout. 636 /// </summary> 637 internal static int EndpointShutdownTimeout => CommunicationsUtilities.GetIntegerVariableOrDefault( 638 "MSBUILDENDPOINTSHUTDOWNTIMEOUT", DefaultEndpointShutdownTimeout); 639 640 /// <summary> 641 /// Gets or sets the engine shutdown timeout. 642 /// </summary> 643 internal static int EngineShutdownTimeout => CommunicationsUtilities.GetIntegerVariableOrDefault( 644 "MSBUILDENGINESHUTDOWNTIMEOUT", DefaultEngineShutdownTimeout); 645 646 /// <summary> 647 /// Gets the maximum number of idle request builders to retain. 648 /// </summary> 649 internal static int IdleRequestBuilderLimit => GetStaticIntVariableOrDefault("MSBUILDIDLEREQUESTBUILDERLIMIT", 650 ref s_idleRequestBuilderLimit, DefaultIdleRequestBuilderLimit); 651 652 /// <summary> 653 /// Gets the logging thread shutdown timeout. 654 /// </summary> 655 internal static int LoggingThreadShutdownTimeout => CommunicationsUtilities.GetIntegerVariableOrDefault( 656 "MSBUILDLOGGINGTHREADSHUTDOWNTIMEOUT", DefaultLoggingThreadShutdownTimeout); 657 658 /// <summary> 659 /// Gets the request builder shutdown timeout. 660 /// </summary> 661 internal static int RequestBuilderShutdownTimeout => CommunicationsUtilities.GetIntegerVariableOrDefault( 662 "MSBUILDREQUESTBUILDERSHUTDOWNTIMEOUT", DefaultRequestBuilderShutdownTimeout); 663 664 /// <summary> 665 /// Gets the startup directory. 666 /// </summary> 667 internal static string StartupDirectory => s_startupDirectory; 668 669 /// <summary> 670 /// Indicates whether the build plan is enabled or not. 671 /// </summary> 672 internal static bool EnableBuildPlan => GetStaticBoolVariableOrDefault("MSBUILDENABLEBUILDPLAN", 673 ref s_enableBuildPlan, false); 674 675 /// <summary> 676 /// Indicates whether we should warn when a property is uninitialized when it is used. 677 /// </summary> 678 internal static bool WarnOnUninitializedProperty 679 { 680 get => GetStaticBoolVariableOrDefault("MSBUILDWARNONUNINITIALIZEDPROPERTY", 681 ref s_warnOnUninitializedProperty, false); 682 683 set => s_warnOnUninitializedProperty = value; 684 } 685 686 /// <summary> 687 /// Indicates whether we should dump string interning stats 688 /// </summary> 689 internal static bool DumpOpportunisticInternStats => GetStaticBoolVariableOrDefault( 690 "MSBUILDDUMPOPPORTUNISTICINTERNSTATS", ref s_dumpOpportunisticInternStats, false); 691 692 /// <summary> 693 /// Indicates whether we should dump debugging information about the expander 694 /// </summary> 695 internal static bool DebugExpansion => GetStaticBoolVariableOrDefault("MSBUILDDEBUGEXPANSION", 696 ref s_debugExpansion, false); 697 698 /// <summary> 699 /// Indicates whether we should keep duplicate target outputs 700 /// </summary> 701 internal static bool KeepDuplicateOutputs => GetStaticBoolVariableOrDefault("MSBUILDKEEPDUPLICATEOUTPUTS", 702 ref s_keepDuplicateOutputs, false); 703 704 /// <summary> 705 /// Gets or sets the build id. 706 /// </summary> 707 internal int BuildId 708 { 709 get => _buildId; 710 set => _buildId = value; 711 } 712 713 /// <summary> 714 /// Gets or sets the environment properties. 715 /// </summary> 716 /// <remarks> 717 /// This is not the same as BuildProcessEnvironment. See EnvironmentProperties. These properties are those which 718 /// are used during evaluation of a project, and exclude those properties which would not be valid MSBuild properties 719 /// because they contain invalid characters (such as 'Program Files (x86)'). 720 /// </remarks> 721 internal PropertyDictionary<ProjectPropertyInstance> EnvironmentPropertiesInternal 722 { 723 get => _environmentProperties; 724 725 set 726 { 727 ErrorUtilities.VerifyThrowInternalNull(value, "EnvironmentPropertiesInternal"); 728 _environmentProperties = value; 729 } 730 } 731 732 /// <summary> 733 /// Gets the global properties. 734 /// </summary> 735 internal PropertyDictionary<ProjectPropertyInstance> GlobalPropertiesInternal => _globalProperties; 736 737 /// <summary> 738 /// Gets or sets the node id. 739 /// </summary> 740 internal int NodeId { get; set; } = 0; 741 742 /// <summary> 743 /// Gets the toolset provider. 744 /// </summary> 745 internal IToolsetProvider ToolsetProvider 746 { 747 get 748 { 749 EnsureToolsets(); 750 return _toolsetProvider; 751 } 752 } 753 754 /// <summary> 755 /// The one and only project root element cache to be used for the build. 756 /// </summary> 757 internal ProjectRootElementCache ProjectRootElementCache 758 { 759 get; 760 set; 761 } 762 763 #if FEATURE_APPDOMAIN 764 /// <summary> 765 /// Information for configuring child AppDomains. 766 /// </summary> 767 internal AppDomainSetup AppDomainSetup 768 { 769 get; 770 set; 771 } 772 #endif 773 774 /// <summary> 775 /// (for diagnostic use) Whether or not this is out of proc 776 /// </summary> 777 internal bool IsOutOfProc 778 { 779 get; 780 set; 781 } 782 783 /// <nodoc/> 784 public ProjectLoadSettings ProjectLoadSettings 785 { 786 get => _projectLoadSettings; 787 set => _projectLoadSettings = value; 788 } 789 790 791 /// <summary> 792 /// Retrieves a toolset. 793 /// </summary> GetToolset(string toolsVersion)794 public Toolset GetToolset(string toolsVersion) 795 { 796 EnsureToolsets(); 797 return _toolsetProvider.GetToolset(toolsVersion); 798 } 799 800 /// <summary> 801 /// Creates a clone of this BuildParameters object. This creates a clone of the logger collections, but does not deep clone 802 /// the loggers within. 803 /// </summary> Clone()804 public BuildParameters Clone() 805 { 806 return new BuildParameters(this); 807 } 808 809 /// <summary> 810 /// Implementation of the serialization mechanism. 811 /// </summary> INodePacketTranslatable.Translate(INodePacketTranslator translator)812 void INodePacketTranslatable.Translate(INodePacketTranslator translator) 813 { 814 translator.Translate(ref _buildId); 815 /* No build thread priority during translation. We specifically use the default (which is ThreadPriority.Normal) */ 816 translator.TranslateDictionary(ref _buildProcessEnvironment, StringComparer.OrdinalIgnoreCase); 817 translator.TranslateCulture(ref _culture); 818 translator.Translate(ref _defaultToolsVersion); 819 translator.Translate(ref _disableInProcNode); 820 translator.Translate(ref _enableNodeReuse); 821 translator.TranslateProjectPropertyInstanceDictionary(ref _environmentProperties); 822 /* No forwarding logger information sent here - that goes with the node configuration */ 823 translator.TranslateProjectPropertyInstanceDictionary(ref _globalProperties); 824 /* No host services during translation */ 825 /* No loggers during translation */ 826 translator.Translate(ref _maxNodeCount); 827 translator.Translate(ref _memoryUseLimit); 828 translator.Translate(ref _nodeExeLocation); 829 /* No node id during translation */ 830 translator.Translate(ref _onlyLogCriticalEvents); 831 translator.Translate(ref s_startupDirectory); 832 translator.TranslateCulture(ref _uiCulture); 833 translator.Translate(ref _toolsetProvider, Microsoft.Build.Evaluation.ToolsetProvider.FactoryForDeserialization); 834 translator.Translate(ref _useSynchronousLogging); 835 translator.Translate(ref _shutdownInProcNodeOnBuildFinish); 836 translator.Translate(ref _logTaskInputs); 837 translator.Translate(ref _logInitialPropertiesAndItems); 838 translator.TranslateEnum(ref _projectLoadSettings, (int) _projectLoadSettings); 839 840 // ProjectRootElementCache is not transmitted. 841 // ResetCaches is not transmitted. 842 // LegacyThreadingSemantics is not transmitted. 843 } 844 845 #region INodePacketTranslatable Members 846 847 /// <summary> 848 /// The class factory for deserialization. 849 /// </summary> FactoryForDeserialization(INodePacketTranslator translator)850 internal static BuildParameters FactoryForDeserialization(INodePacketTranslator translator) 851 { 852 return new BuildParameters(translator); 853 } 854 855 #endregion 856 857 /// <summary> 858 /// Gets the value of a boolean environment setting which is not expected to change. 859 /// </summary> GetStaticBoolVariableOrDefault(string environmentVariable, ref bool? backing, bool @default)860 private static bool GetStaticBoolVariableOrDefault(string environmentVariable, ref bool? backing, bool @default) 861 { 862 if (!backing.HasValue) 863 { 864 backing = !String.IsNullOrEmpty(Environment.GetEnvironmentVariable(environmentVariable)) || @default; 865 } 866 867 return backing.Value; 868 } 869 870 /// <summary> 871 /// Gets the value of an integer environment variable, or returns the default if none is set or it cannot be converted. 872 /// </summary> GetStaticIntVariableOrDefault(string environmentVariable, ref int? backingValue, int defaultValue)873 private static int GetStaticIntVariableOrDefault(string environmentVariable, ref int? backingValue, int defaultValue) 874 { 875 if (!backingValue.HasValue) 876 { 877 string environmentValue = Environment.GetEnvironmentVariable(environmentVariable); 878 if (String.IsNullOrEmpty(environmentValue)) 879 { 880 backingValue = defaultValue; 881 } 882 else 883 { 884 backingValue = Int32.TryParse(environmentValue, out var parsedValue) ? parsedValue : defaultValue; 885 } 886 } 887 888 return backingValue.Value; 889 } 890 891 /// <summary> 892 /// Centralization of the common parts of construction. 893 /// </summary> Initialize(PropertyDictionary<ProjectPropertyInstance> environmentProperties, ProjectRootElementCache projectRootElementCache, ToolsetProvider toolsetProvider)894 private void Initialize(PropertyDictionary<ProjectPropertyInstance> environmentProperties, ProjectRootElementCache projectRootElementCache, ToolsetProvider toolsetProvider) 895 { 896 _buildProcessEnvironment = CommunicationsUtilities.GetEnvironmentVariables(); 897 _environmentProperties = environmentProperties; 898 ProjectRootElementCache = projectRootElementCache; 899 ResetCaches = true; 900 _toolsetProvider = toolsetProvider; 901 902 if (Environment.GetEnvironmentVariable("MSBUILDDISABLENODEREUSE") == "1") // For example to disable node reuse within Visual Studio 903 { 904 _enableNodeReuse = false; 905 } 906 907 if (Environment.GetEnvironmentVariable("MSBUILDDETAILEDSUMMARY") == "1") // For example to get detailed summary within Visual Studio 908 { 909 _detailedSummary = true; 910 } 911 912 _nodeExeLocation = FindMSBuildExe(); 913 } 914 915 /// <summary> 916 /// Loads the toolsets if we don't have them already. 917 /// </summary> EnsureToolsets()918 private void EnsureToolsets() 919 { 920 if (_toolsetProvider != null) 921 { 922 return; 923 } 924 925 _toolsetProvider = new ToolsetProvider(DefaultToolsVersion, _environmentProperties, _globalProperties, ToolsetDefinitionLocations); 926 } 927 928 /// <summary> 929 /// This method determines where MSBuild.Exe is and sets the NodeExePath to that by default. 930 /// </summary> FindMSBuildExe()931 private string FindMSBuildExe() 932 { 933 string location = _nodeExeLocation; 934 935 // Use the location specified by the user in code. 936 if (!string.IsNullOrEmpty(location) && CheckMSBuildExeExistsAt(location)) 937 { 938 return location; 939 } 940 941 // Try what we think is the current executable path. 942 return BuildEnvironmentHelper.Instance.CurrentMSBuildExePath; 943 } 944 945 /// <summary> 946 /// Helper to avoid doing an expensive disk check for MSBuild.exe when 947 /// we already checked in a previous build. 948 /// This File.Exists otherwise can show up in profiles when there's a lot of 949 /// design time builds going on. 950 /// </summary> CheckMSBuildExeExistsAt(string path)951 private bool CheckMSBuildExeExistsAt(string path) 952 { 953 if (s_msbuildExeKnownToExistAt != null && string.Equals(path, s_msbuildExeKnownToExistAt, StringComparison.OrdinalIgnoreCase)) 954 { 955 // We found it there last time: it must exist there. 956 return true; 957 } 958 959 if (File.Exists(path)) 960 { 961 s_msbuildExeKnownToExistAt = path; 962 return true; 963 } 964 965 return false; 966 } 967 } 968 } 969