Example #1
0
        protected override string GenerateCommandLineCommands()
        {
            ProcessArguments arguments = null;

            if (!InvokeLinkerUsingMono)
            {
                arguments = ProcessArguments.Create("--verbose");
            }
            else
            {
                var toolsPath = GetPathToMonoLinker();
                Log.LogMessage(MessageImportance.High, $"Running monolinker from {toolsPath}.");
                arguments = ProcessArguments.Create(toolsPath);
                arguments = arguments.Add("--verbose");
            }

            // add exclude features
            arguments = arguments.AddRange("--exclude-feature", "remoting", "--exclude-feature", "com", "--exclude-feature", "etw");

            string coremode, usermode;

            switch ((WasmLinkMode)Enum.Parse(typeof(WasmLinkMode), LinkMode))
            {
            case WasmLinkMode.SdkOnly:
                coremode = "link";
                usermode = "copy";
                break;

            case WasmLinkMode.Full:
                coremode = "link";
                usermode = "link";
                break;

            default:
                coremode = "copyused";
                usermode = "copy";
                break;
            }

            arguments = arguments.AddRange("-c", coremode, "-u", usermode);

            //the linker doesn't consider these core by default
            arguments = arguments.AddRange("-p", coremode, "WebAssembly.Bindings");
            arguments = arguments.AddRange("-p", coremode, "WebAssembly.Net.Http");
            arguments = arguments.AddRange("-p", coremode, "WebAssembly.Net.WebSockets");

            if (!string.IsNullOrEmpty(LinkSkip))
            {
                var skips = LinkSkip.Split(new[] { ';', ',', ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var s in skips)
                {
                    arguments = arguments.AddRange("-p", "copy", s);
                }
            }

            arguments = arguments.AddRange("-out", OutputDir);

            arguments = arguments.AddRange("-d", FrameworkDir);

            arguments = arguments.AddRange("-d", Path.Combine(FrameworkDir, "Facades"));

            arguments = arguments.AddRange("-b", Debug.ToString());
            arguments = arguments.AddRange("-v", Debug.ToString());

            arguments = arguments.AddRange("-a", RootAssembly[0].GetMetadata("FullPath"));

            //we'll normally have to check most of the because the SDK references most framework asm by default
            //so let's enumerate upfront
            var frameworkAssemblies = new HashSet <string> (StringComparer.OrdinalIgnoreCase);

            foreach (var f in Directory.EnumerateFiles(FrameworkDir))
            {
                frameworkAssemblies.Add(Path.GetFileNameWithoutExtension(f));
            }
            foreach (var f in Directory.EnumerateFiles(Path.Combine(FrameworkDir, "Facades")))
            {
                frameworkAssemblies.Add(Path.GetFileNameWithoutExtension(f));
            }

            //add references for non-framework assemblies
            if (Assemblies != null)
            {
                foreach (var asm in Assemblies)
                {
                    var p = asm.GetMetadata("FullPath");
                    if (frameworkAssemblies.Contains(Path.GetFileNameWithoutExtension(p)))
                    {
                        continue;
                    }
                    arguments = arguments.AddRange("-r", p);
                }
            }

            if (string.IsNullOrEmpty(I18n))
            {
                arguments = arguments.AddRange("-l", "none");
            }
            else
            {
                var vals = I18n.Split(new[] { ',', ';', ' ', '\r', '\n', '\t' });
                arguments = arguments.AddRange("-l", string.Join(",", vals));
            }
            return(arguments.ToString());
        }
        bool Execute(DirectoryAssemblyResolver res)
        {
            // Put every assembly we'll need in the resolver
            foreach (var assembly in ResolvedAssemblies)
            {
                res.Load(Path.GetFullPath(assembly.ItemSpec));
            }

            var resolver = new AssemblyResolver(res.ToResolverCache());

            // Set up for linking
            var options = new LinkerOptions();

            options.MainAssembly     = res.GetAssembly(MainAssembly);
            options.OutputDirectory  = Path.GetFullPath(OutputDirectory);
            options.LinkSdkOnly      = string.Compare(LinkMode, "SdkOnly", true) == 0;
            options.LinkNone         = false;
            options.Resolver         = resolver;
            options.LinkDescriptions = LinkDescriptions.Select(item => Path.GetFullPath(item.ItemSpec)).ToArray();
            options.I18nAssemblies   = Linker.ParseI18nAssemblies(I18nAssemblies);
            if (!options.LinkSdkOnly)
            {
                options.RetainAssemblies = GetRetainAssemblies(res);
            }
            options.DumpDependencies          = DumpDependencies;
            options.HttpClientHandlerType     = HttpClientHandlerType;
            options.TlsProvider               = TlsProvider;
            options.AddKeepAlives             = AddKeepAlives;
            options.PreserveJniMarshalMethods = PreserveJniMarshalMethods;
            options.DeterministicOutput       = Deterministic;
            options.LinkResources             = LinkResources;

            var skiplist = new List <string> ();

            // Add LinkSkip options
            if (!string.IsNullOrWhiteSpace(LinkSkip))
            {
                skiplist.AddRange(LinkSkip.Split(',', ';'));
            }

            options.SkippedAssemblies = skiplist;

            if (EnableProguard)
            {
                options.ProguardConfiguration = ProguardConfiguration;
            }

            // Link!
            try {
                LinkContext link_context;
                Linker.Process(options, this, out link_context);

                foreach (var assembly in ResolvedAssemblies)
                {
                    var copysrc             = assembly.ItemSpec;
                    var filename            = Path.GetFileName(assembly.ItemSpec);
                    var assemblyDestination = Path.Combine(OutputDirectory, filename);

                    if (!MonoAndroidHelper.IsForceRetainedAssembly(filename))
                    {
                        continue;
                    }

                    MonoAndroidHelper.CopyAssemblyAndSymbols(copysrc, assemblyDestination);
                }
            } catch (ResolutionException ex) {
                Diagnostic.Error(2006, ex, Properties.Resources.XA2006, ex.Member, ex.Member.Module.Assembly, ex.Scope);
            }

            return(true);
        }
        bool Execute(DirectoryAssemblyResolver res)
        {
            // Put every assembly we'll need in the resolver
            foreach (var assembly in ResolvedAssemblies)
            {
                res.Load(Path.GetFullPath(assembly.ItemSpec));
            }

            var resolver = new AssemblyResolver(res.ToResolverCache());

            // Set up for linking
            var options = new LinkerOptions();

            options.MainAssembly     = res.GetAssembly(MainAssembly);
            options.OutputDirectory  = Path.GetFullPath(OutputDirectory);
            options.LinkSdkOnly      = string.Compare(LinkMode, "SdkOnly", true) == 0;
            options.LinkNone         = string.Compare(LinkMode, "None", true) == 0;
            options.Resolver         = resolver;
            options.LinkDescriptions = LinkDescriptions.Select(item => Path.GetFullPath(item.ItemSpec)).ToArray();
            options.I18nAssemblies   = Linker.ParseI18nAssemblies(I18nAssemblies);
            if (!options.LinkSdkOnly)
            {
                options.RetainAssemblies = GetRetainAssemblies(res);
            }
            options.DumpDependencies          = DumpDependencies;
            options.HttpClientHandlerType     = HttpClientHandlerType;
            options.TlsProvider               = TlsProvider;
            options.PreserveJniMarshalMethods = PreserveJniMarshalMethods;

            var skiplist = new List <string> ();

            if (string.Compare(UseSharedRuntime, "true", true) == 0)
            {
                skiplist.AddRange(Profile.SharedRuntimeAssemblies.Where(a => a.EndsWith(".dll")).Select(a => Path.GetFileNameWithoutExtension(a)));
            }
            if (!string.IsNullOrWhiteSpace(LinkOnlyNewerThan) && File.Exists(LinkOnlyNewerThan))
            {
                var newerThan   = File.GetLastWriteTime(LinkOnlyNewerThan);
                var skipOldOnes = ResolvedAssemblies.Where(a => File.GetLastWriteTime(a.ItemSpec) < newerThan);
                foreach (var old in skipOldOnes)
                {
                    Log.LogMessage(MBF.MessageImportance.Low, "  Skip linking unchanged file: " + old.ItemSpec);
                }
                skiplist = skipOldOnes.Select(a => Path.GetFileNameWithoutExtension(a.ItemSpec)).Concat(skiplist).ToList();
            }

            // Add LinkSkip options
            if (!string.IsNullOrWhiteSpace(LinkSkip))
            {
                foreach (var assembly in LinkSkip.Split(',', ';'))
                {
                    skiplist.Add(assembly);
                }
            }

            options.SkippedAssemblies = skiplist;

            if (EnableProguard)
            {
                options.ProguardConfiguration = ProguardConfiguration;
            }

            // Link!
            try {
                LinkContext link_context;
                Linker.Process(options, this, out link_context);

                var copydst = OptionalDestinationDirectory ?? OutputDirectory;

                foreach (var assembly in ResolvedAssemblies)
                {
                    var copysrc             = assembly.ItemSpec;
                    var filename            = Path.GetFileName(assembly.ItemSpec);
                    var assemblyDestination = Path.Combine(copydst, filename);

                    if (options.LinkNone)
                    {
                        if (skiplist.Any(s => Path.GetFileNameWithoutExtension(filename) == s))
                        {
                            // For skipped assemblies, skip if there is existing file in the destination.
                            // We cannot just copy the linker output from *current* run output, because
                            // it always renew the assemblies, in *different* binary values, whereas
                            // the dll in the OptionalDestinationDirectory must retain old and unchanged.
                            if (File.Exists(assemblyDestination))
                            {
                                MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(assemblyDestination, DateTime.UtcNow, Log);
                                continue;
                            }
                        }
                        else
                        {
                            // Prefer fixup assemblies if exists, otherwise just copy the original.
                            copysrc = Path.Combine(OutputDirectory, filename);
                            copysrc = File.Exists(copysrc) ? copysrc : assembly.ItemSpec;
                        }
                    }
                    else if (!MonoAndroidHelper.IsForceRetainedAssembly(filename))
                    {
                        continue;
                    }

                    if (MonoAndroidHelper.CopyIfChanged(copysrc, assemblyDestination))
                    {
                        MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(assemblyDestination, DateTime.UtcNow, Log);
                    }
                    try {
                        var mdbDestination = assemblyDestination + ".mdb";
                        if (MonoAndroidHelper.CopyIfChanged(assembly.ItemSpec + ".mdb", mdbDestination))
                        {
                            MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(mdbDestination, DateTime.UtcNow, Log);
                        }
                    } catch (Exception) {                     // skip it, mdb sometimes fails to read and it's optional
                    }
                    var pdb = Path.ChangeExtension(copysrc, "pdb");
                    if (File.Exists(pdb) && Files.IsPortablePdb(pdb))
                    {
                        var pdbDestination = Path.ChangeExtension(Path.Combine(copydst, filename), "pdb");
                        if (MonoAndroidHelper.CopyIfChanged(pdb, pdbDestination))
                        {
                            MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(pdbDestination, DateTime.UtcNow, Log);
                        }
                    }
                }
            } catch (ResolutionException ex) {
                Diagnostic.Error(2006, ex, "Could not resolve reference to '{0}' (defined in assembly '{1}') with scope '{2}'. When the scope is different from the defining assembly, it usually means that the type is forwarded.", ex.Member, ex.Member.Module.Assembly, ex.Scope);
            }

            return(true);
        }
        protected override string GenerateCommandLineCommands()
        {
            var sb = new StringBuilder();

            sb.Append(" --verbose");

            string coremode, usermode;

            switch ((WasmLinkMode)Enum.Parse(typeof(WasmLinkMode), LinkMode))
            {
            case WasmLinkMode.SdkOnly:
                coremode = "link";
                usermode = "copy";
                break;

            case WasmLinkMode.Full:
                coremode = "link";
                usermode = "link";
                break;

            default:
                coremode = "copyused";
                usermode = "copy";
                break;
            }

            sb.AppendFormat(" -c {0} -u {1}", coremode, usermode);

            //the linker doesn't consider these core by default
            sb.AppendFormat(" -p {0} netstandard -p {1} WebAssembly.Bindings -p {1} WebAssembly.Net.Http", coremode, usermode);

            if (!string.IsNullOrEmpty(LinkSkip))
            {
                var skips = LinkSkip.Split(new[] { ';', ',', ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var s in skips)
                {
                    sb.AppendFormat(" -p \"{0}\" copy", s);
                }
            }

            sb.AppendFormat(" -out \"{0}\"", OutputDir);
            sb.AppendFormat(" -d \"{0}\"", FrameworkDir);
            sb.AppendFormat(" -b {0} -v {0}", Debug);

            sb.AppendFormat(" -a \"{0}\"", RootAssembly[0].GetMetadata("FullPath"));

            //we'll normally have to check most of the because the SDK references most framework asm by default
            //so let's enumerate upfront
            var frameworkAssemblies = new HashSet <string> (StringComparer.OrdinalIgnoreCase);

            foreach (var f in Directory.EnumerateFiles(FrameworkDir))
            {
                frameworkAssemblies.Add(Path.GetFileNameWithoutExtension(f));
            }
            foreach (var f in Directory.EnumerateFiles(Path.Combine(FrameworkDir, "Facades")))
            {
                frameworkAssemblies.Add(Path.GetFileNameWithoutExtension(f));
            }

            //add references for non-framework assemblies
            if (Assemblies != null)
            {
                foreach (var asm in Assemblies)
                {
                    var p = asm.GetMetadata("FullPath");
                    if (frameworkAssemblies.Contains(Path.GetFileNameWithoutExtension(p)))
                    {
                        continue;
                    }
                    sb.AppendFormat(" -r \"{0}\"", p);
                }
            }

            if (string.IsNullOrEmpty(I18n))
            {
                sb.Append(" -l none");
            }
            else
            {
                var vals = I18n.Split(new[] { ',', ';', ' ', '\r', '\n', '\t' });
                sb.AppendFormat(" -l {0}", string.Join(",", vals));
            }

            return(sb.ToString());
        }
Example #5
0
        public override bool Execute()
        {
            Log.LogDebugMessage("LinkAssemblies Task");
            Log.LogDebugMessage("  UseSharedRuntime: {0}", UseSharedRuntime);
            Log.LogDebugMessage("  MainAssembly: {0}", MainAssembly);
            Log.LogDebugMessage("  OutputDirectory: {0}", OutputDirectory);
            Log.LogDebugMessage("  OptionalDestinationDirectory: {0}", OptionalDestinationDirectory);
            Log.LogDebugMessage("  I18nAssemblies: {0}", I18nAssemblies);
            Log.LogDebugMessage("  LinkMode: {0}", LinkMode);
            Log.LogDebugMessage("  LinkSkip: {0}", LinkSkip);
            Log.LogDebugTaskItems("  LinkDescriptions:", LinkDescriptions);
            Log.LogDebugTaskItems("  ResolvedAssemblies:", ResolvedAssemblies);
            Log.LogDebugMessage("  EnableProguard: {0}", EnableProguard);
            Log.LogDebugMessage("  ProguardConfiguration: {0}", ProguardConfiguration);
            Log.LogDebugMessage("  DumpDependencies: {0}", DumpDependencies);
            Log.LogDebugMessage("  LinkOnlyNewerThan: {0}", LinkOnlyNewerThan);

            var res = new DirectoryAssemblyResolver(Log.LogWarning, loadDebugSymbols: false);

            // Put every assembly we'll need in the resolver
            foreach (var assembly in ResolvedAssemblies)
            {
                res.Load(Path.GetFullPath(assembly.ItemSpec));
            }

            var resolver = new AssemblyResolver(res.ToResolverCache());

            // Set up for linking
            var options = new LinkerOptions();

            options.MainAssembly     = res.GetAssembly(MainAssembly);
            options.OutputDirectory  = Path.GetFullPath(OutputDirectory);
            options.LinkSdkOnly      = string.Compare(LinkMode, "SdkOnly", true) == 0;
            options.LinkNone         = string.Compare(LinkMode, "None", true) == 0;
            options.Resolver         = resolver;
            options.LinkDescriptions = LinkDescriptions.Select(item => Path.GetFullPath(item.ItemSpec)).ToArray();
            options.I18nAssemblies   = Linker.ParseI18nAssemblies(I18nAssemblies);
            if (!options.LinkSdkOnly)
            {
                options.RetainAssemblies = GetRetainAssemblies(res);
            }
            options.DumpDependencies = DumpDependencies;

            var skiplist = new List <string> ();

            if (string.Compare(UseSharedRuntime, "true", true) == 0)
            {
                skiplist.AddRange(Profile.SharedRuntimeAssemblies.Where(a => a.EndsWith(".dll")).Select(a => Path.GetFileNameWithoutExtension(a)));
            }
            if (!string.IsNullOrWhiteSpace(LinkOnlyNewerThan) && File.Exists(LinkOnlyNewerThan))
            {
                var newerThan   = File.GetLastWriteTime(LinkOnlyNewerThan);
                var skipOldOnes = ResolvedAssemblies.Where(a => File.GetLastWriteTime(a.ItemSpec) < newerThan);
                foreach (var old in skipOldOnes)
                {
                    Log.LogMessage(MessageImportance.Low, "  Skip linking unchanged file: " + old.ItemSpec);
                }
                skiplist = skipOldOnes.Select(a => Path.GetFileNameWithoutExtension(a.ItemSpec)).Concat(skiplist).ToList();
            }

            // Add LinkSkip options
            if (!string.IsNullOrWhiteSpace(LinkSkip))
            {
                foreach (var assembly in LinkSkip.Split(',', ';'))
                {
                    skiplist.Add(assembly);
                }
            }

            options.SkippedAssemblies = skiplist;

            if (EnableProguard)
            {
                options.ProguardConfiguration = ProguardConfiguration;
            }

            // Link!
            try {
                LinkContext link_context;
                Linker.Process(options, out link_context);

                var copydst = OptionalDestinationDirectory ?? OutputDirectory;

                foreach (var assembly in ResolvedAssemblies)
                {
                    var copysrc  = assembly.ItemSpec;
                    var filename = Path.GetFileName(assembly.ItemSpec);

                    if (options.LinkNone)
                    {
                        if (skiplist.Any(s => Path.GetFileNameWithoutExtension(filename) == s))
                        {
                            // For skipped assemblies, skip if there is existing file in the destination.
                            // We cannot just copy the linker output from *current* run output, because
                            // it always renew the assemblies, in *different* binary values, whereas
                            // the dll in the OptionalDestinationDirectory must retain old and unchanged.
                            if (File.Exists(Path.Combine(copydst, filename)))
                            {
                                continue;
                            }
                            copysrc = assembly.ItemSpec;
                        }
                        else
                        {
                            // Prefer fixup assemblies if exists, otherwise just copy the original.
                            copysrc = Path.Combine(OutputDirectory, filename);
                            copysrc = File.Exists(copysrc) ? copysrc : assembly.ItemSpec;
                        }
                    }
                    else if (!MonoAndroidHelper.IsForceRetainedAssembly(filename))
                    {
                        continue;
                    }

                    MonoAndroidHelper.CopyIfChanged(copysrc, Path.Combine(copydst, filename));
                    try {
                        MonoAndroidHelper.CopyIfChanged(assembly.ItemSpec + ".mdb", Path.Combine(copydst, filename + ".mdb"));
                    } catch (Exception) {                     // skip it, mdb sometimes fails to read and it's optional
                    }
                }
            } catch (ResolutionException ex) {
                Diagnostic.Error(2006, ex, "Reference to metadata item '{0}' (defined in '{1}') from '{1}' could not be resolved.", ex.Member, ex.Member.Module.Assembly, ex.Scope);
            }

            return(true);
        }
Example #6
0
        bool Execute(DirectoryAssemblyResolver res)
        {
            // Put every assembly we'll need in the resolver
            foreach (var assembly in ResolvedAssemblies)
            {
                res.Load(Path.GetFullPath(assembly.ItemSpec));
            }

            var resolver = new AssemblyResolver(res.ToResolverCache());

            // Set up for linking
            var options = new LinkerOptions();

            options.MainAssembly     = res.GetAssembly(MainAssembly);
            options.OutputDirectory  = Path.GetFullPath(OutputDirectory);
            options.LinkSdkOnly      = string.Compare(LinkMode, "SdkOnly", true) == 0;
            options.LinkNone         = false;
            options.Resolver         = resolver;
            options.LinkDescriptions = LinkDescriptions.Select(item => Path.GetFullPath(item.ItemSpec)).ToArray();
            options.I18nAssemblies   = Linker.ParseI18nAssemblies(I18nAssemblies);
            if (!options.LinkSdkOnly)
            {
                options.RetainAssemblies = GetRetainAssemblies(res);
            }
            options.DumpDependencies          = DumpDependencies;
            options.HttpClientHandlerType     = HttpClientHandlerType;
            options.TlsProvider               = TlsProvider;
            options.PreserveJniMarshalMethods = PreserveJniMarshalMethods;
            options.DeterministicOutput       = Deterministic;

            var skiplist = new List <string> ();

            if (string.Compare(UseSharedRuntime, "true", true) == 0)
            {
                skiplist.AddRange(Profile.SharedRuntimeAssemblies.Where(a => a.EndsWith(".dll")).Select(a => Path.GetFileNameWithoutExtension(a)));
            }

            // Add LinkSkip options
            if (!string.IsNullOrWhiteSpace(LinkSkip))
            {
                skiplist.AddRange(LinkSkip.Split(',', ';'));
            }

            options.SkippedAssemblies = skiplist;

            if (EnableProguard)
            {
                options.ProguardConfiguration = ProguardConfiguration;
            }

            // Link!
            try {
                LinkContext link_context;
                Linker.Process(options, this, out link_context);

                foreach (var assembly in ResolvedAssemblies)
                {
                    var copysrc             = assembly.ItemSpec;
                    var filename            = Path.GetFileName(assembly.ItemSpec);
                    var assemblyDestination = Path.Combine(OutputDirectory, filename);

                    if (!MonoAndroidHelper.IsForceRetainedAssembly(filename))
                    {
                        continue;
                    }

                    MonoAndroidHelper.CopyAssemblyAndSymbols(copysrc, assemblyDestination);
                }
            } catch (ResolutionException ex) {
                Diagnostic.Error(2006, ex, "Could not resolve reference to '{0}' (defined in assembly '{1}') with scope '{2}'. When the scope is different from the defining assembly, it usually means that the type is forwarded.", ex.Member, ex.Member.Module.Assembly, ex.Scope);
            }

            return(true);
        }
        protected override string GenerateCommandLineCommands()
        {
            ProcessArguments arguments = null;

            if (!InvokeLinkerUsingMono)
            {
                arguments = ProcessArguments.Create("--verbose");
            }
            else
            {
                var toolsPath = GetPathToMonoLinker();
                Log.LogMessage(MessageImportance.High, $"Running monolinker from {toolsPath}.");
                arguments = ProcessArguments.Create(toolsPath);
                arguments = arguments.Add("--verbose");
            }

            arguments = arguments.AddRange("--deterministic");

            // add exclude features
            arguments = arguments.AddRange("--exclude-feature", "remoting", "--exclude-feature", "com", "--exclude-feature", "etw");

            string coremode, usermode;

            switch ((WasmLinkMode)Enum.Parse(typeof(WasmLinkMode), LinkMode))
            {
            case WasmLinkMode.SdkOnly:
                coremode = "link";
                usermode = "copy";
                break;

            case WasmLinkMode.Full:
                coremode = "link";
                usermode = "link";
                break;

            default:
                coremode = "copyused";
                usermode = "copy";
                break;
            }

            arguments = arguments.AddRange("-c", coremode, "-u", usermode);

            //the linker doesn't consider these core by default
            foreach (var bn in bindingNames)
            {
                arguments = arguments.AddRange("-p", coremode, bn);
            }

            if (!string.IsNullOrEmpty(LinkSkip))
            {
                var skips = LinkSkip.Split(new[] { ';', ',', ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var s in skips)
                {
                    arguments = arguments.AddRange("-p", "copy", s);
                }
            }

            arguments = arguments.AddRange("-out", OutputDir);

            arguments = arguments.AddRange("-d", FrameworkDir);

            arguments = arguments.AddRange("-d", Path.Combine(FrameworkDir, "Facades"));

            arguments = arguments.AddRange("-b", Debug.ToString());
            arguments = arguments.AddRange("-v", Debug.ToString());

            // add custom link descriptions
            // to ensure the type, methods and/or fields are not eliminated from your application.
            if (LinkDescriptions != null)
            {
                foreach (var desc in LinkDescriptions)
                {
                    var l = desc.GetMetadata("FullPath");
                    arguments = arguments.AddRange("-x", l);
                }
            }

            arguments = arguments.AddRange("-a", RootAssembly[0].GetMetadata("FullPath"));

            //we'll normally have to check most of the files because the SDK references most framework asm by default
            //so let's enumerate upfront
            var frameworkAssemblies = new HashSet <string> (StringComparer.OrdinalIgnoreCase);

            foreach (var f in Directory.EnumerateFiles(FrameworkDir))
            {
                frameworkAssemblies.Add(Path.GetFileNameWithoutExtension(f));
            }
            foreach (var f in Directory.EnumerateFiles(Path.Combine(FrameworkDir, "Facades")))
            {
                frameworkAssemblies.Add(Path.GetFileNameWithoutExtension(f));
            }

            // Load the runtime assemblies to be replaced in the references below
            var runtimeCopyLocal = new Dictionary <string, string> (StringComparer.OrdinalIgnoreCase);

            if (RuntimeCopyLocalAssemblies != null)
            {
                foreach (var copyAsm in RuntimeCopyLocalAssemblies)
                {
                    var p = copyAsm.GetMetadata("FullPath");

                    if (frameworkAssemblies.Contains(Path.GetFileNameWithoutExtension(p)))
                    {
                        continue;
                    }
                    runtimeCopyLocal.Add(Path.GetFileNameWithoutExtension(p), p);
                }
            }

            //add references for non-framework assemblies
            if (Assemblies != null)
            {
                foreach (var asm in Assemblies)
                {
                    var p = asm.GetMetadata("FullPath");

                    if (frameworkAssemblies.Contains(Path.GetFileNameWithoutExtension(p)))
                    {
                        continue;
                    }

                    if (runtimeCopyLocal.TryGetValue(Path.GetFileNameWithoutExtension(p), out var runtimePath))
                    {
                        if (!string.IsNullOrEmpty(BindingsDir) && bindingNames.Contains(Path.GetFileNameWithoutExtension(p)))
                        {
                            runtimePath = Path.Combine(BindingsDir, Path.GetFileName(p));
                        }
                        // Just in case
                        if (File.Exists(runtimePath))
                        {
                            p = runtimePath;
                        }
                    }
                    arguments = arguments.AddRange("-r", p);
                }
            }

            if (string.IsNullOrEmpty(I18n))
            {
                arguments = arguments.AddRange("-l", "none");
            }
            else
            {
                var vals = I18n.Split(new[] { ',', ';', ' ', '\r', '\n', '\t' });
                arguments = arguments.AddRange("-l", string.Join(",", vals));
            }
            return(arguments.ToString());
        }