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;
}