Beispiel #1
0
        // 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);
        }