protected int SetupContext()

in src/tools/illink/src/linker/Linker/Driver.cs [188:824]


		protected int SetupContext (ILogger? customLogger = null)
		{
			Pipeline p = GetStandardPipeline ();
			context = GetDefaultContext (p, customLogger);

			var body_substituter_steps = new Stack<string> ();
			var xml_custom_attribute_steps = new Stack<string> ();
			var custom_steps = new List<string> ();
			var set_optimizations = new List<(CodeOptimizations, string?, bool)> ();
			bool dumpDependencies = false;
			string? dependenciesFileName = null;
			context.StripSecurity = true;
			bool new_mvid_used = false;
			bool deterministic_used = false;
			bool keepCompilersResources = false;
			MetadataTrimming metadataTrimming = MetadataTrimming.Any;
			DependenciesFileFormat fileType = DependenciesFileFormat.Xml;

			List<BaseStep> inputs = CreateDefaultResolvers ();

			while (arguments.Count > 0) {
				string token = arguments.Dequeue ();
				if (token.Length < 2) {
					context.LogError (null, DiagnosticId.UnrecognizedCommandLineOption, token);
					return -1;
				}

				//
				// Handling of --value like options
				//
				if (token[0] == '-' && token[1] == '-') {
					switch (token) {
					case "--help":
						Usage ();
						return 1;

					case "--skip-unresolved":
						if (!GetBoolParam (token, l => context.IgnoreUnresolved = l))
							return -1;

						continue;

					case "--verbose":
						context.LogMessages = true;
						continue;

					case "--dependencies-file":
						if (!GetStringParam (token, out dependenciesFileName))
							return -1;

						continue;

					case "--dump-dependencies": {
							dumpDependencies = true;

							string? assemblyName = GetNextStringValue ();
							if (assemblyName != null) {
								if (!IsValidAssemblyName (assemblyName)) {
									context.LogError (null, DiagnosticId.InvalidAssemblyName, assemblyName);
									return -1;
								}

								context.TraceAssembly ??= new HashSet<string> ();
								context.TraceAssembly.Add (assemblyName);
							}

							continue;
						}

					case "--dependencies-file-format":
						if (!GetStringParam (token, out var dependenciesFileFormat))
							return -1;

						if (!Enum.TryParse (dependenciesFileFormat, ignoreCase: true, out fileType)) {
							context.LogError (null, DiagnosticId.InvalidDependenciesFileFormat);
							return -1;
						}
						continue;

					case "--reduced-tracing":
						if (!GetBoolParam (token, l => context.EnableReducedTracing = l))
							return -1;

						continue;

					case "--used-attrs-only":
						if (!GetBoolParam (token, l => context.KeepUsedAttributeTypesOnly = l))
							return -1;

						continue;

					case "--strip-security":
						if (!GetBoolParam (token, l => context.StripSecurity = l))
							return -1;

						continue;

					case "--strip-descriptors":
						if (!GetBoolParam (token, l => set_optimizations.Add ((CodeOptimizations.RemoveDescriptors, null, l))))
							return -1;

						continue;

					case "--strip-substitutions":
						if (!GetBoolParam (token, l => set_optimizations.Add ((CodeOptimizations.RemoveSubstitutions, null, l))))
							return -1;

						continue;

					case "--strip-link-attributes":
						if (!GetBoolParam (token, l => set_optimizations.Add ((CodeOptimizations.RemoveLinkAttributes, null, l))))
							return -1;

						continue;

					case "--substitutions":
						if (arguments.Count < 1) {
							ErrorMissingArgument (token);
							return -1;
						}

						if (!GetStringParam (token, out string? substitutionFile))
							return -1;

						body_substituter_steps.Push (substitutionFile);

						continue;
					case "--explicit-reflection":
						if (!GetBoolParam (token, l => context.AddReflectionAnnotations = l))
							return -1;

						continue;

					case "--action": {
							if (!GetStringParam (token, out string? actionString))
								return -1;

							AssemblyAction? action = ParseAssemblyAction (actionString);
							if (action == null)
								return -1;

							string? assemblyName = GetNextStringValue ();
							if (assemblyName == null) {
								context.DefaultAction = action.Value;
								continue;
							}

							if (!IsValidAssemblyName (assemblyName)) {
								context.LogError (null, DiagnosticId.InvalidAssemblyName, assemblyName);
								return -1;
							}

							context.RegisterAssemblyAction (assemblyName, action.Value);
							continue;
						}
					case "--trim-mode": {
							if (!GetStringParam (token, out string? actionString))
								return -1;

							AssemblyAction? action = ParseAssemblyAction (actionString);
							if (action == null)
								return -1;

							context.TrimAction = action.Value;
							continue;
						}
					case "--custom-step":
						if (!GetStringParam (token, out string? custom_step))
							return -1;

						custom_steps.Add (custom_step);

						continue;

					case "--custom-data":
						if (arguments.Count < 1) {
							ErrorMissingArgument (token);
							return -1;
						}

						var arg = arguments.Dequeue ();
						string[] values = arg.Split ('=');
						if (values?.Length != 2) {
							context.LogError (null, DiagnosticId.CustomDataFormatIsInvalid);
							return -1;
						}

						context.SetCustomData (values[0], values[1]);
						continue;

					case "--keep-com-interfaces":
						if (!GetBoolParam (token, l => context.KeepComInterfaces = l))
							return -1;

						continue;

					case "--keep-compilers-resources":
						if (!GetBoolParam (token, l => keepCompilersResources = l))
							return -1;

						continue;

					case "--keep-dep-attributes":
						if (!GetBoolParam (token, l => set_optimizations.Add ((CodeOptimizations.RemoveDynamicDependencyAttribute, null, !l))))
							return -1;

						continue;

					case "--keep-metadata": {
							if (!GetStringParam (token, out string? mname))
								return -1;

							if (!TryGetMetadataTrimming (mname, out var type))
								return -1;

							metadataTrimming &= ~type;
							continue;
						}

					case "--enable-serialization-discovery":
						if (!GetBoolParam (token, l => context.EnableSerializationDiscovery = l))
							return -1;

						continue;

					case "--disable-operator-discovery":
						if (!GetBoolParam (token, l => context.DisableOperatorDiscovery = l))
							return -1;

						continue;

					case "--ignore-descriptors":
						if (!GetBoolParam (token, l => context.IgnoreDescriptors = l))
							return -1;

						continue;

					case "--ignore-substitutions":
						if (!GetBoolParam (token, l => context.IgnoreSubstitutions = l))
							return -1;

						continue;

					case "--ignore-link-attributes":
						if (!GetBoolParam (token, l => context.IgnoreLinkAttributes = l))
							return -1;

						continue;

					case "--disable-opt": {
							if (!GetStringParam (token, out string? optName))
								return -1;

							if (!GetOptimizationName (optName, out var opt))
								return -1;

							string? assemblyName = GetNextStringValue ();
							set_optimizations.Add ((opt, assemblyName, false));

							continue;
						}
					case "--enable-opt": {
							if (!GetStringParam (token, out string? optName))
								return -1;

							if (!GetOptimizationName (optName, out var opt))
								return -1;

							string? assemblyName = GetNextStringValue ();
							set_optimizations.Add ((opt, assemblyName, true));

							continue;
						}

					case "--feature": {
							if (!GetStringParam (token, out string? featureName))
								return -1;

							if (!GetBoolParam (token, value => {
								context.SetFeatureValue (featureName, value);
							}))
								return -1;

							continue;
						}
					case "--new-mvid":
						//
						// This is not same as --deterministic which calculates MVID
						// from stable assembly content. This option creates a new random
						// mvid or uses mvid of the source assembly.
						//
						if (!GetBoolParam (token, l => {
							if (!l)
								p.RemoveStep (typeof (RegenerateGuidStep));
						}))
							return -1;

						new_mvid_used = true;
						continue;

					case "--deterministic":
						if (!GetBoolParam (token, l => context.DeterministicOutput = l))
							return -1;

						deterministic_used = true;
						continue;

					case "--output-assemblylist":
						if (!GetStringParam (token, out string? assemblyListFile))
							return -1;

						context.AssemblyListFile = assemblyListFile;

						continue;

					case "--output-pinvokes":
						if (!GetStringParam (token, out string? pinvokesListFile))
							return -1;

						context.PInvokesListFile = pinvokesListFile;

						continue;

					case "--link-attributes":
						if (arguments.Count < 1) {
							ErrorMissingArgument (token);
							return -1;
						}

						if (!GetStringParam (token, out string? fileList))
							return -1;

						foreach (string file in GetFiles (fileList))
							xml_custom_attribute_steps.Push (file);

						continue;

					case "--generate-warning-suppressions":
						if (!GetStringParam (token, out string? generateWarningSuppressionsArgument))
							return -1;

						if (!GetWarningSuppressionWriterFileOutputKind (generateWarningSuppressionsArgument, out var fileOutputKind)) {
							context.LogError (null, DiagnosticId.InvalidGenerateWarningSuppressionsValue, generateWarningSuppressionsArgument);
							return -1;
						}

						context.WarningSuppressionWriter = new WarningSuppressionWriter (context, fileOutputKind);
						continue;

					case "--notrimwarn":
						context.NoTrimWarn = true;
						continue;

					case "--nowarn":
						if (!GetStringParam (token, out string? noWarnArgument))
							return -1;

						context.NoWarn.UnionWith (ProcessWarningCodes (noWarnArgument));
						continue;

					case "--warnaserror":
					case "--warnaserror+":
						var warningList = GetNextStringValue ();
						if (!string.IsNullOrEmpty (warningList)) {
							foreach (var warning in ProcessWarningCodes (warningList))
								context.WarnAsError[warning] = true;

						} else {
							context.GeneralWarnAsError = true;
							context.WarnAsError.Clear ();
						}

						continue;

					case "--warnaserror-":
						warningList = GetNextStringValue ();
						if (!string.IsNullOrEmpty (warningList)) {
							foreach (var warning in ProcessWarningCodes (warningList))
								context.WarnAsError[warning] = false;

						} else {
							context.GeneralWarnAsError = false;
							context.WarnAsError.Clear ();
						}

						continue;

					case "--warn":
						if (!GetStringParam (token, out string? warnVersionArgument))
							return -1;

						if (!GetWarnVersion (warnVersionArgument, out WarnVersion version))
							return -1;

						context.WarnVersion = version;

						continue;

					case "--singlewarn":
					case "--singlewarn+": {
							string? assemblyName = GetNextStringValue ();
							if (assemblyName != null) {
								if (!IsValidAssemblyName (assemblyName)) {
									context.LogError (null, DiagnosticId.InvalidAssemblyName, assemblyName);
									return -1;
								}

								context.SingleWarn[assemblyName] = true;
							} else {
								context.GeneralSingleWarn = true;
								context.SingleWarn.Clear ();
							}

							continue;
						}

					case "--singlewarn-": {
							string? assemblyName = GetNextStringValue ();
							if (assemblyName != null) {
								if (!IsValidAssemblyName (assemblyName)) {
									context.LogError (null, DiagnosticId.InvalidAssemblyName, assemblyName);
									return -1;
								}

								context.SingleWarn[assemblyName] = false;
							} else {
								context.GeneralSingleWarn = false;
								context.SingleWarn.Clear ();
							}

							continue;
						}

					case "--preserve-symbol-paths":
						if (!GetBoolParam (token, l => context.PreserveSymbolPaths = l))
							return -1;

						continue;

					case "--version":
						Version ();
						return 1;

					case "--about":
						About ();
						return 1;
					}
				}

				if (token[0] == '-' || token[1] == '/') {

					switch (token.Substring (1)) {
					case "d":
						if (!GetStringParam (token, out string? directory))
							return -1;

						DirectoryInfo info = new DirectoryInfo (directory);
						context.Resolver.AddSearchDirectory (info.FullName);

						continue;
					case "o":
					case "out":
						if (!GetStringParam (token, out string? outputDirectory))
							return -1;

						context.OutputDirectory = outputDirectory;

						continue;
					case "x": {
							if (!GetStringParam (token, out string? xmlFile))
								return -1;

							if (!File.Exists (xmlFile)) {
								context.LogError (null, DiagnosticId.XmlDescriptorCouldNotBeFound, xmlFile);
								return -1;
							}

							inputs.Add (new ResolveFromXmlStep (File.OpenRead (xmlFile), xmlFile));
							continue;
						}
					case "a": {
							if (!GetStringParam (token, out string? assemblyFile))
								return -1;

							if (!File.Exists (assemblyFile) && assemblyFile.EndsWith (".dll", StringComparison.InvariantCultureIgnoreCase)) {
								context.LogError (null, DiagnosticId.RootAssemblyCouldNotBeFound, assemblyFile);
								return -1;
							}

							AssemblyRootMode rmode = AssemblyRootMode.AllMembers;
							var rootMode = GetNextStringValue ();
							if (rootMode != null) {
								var parsed_rmode = ParseAssemblyRootMode (rootMode);
								if (parsed_rmode is null)
									return -1;

								rmode = parsed_rmode.Value;
							}

							inputs.Add (new RootAssemblyInput (assemblyFile, rmode));
							continue;
						}
					case "b":
						if (!GetBoolParam (token, l => context.LinkSymbols = l))
							return -1;

						continue;
					case "g":
						if (!GetBoolParam (token, l => context.DeterministicOutput = !l))
							return -1;

						continue;
					case "z":
						if (!GetBoolParam (token, l => context.IgnoreDescriptors = !l))
							return -1;

						continue;
					case "?":
					case "h":
					case "help":
						Usage ();
						return 1;

					case "reference":
						if (!GetStringParam (token, out string? reference))
							return -1;

						context.Resolver.AddReferenceAssembly (reference);

						continue;
					}
				}

				context.LogError (null, DiagnosticId.UnrecognizedCommandLineOption, token);
				return -1;
			}

			if (inputs.Count == 0) {
				context.LogError (null, DiagnosticId.NoFilesToLinkSpecified, resolvers);
				return -1;
			}

			if (new_mvid_used && deterministic_used) {
				context.LogError (null, DiagnosticId.NewMvidAndDeterministicCannotBeUsedAtSameTime);
				return -1;
			}

			context.MetadataTrimming = metadataTrimming;

			// Default to deterministic output
			if (!new_mvid_used && !deterministic_used) {
				context.DeterministicOutput = true;
			}
			if (dumpDependencies) {
				switch (fileType) {
				case DependenciesFileFormat.Xml:
					AddXmlDependencyRecorder (context, dependenciesFileName);
					break;
				case DependenciesFileFormat.Dgml:
					AddDgmlDependencyRecorder (context, dependenciesFileName);
					break;
				default:
					context.LogError (null, DiagnosticId.InvalidDependenciesFileFormat);
					break;
				}
			}


			if (set_optimizations.Count > 0) {
				foreach (var (opt, assemblyName, enable) in set_optimizations) {
					if (enable)
						context.Optimizations.Enable (opt, assemblyName);
					else
						context.Optimizations.Disable (opt, assemblyName);
				}
			}

			//
			// Modify the default pipeline
			//

			for (int i = inputs.Count; i != 0; --i)
				p.PrependStep (inputs[i - 1]);

			foreach (var file in xml_custom_attribute_steps)
				AddLinkAttributesStep (p, file);

			foreach (var file in body_substituter_steps)
				AddBodySubstituterStep (p, file);

			if (context.DeterministicOutput)
				p.RemoveStep (typeof (RegenerateGuidStep));

			if (context.AddReflectionAnnotations)
				p.AddStepAfter (typeof (MarkStep), new ReflectionBlockedStep ());

			if (_needAddBypassNGenStep)
				p.AddStepAfter (typeof (SweepStep), new AddBypassNGenStep ());

			if (keepCompilersResources) {
				p.RemoveStep (typeof (RemoveResourcesStep));
			}

			p.AddStepBefore (typeof (OutputStep), new SealerStep ());

			//
			// Pipeline setup with all steps enabled
			//
			// RootAssemblyInputStep or ResolveFromXmlStep [at least one of them]
			// LinkAttributesStep [optional, possibly many]
			// BodySubstituterStep [optional]
			// MarkStep
			// ReflectionBlockedStep [optional]
			// RemoveResourcesStep [optional]
			// ProcessWarningsStep
			// OutputWarningSuppressions
			// SweepStep
			// AddBypassNGenStep [optional]
			// CodeRewriterStep
			// CleanStep
			// RegenerateGuidStep [optional]
			// SealerStep
			// OutputStep

			if (context.EnableSerializationDiscovery)
				p.MarkHandlers.Add (new DiscoverSerializationHandler ());

			if (!context.DisableOperatorDiscovery)
				p.MarkHandlers.Add (new DiscoverOperatorsHandler ());

			foreach (string custom_step in custom_steps) {
				if (!AddCustomStep (p, custom_step))
					return -1;
			}

			return 0;
		}