// Perform setup of the LinkContext and parse the arguments. // Return values: // 0 => successfully set up context with all arguments // 1 => argument processing stopped early without errors // -1 => error setting up context protected int SetupContext(ILogger customLogger = null) { Pipeline p = GetStandardPipeline(); context = GetDefaultContext(p); if (customLogger != null) { context.Logger = customLogger; } #if !FEATURE_ILLINK I18nAssemblies assemblies = I18nAssemblies.All; var excluded_features = new HashSet <string> (StringComparer.Ordinal); var resolve_from_xapi_steps = new Stack <string> (); #endif var resolve_from_assembly_steps = new Stack <(string, ResolveFromAssemblyStep.RootVisibility)> (); var resolve_from_xml_steps = new Stack <string> (); var body_substituter_steps = new Stack <string> (); var custom_steps = new Stack <string> (); var set_optimizations = new List <(CodeOptimizations, string, bool)> (); bool dumpDependencies = false; string dependenciesFileName = null; bool removeCAS = true; bool new_mvid_used = false; bool deterministic_used = false; bool resolver = false; while (arguments.Count > 0) { string token = arguments.Dequeue(); if (token.Length < 2) { ErrorUnrecognizedOption(token); return(-1); } // // Handling of --value like options // if (token[0] == '-' && token[1] == '-') { switch (token) { case "--skip-unresolved": if (!GetBoolParam(token, l => context.IgnoreUnresolved = context.Resolver.IgnoreUnresolved = l)) { return(-1); } continue; case "--verbose": context.LogMessages = true; continue; case "--dependencies-file": if (!GetStringParam(token, l => dependenciesFileName = l)) { return(-1); } continue; case "--dump-dependencies": dumpDependencies = true; 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 => removeCAS = l)) { return(-1); } continue; case "--strip-descriptors": if (!GetBoolParam(token, l => context.StripDescriptors = l)) { return(-1); } continue; case "--strip-substitutions": if (!GetBoolParam(token, l => context.StripSubstitutions = l)) { return(-1); } continue; case "--substitutions": if (arguments.Count < 1) { ErrorMissingArgument(token); return(-1); } if (!GetStringParam(token, l => body_substituter_steps.Push(l))) { return(-1); } continue; #if !FEATURE_ILLINK case "--exclude-feature": if (arguments.Count < 1) { ErrorMissingArgument(token); return(-1); } if (!GetStringParam(token, l => { foreach (var feature in l.Split(',')) { if (!excluded_features.Contains(feature)) { excluded_features.Add(feature); } } })) { return(-1); } continue; #endif case "--explicit-reflection": if (!GetBoolParam(token, l => context.AddReflectionAnnotations = l)) { return(-1); } continue; case "--custom-step": if (!GetStringParam(token, l => custom_steps.Push(l))) { return(-1); } continue; case "--custom-data": if (arguments.Count < 1) { ErrorMissingArgument(token); return(-1); } var arg = arguments.Dequeue(); string[] values = arg.Split('='); if (values?.Length != 2) { Console.WriteLine($"Value used with '--custom-data' has to be in the KEY=VALUE format"); return(-1); } context.SetCustomData(values[0], values[1]); continue; case "--keep-facades": if (!GetBoolParam(token, l => context.KeepTypeForwarderOnlyAssemblies = l)) { return(-1); } continue; case "--keep-dep-attributes": if (!GetBoolParam(token, l => context.KeepDependencyAttributes = 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 "--disable-opt": { string optName = null; if (!GetStringParam(token, l => optName = l)) { return(-1); } if (!GetOptimizationName(optName, out var opt)) { return(-1); } string assemblyName = GetNextStringValue(); set_optimizations.Add((opt, assemblyName, false)); continue; } case "--enable-opt": { string optName = null; if (!GetStringParam(token, l => optName = l)) { return(-1); } if (!GetOptimizationName(optName, out var opt)) { return(-1); } string assemblyName = GetNextStringValue(); set_optimizations.Add((opt, assemblyName, true)); continue; } case "--feature": { string featureName = null; if (!GetStringParam(token, l => featureName = l)) { 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, l => context.AssemblyListFile = l)) { return(-1); } continue; case "--output-pinvokes": if (!GetStringParam(token, l => context.PInvokesListFile = l)) { return(-1); } continue; case "--attribute-defs": if (arguments.Count < 1) { ErrorMissingArgument(token); return(-1); } if (!GetStringParam(token, l => context.AddAttributeDefinitionFile(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, l => { DirectoryInfo info = new DirectoryInfo(l); context.Resolver.AddSearchDirectory(info.FullName); })) { return(-1); } continue; case "o": case "out": if (!GetStringParam(token, l => context.OutputDirectory = l)) { return(-1); } continue; case "c": if (!GetStringParam(token, l => context.CoreAction = ParseAssemblyAction(l))) { return(-1); } continue; case "u": if (!GetStringParam(token, l => context.UserAction = ParseAssemblyAction(l))) { return(-1); } continue; case "p": if (arguments.Count < 2) { ErrorMissingArgument(token); return(-1); } AssemblyAction action = ParseAssemblyAction(arguments.Dequeue()); context.Actions[arguments.Dequeue()] = action; continue; case "t": context.KeepTypeForwarderOnlyAssemblies = true; continue; case "x": if (!GetStringParam(token, l => { foreach (string file in GetFiles(l)) { resolve_from_xml_steps.Push(file); } })) { return(-1); } resolver = true; continue; case "r": case "a": if (!GetStringParam(token, l => { var rootVisibility = (token[1] == 'r') ? ResolveFromAssemblyStep.RootVisibility.PublicAndFamily : ResolveFromAssemblyStep.RootVisibility.Any; foreach (string file in GetFiles(l)) { resolve_from_assembly_steps.Push((file, rootVisibility)); } })) { return(-1); } resolver = true; continue; #if !FEATURE_ILLINK case "i": if (!GetStringParam(token, l => { foreach (string file in GetFiles(l)) { resolve_from_xapi_steps.Push(file); } })) { return(-1); } resolver = true; continue; case "l": if (!GetStringParam(token, l => assemblies = ParseI18n(l))) { return(-1); } continue; #endif 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 "v": if (!GetBoolParam(token, l => context.KeepMembersForDebugger = l)) { return(-1); } continue; case "?": case "help": Usage(); return(1); case "reference": if (!GetStringParam(token, l => context.Resolver.AddReferenceAssembly(l))) { return(-1); } continue; } } ErrorUnrecognizedOption(token); return(-1); } if (!resolver) { Console.WriteLine($"No files to link were specified. Use one of '{resolvers}' options"); return(-1); } if (new_mvid_used && deterministic_used) { Console.WriteLine($"Options '--new-mvid' and '--deterministic' cannot be used at the same time"); return(-1); } if (dumpDependencies) { AddXmlDependencyRecorder(context, dependenciesFileName); } 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 // #if !FEATURE_ILLINK foreach (var file in resolve_from_xapi_steps) { p.PrependStep(new ResolveFromXApiStep(new XPathDocument(file))); } #endif foreach (var file in resolve_from_xml_steps) { AddResolveFromXmlStep(p, file); } foreach (var(file, rootVisibility) in resolve_from_assembly_steps) { p.PrependStep(new ResolveFromAssemblyStep(file, rootVisibility)); } 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 !FEATURE_ILLINK p.AddStepAfter(typeof(LoadReferencesStep), new LoadI18nAssemblies(assemblies)); if (assemblies != I18nAssemblies.None) { p.AddStepAfter(typeof(PreserveDependencyLookupStep), new PreserveCalendarsStep(assemblies)); } #endif if (_needAddBypassNGenStep) { p.AddStepAfter(typeof(SweepStep), new AddBypassNGenStep()); } if (removeCAS) { p.AddStepBefore(typeof(MarkStep), new RemoveSecurityStep()); } #if !FEATURE_ILLINK if (excluded_features.Count > 0) { p.AddStepBefore(typeof(MarkStep), new RemoveFeaturesStep() { FeatureCOM = excluded_features.Contains("com"), FeatureETW = excluded_features.Contains("etw"), FeatureSRE = excluded_features.Contains("sre"), FeatureGlobalization = excluded_features.Contains("globalization") }); var excluded = new string[excluded_features.Count]; excluded_features.CopyTo(excluded); context.ExcludedFeatures = excluded; } #endif p.AddStepBefore(typeof(MarkStep), new RemoveUnreachableBlocksStep()); p.AddStepBefore(typeof(OutputStep), new ClearInitLocalsStep()); p.AddStepBefore(typeof(OutputStep), new SealerStep()); // // Pipeline setup with all steps enabled // // ResolveFromAssemblyStep [optional, possibly many] // ResolveFromXmlStep [optional, possibly many] // [mono only] ResolveFromXApiStep [optional, possibly many] // LoadReferencesStep // [mono only] LoadI18nAssemblies // BlacklistStep // dynamically adds steps: // ResolveFromXmlStep [optional, possibly many] // BodySubstituterStep [optional, possibly many] // PreserveDependencyLookupStep // [mono only] PreselveCalendarsStep [optional] // TypeMapStep // BodySubstituterStep [optional] // RemoveSecurityStep [optional] // [mono only] RemoveFeaturesStep [optional] // RemoveUnreachableBlocksStep [optional] // MarkStep // ReflectionBlockedStep [optional] // SweepStep // AddBypassNGenStep [optional] // CodeRewriterStep // CleanStep // RegenerateGuidStep [optional] // ClearInitLocalsStep // SealerStep // OutputStep // foreach (string custom_step in custom_steps) { if (!AddCustomStep(p, custom_step)) { return(-1); } } return(0); }