-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
BuildParameters.cs
991 lines (847 loc) · 37.7 KB
/
BuildParameters.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Globalization;
using Microsoft.Build.BackEnd;
using Microsoft.Build.Collections;
using Microsoft.Build.Evaluation;
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;
/// <summary>
/// The settings used to load the project under build
/// </summary>
private ProjectLoadSettings _projectLoadSettings = ProjectLoadSettings.Default;
private bool _interactive;
private bool _isolateProjects;
private string[] _inputResultsCacheFiles;
private string _outputResultsCacheFile;
/// <summary>
/// Constructor for those who intend to set all properties themselves.
/// </summary>
public BuildParameters()
{
Initialize(Utilities.GetEnvironmentProperties(), 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, nameof(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, nameof(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;
_isolateProjects = other._isolateProjects;
_inputResultsCacheFiles = other._inputResultsCacheFiles;
_outputResultsCacheFile = other._outputResultsCacheFile;
DiscardBuildResults = other.DiscardBuildResults;
LowPriority = other.LowPriority;
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.
/// </summary>
internal static string StartupDirectory => s_startupDirectory;
/// <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 whether projects should build in isolation.
/// </summary>
public bool IsolateProjects
{
get => _isolateProjects;
set => _isolateProjects = value;
}
/// <summary>
/// Input cache files that MSBuild will use to read build results from.
/// Setting this also turns on isolated builds.
/// </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.
/// Setting this also turns on isolated builds.
/// </summary>
public string OutputResultsCacheFile
{
get => _outputResultsCacheFile;
set => _outputResultsCacheFile = value;
}
/// <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>
/// If set, the BuildManager will query all
/// incoming <see cref="BuildSubmission"/> requests against the specified project cache.
/// Any <see cref="GraphBuildSubmission"/> requests will also use this project cache instead of
/// the potential project caches described in graph node's evaluations.
/// </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() => IsolateProjects;
/// <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 _isolateProjects);
// 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;
}
}
}