// Checks if any of the source files have a time stamp later than any of the target files.
        public static bool IsUptodate(IEnumerable <string> sources, IEnumerable <string> targets)
        {
            if (Driver.Force)
            {
                return(false);
            }

            DateTime max_source = DateTime.MinValue;
            string   max_s      = null;

            if (sources.Count() == 0 || targets.Count() == 0)
            {
                ErrorHelper.Error(1013, "Dependency tracking error: no files to compare. Please file a bug report at http://bugzilla.xamarin.com with a test case.");
            }

            foreach (var s in sources)
            {
                var sfi = new FileInfo(s);
                if (!sfi.Exists)
                {
                    Driver.Log(3, "Prerequisite '{0}' does not exist.", s);
                    return(false);
                }

                var st = sfi.LastWriteTimeUtc;
                if (st > max_source)
                {
                    max_source = st;
                    max_s      = s;
                }
            }


            foreach (var t in targets)
            {
                var tfi = new FileInfo(t);
                if (!tfi.Exists)
                {
                    Driver.Log(3, "Target '{0}' does not exist.", t);
                    return(false);
                }

                var lwt = tfi.LastWriteTimeUtc;
                if (max_source > lwt)
                {
                    Driver.Log(3, "Prerequisite '{0}' is newer than target '{1}' ({2} vs {3}).", max_s, t, max_source, lwt);
                    return(false);
                }
            }

            Driver.Log(3, "Prerequisite(s) '{0}' are all older than the target(s) '{1}'.", string.Join("', '", sources.ToArray()), string.Join("', '", targets.ToArray()));

            return(true);
        }
Exemple #2
0
        public void NativeLink()
        {
            if (!string.IsNullOrEmpty(App.UserGccFlags))
            {
                App.DeadStrip = false;
            }
            if (App.EnableLLVMOnlyBitCode)
            {
                App.DeadStrip = false;
            }

            var compiler_flags = new CompilerFlags()
            {
                Target = this
            };

            // Get global frameworks
            compiler_flags.AddFrameworks(App.Frameworks, App.WeakFrameworks);
            compiler_flags.AddFrameworks(Frameworks, WeakFrameworks);

            // Collect all LinkWith flags and frameworks from all assemblies.
            foreach (var a in Assemblies)
            {
                compiler_flags.AddFrameworks(a.Frameworks, a.WeakFrameworks);
                if (!App.FastDev || App.IsSimulatorBuild)
                {
                    compiler_flags.AddLinkWith(a.LinkWith, a.ForceLoad);
                }
                compiler_flags.AddOtherFlags(a.LinkerFlags);
            }

            var bitcode = App.EnableBitCode;

            if (bitcode)
            {
                compiler_flags.AddOtherFlag(App.EnableMarkerOnlyBitCode ? "-fembed-bitcode-marker" : "-fembed-bitcode");
            }

            if (App.EnablePie.HasValue && App.EnablePie.Value && (App.DeploymentTarget < new Version(4, 2)))
            {
                ErrorHelper.Error(28, "Cannot enable PIE (-pie) when targeting iOS 4.1 or earlier. Please disable PIE (-pie:false) or set the deployment target to at least iOS 4.2");
            }

            if (!App.EnablePie.HasValue)
            {
                App.EnablePie = true;
            }

            if (App.Platform == ApplePlatform.iOS)
            {
                if (App.EnablePie.Value && (App.DeploymentTarget >= new Version(4, 2)))
                {
                    compiler_flags.AddOtherFlag("-Wl,-pie");
                }
                else
                {
                    compiler_flags.AddOtherFlag("-Wl,-no_pie");
                }
            }

            CompileTask.GetArchFlags(compiler_flags, Abis);
            if (App.IsDeviceBuild)
            {
                compiler_flags.AddOtherFlag($"-m{Driver.GetTargetMinSdkName (App)}-version-min={App.DeploymentTarget}");
                compiler_flags.AddOtherFlag($"-isysroot {Driver.Quote (Driver.GetFrameworkDirectory (App))}");
            }
            else
            {
                CompileTask.GetSimulatorCompilerFlags(compiler_flags, null, App);
            }
            compiler_flags.LinkWithMono();
            compiler_flags.LinkWithXamarin();

            compiler_flags.AddLinkWith(link_with);
            compiler_flags.AddOtherFlag($"-o {Driver.Quote (Executable)}");

            compiler_flags.AddOtherFlag("-lz");
            compiler_flags.AddOtherFlag("-liconv");

            bool need_libcpp = false;

            if (App.EnableBitCode)
            {
                need_libcpp = true;
            }
#if ENABLE_BITCODE_ON_IOS
            need_libcpp = true;
#endif
            if (need_libcpp)
            {
                compiler_flags.AddOtherFlag("-lc++");
            }

            // allow the native linker to remove unused symbols (if the caller was removed by the managed linker)
            if (!bitcode)
            {
                // Note that we include *all* (__Internal) p/invoked symbols here
                // We also include any fields from [Field] attributes.
                compiler_flags.ReferenceSymbols(GetRequiredSymbols());
            }

            string mainlib;
            if (App.IsWatchExtension)
            {
                mainlib = "libwatchextension.a";
                compiler_flags.AddOtherFlag(" -e _xamarin_watchextension_main");
            }
            else if (App.IsTVExtension)
            {
                mainlib = "libtvextension.a";
            }
            else if (App.IsExtension)
            {
                mainlib = "libextension.a";
            }
            else
            {
                mainlib = "libapp.a";
            }
            var libdir  = Path.Combine(Driver.GetProductSdkDirectory(App), "usr", "lib");
            var libmain = Path.Combine(libdir, mainlib);
            compiler_flags.AddLinkWith(libmain, true);

            if (App.EnableProfiling)
            {
                string libprofiler;
                if (App.FastDev)
                {
                    libprofiler = Path.Combine(libdir, "libmono-profiler-log.dylib");
                    compiler_flags.AddLinkWith(libprofiler);
                }
                else
                {
                    libprofiler = Path.Combine(libdir, "libmono-profiler-log.a");
                    compiler_flags.AddLinkWith(libprofiler);
                    if (!App.EnableBitCode)
                    {
                        compiler_flags.ReferenceSymbol("mono_profiler_startup_log");
                    }
                }
            }

            if (!string.IsNullOrEmpty(App.UserGccFlags))
            {
                compiler_flags.AddOtherFlag(App.UserGccFlags);
            }

            if (App.DeadStrip)
            {
                compiler_flags.AddOtherFlag("-dead_strip");
            }

            if (App.IsExtension)
            {
                if (App.Platform == ApplePlatform.iOS && Driver.XcodeVersion.Major < 7)
                {
                    compiler_flags.AddOtherFlag("-lpkstart");
                    compiler_flags.AddOtherFlag($"-F {Driver.Quote (Path.Combine (Driver.GetFrameworkDirectory (App), "System/Library/PrivateFrameworks"))} -framework PlugInKit");
                }
                compiler_flags.AddOtherFlag("-fapplication-extension");
            }

            compiler_flags.Inputs = new List <string> ();
            var flags = compiler_flags.ToString();              // This will populate Inputs.

            if (!Application.IsUptodate(compiler_flags.Inputs, new string [] { Executable }))
            {
                // always show the native linker warnings since many of them turn out to be very important
                // and very hard to diagnose otherwise when hidden from the build output. Ref: bug #2430
                var linker_errors = new List <Exception> ();
                var output        = new StringBuilder();
                var code          = Driver.RunCommand(App.CompilerPath, flags, null, output);

                Application.ProcessNativeLinkerOutput(this, output.ToString(), link_with, linker_errors, code != 0);

                if (code != 0)
                {
                    // if the build failed - it could be because of missing frameworks / libraries we identified earlier
                    foreach (var assembly in Assemblies)
                    {
                        if (assembly.UnresolvedModuleReferences == null)
                        {
                            continue;
                        }

                        foreach (var mr in assembly.UnresolvedModuleReferences)
                        {
                            // TODO: add more diagnose information on the warnings
                            var name = Path.GetFileNameWithoutExtension(mr.Name);
                            linker_errors.Add(new MonoTouchException(5215, false, "References to '{0}' might require additional -framework=XXX or -lXXX instructions to the native linker", name));
                        }
                    }
                    // mtouch does not validate extra parameters given to GCC when linking (--gcc_flags)
                    if (!String.IsNullOrEmpty(App.UserGccFlags))
                    {
                        linker_errors.Add(new MonoTouchException(5201, true, "Native linking failed. Please review the build log and the user flags provided to gcc: {0}", App.UserGccFlags));
                    }
                    linker_errors.Add(new MonoTouchException(5202, true, "Native linking failed. Please review the build log.", App.UserGccFlags));
                }
                ErrorHelper.Show(linker_errors);
            }
            else
            {
                cached_executable = true;
                Driver.Log(3, "Target '{0}' is up-to-date.", Executable);
            }
            // the native linker can prefer private (and existing) over public (but non-existing) framework when weak_framework are used
            // on an iOS target version where the framework does not exists, e.g. targeting iOS6 for JavaScriptCore added in iOS7 results in
            // /System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore instead of
            // /System/Library/Frameworks/JavaScriptCore.framework/JavaScriptCore
            // more details in https://bugzilla.xamarin.com/show_bug.cgi?id=31036
            if (WeakFrameworks.Count > 0)
            {
                AdjustDylibs();
            }
            Driver.Watch("Native Link", 1);
        }
Exemple #3
0
        // Checks if any of the source files have a time stamp later than any of the target files.
        //
        // If check_stamp is true, the function will use the timestamp of a "target".stamp file
        // if it's later than the timestamp of the "target" file itself.
        public static bool IsUptodate(IEnumerable <string> sources, IEnumerable <string> targets, bool check_stamp = true)
        {
            if (Driver.Force)
            {
                return(false);
            }

            DateTime max_source = DateTime.MinValue;
            string   max_s      = null;

            if (sources.Count() == 0 || targets.Count() == 0)
            {
                ErrorHelper.Error(1013, "Dependency tracking error: no files to compare. Please file a bug report at https://github.com/xamarin/xamarin-macios/issues/new with a test case.");
            }

            foreach (var s in sources)
            {
                var sfi = new FileInfo(s);
                if (!sfi.Exists)
                {
                    Driver.Log(3, "Prerequisite '{0}' does not exist.", s);
                    return(false);
                }

                var st = sfi.LastWriteTimeUtc;
                if (st > max_source)
                {
                    max_source = st;
                    max_s      = s;
                }
            }


            foreach (var t in targets)
            {
                var tfi = new FileInfo(t);
                if (!tfi.Exists)
                {
                    Driver.Log(3, "Target '{0}' does not exist.", t);
                    return(false);
                }

                if (check_stamp)
                {
                    var tfi_stamp = new FileInfo(t + ".stamp");
                    if (tfi_stamp.Exists && tfi_stamp.LastWriteTimeUtc > tfi.LastWriteTimeUtc)
                    {
                        Driver.Log(3, "Target '{0}' has a stamp file with newer timestamp ({1} > {2}), using the stamp file's timestamp", t, tfi_stamp.LastWriteTimeUtc, tfi.LastWriteTimeUtc);
                        tfi = tfi_stamp;
                    }
                }

                var lwt = tfi.LastWriteTimeUtc;
                if (max_source > lwt)
                {
                    Driver.Log(3, "Prerequisite '{0}' is newer than target '{1}' ({2} vs {3}).", max_s, t, max_source, lwt);
                    return(false);
                }
            }

            Driver.Log(3, "Prerequisite(s) '{0}' are all older than the target(s) '{1}'.", string.Join("', '", sources.ToArray()), string.Join("', '", targets.ToArray()));

            return(true);
        }
Exemple #4
0
        static void AddSharedOptions(Application app, Mono.Options.OptionSet options)
        {
            options.Add("warnaserror:", "An optional comma-separated list of warning codes that should be reported as errors (if no warnings are specified all warnings are reported as errors).", v =>
            {
                try {
                    if (!string.IsNullOrEmpty(v))
                    {
                        foreach (var code in v.Split(new char [] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                        {
                            ErrorHelper.SetWarningLevel(ErrorHelper.WarningLevel.Error, int.Parse(code));
                        }
                    }
                    else
                    {
                        ErrorHelper.SetWarningLevel(ErrorHelper.WarningLevel.Error);
                    }
                } catch (Exception ex) {
                    ErrorHelper.Error(26, ex, "Could not parse the command line argument '{0}': {1}", "--warnaserror", ex.Message);
                }
            });
            options.Add("nowarn:", "An optional comma-separated list of warning codes to ignore (if no warnings are specified all warnings are ignored).", v =>
            {
                try {
                    if (!string.IsNullOrEmpty(v))
                    {
                        foreach (var code in v.Split(new char [] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                        {
                            ErrorHelper.SetWarningLevel(ErrorHelper.WarningLevel.Disable, int.Parse(code));
                        }
                    }
                    else
                    {
                        ErrorHelper.SetWarningLevel(ErrorHelper.WarningLevel.Disable);
                    }
                } catch (Exception ex) {
                    ErrorHelper.Error(26, ex, "Could not parse the command line argument '{0}': {1}", "--nowarn", ex.Message);
                }
            });
            options.Add("coop:", "If the GC should run in cooperative mode.", v => { app.EnableCoopGC = ParseBool(v, "coop"); }, hidden: true);
            options.Add("sgen-conc", "Enable the *experimental* concurrent garbage collector.", v => { app.EnableSGenConc = true; });
            options.Add("marshal-objectivec-exceptions:", "Specify how Objective-C exceptions should be marshalled. Valid values: default, unwindmanagedcode, throwmanagedexception, abort and disable. The default depends on the target platform (on watchOS the default is 'throwmanagedexception', while on all other platforms it's 'disable').", v => {
                switch (v)
                {
                case "default":
                    app.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.Default;
                    break;

                case "unwindmanaged":
                case "unwindmanagedcode":
                    app.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.UnwindManagedCode;
                    break;

                case "throwmanaged":
                case "throwmanagedexception":
                    app.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.ThrowManagedException;
                    break;

                case "abort":
                    app.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.Abort;
                    break;

                case "disable":
                    app.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.Disable;
                    break;

                default:
                    throw ErrorHelper.CreateError(26, "Could not parse the command line argument '{0}': {1}", "--marshal-objective-exceptions", $"Invalid value: {v}. Valid values are: default, unwindmanagedcode, throwmanagedexception, abort and disable.");
                }
            });
            options.Add("marshal-managed-exceptions:", "Specify how managed exceptions should be marshalled. Valid values: default, unwindnativecode, throwobjectivecexception, abort and disable. The default depends on the target platform (on watchOS the default is 'throwobjectivecexception', while on all other platform it's 'disable').", v => {
                switch (v)
                {
                case "default":
                    app.MarshalManagedExceptions = MarshalManagedExceptionMode.Default;
                    break;

                case "unwindnative":
                case "unwindnativecode":
                    app.MarshalManagedExceptions = MarshalManagedExceptionMode.UnwindNativeCode;
                    break;

                case "throwobjectivec":
                case "throwobjectivecexception":
                    app.MarshalManagedExceptions = MarshalManagedExceptionMode.ThrowObjectiveCException;
                    break;

                case "abort":
                    app.MarshalManagedExceptions = MarshalManagedExceptionMode.Abort;
                    break;

                case "disable":
                    app.MarshalManagedExceptions = MarshalManagedExceptionMode.Disable;
                    break;

                default:
                    throw ErrorHelper.CreateError(26, "Could not parse the command line argument '{0}': {1}", "--marshal-managed-exceptions", $"Invalid value: {v}. Valid values are: default, unwindnativecode, throwobjectivecexception, abort and disable.");
                }
            });
            options.Add("j|jobs=", "The level of concurrency. Default is the number of processors.", v => {
                Jobs = int.Parse(v);
            });
            options.Add("embeddinator", "Enables Embeddinator targetting mode.", v => {
                app.Embeddinator = true;
            }, true);
            options.Add("dynamic-symbol-mode:", "Specify how dynamic symbols are treated so that they're not linked away by the native linker. Valid values: linker (pass \"-u symbol\" to the native linker), code (generate native code that uses the dynamic symbol), ignore (do nothing and hope for the best). The default is 'code' when using bitcode, and 'linker' otherwise.", (v) => {
                switch (v.ToLowerInvariant())
                {
                case "default":
                    app.SymbolMode = SymbolMode.Default;
                    break;

                case "linker":
                    app.SymbolMode = SymbolMode.Linker;
                    break;

                case "code":
                    app.SymbolMode = SymbolMode.Code;
                    break;

                case "ignore":
                    app.SymbolMode = SymbolMode.Ignore;
                    break;

                default:
                    throw ErrorHelper.CreateError(26, "Could not parse the command line argument '{0}': {1}", "--dynamic-symbol-mode", $"Invalid value: {v}. Valid values are: default, linker, code and ignore.");
                }
            });
            options.Add("ignore-dynamic-symbol:", "Specify that Xamarin.iOS/Xamarin.Mac should not try to prevent the linker from removing the specified symbol.", (v) => {
                app.IgnoredSymbols.Add(v);
            });
        }
        static void AddSharedOptions(Application app, Mono.Options.OptionSet options)
        {
            options.Add("warnaserror:", "An optional comma-separated list of warning codes that should be reported as errors (if no warnings are specified all warnings are reported as errors).", v =>
            {
                try {
                    if (!string.IsNullOrEmpty(v))
                    {
                        foreach (var code in v.Split(new char [] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                        {
                            ErrorHelper.SetWarningLevel(ErrorHelper.WarningLevel.Error, int.Parse(code));
                        }
                    }
                    else
                    {
                        ErrorHelper.SetWarningLevel(ErrorHelper.WarningLevel.Error);
                    }
                } catch (Exception ex) {
                    ErrorHelper.Error(26, ex, "Could not parse the command line argument '{0}': {1}", "--warnaserror", ex.Message);
                }
            });
            options.Add("nowarn:", "An optional comma-separated list of warning codes to ignore (if no warnings are specified all warnings are ignored).", v =>
            {
                try {
                    if (!string.IsNullOrEmpty(v))
                    {
                        foreach (var code in v.Split(new char [] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                        {
                            ErrorHelper.SetWarningLevel(ErrorHelper.WarningLevel.Disable, int.Parse(code));
                        }
                    }
                    else
                    {
                        ErrorHelper.SetWarningLevel(ErrorHelper.WarningLevel.Disable);
                    }
                } catch (Exception ex) {
                    ErrorHelper.Error(26, ex, "Could not parse the command line argument '{0}': {1}", "--nowarn", ex.Message);
                }
            });
            options.Add("coop:", "If the GC should run in cooperative mode.", v => { app.EnableCoopGC = ParseBool(v, "coop"); }, hidden: true);
            options.Add("sgen-conc", "Enable the *experimental* concurrent garbage collector.", v => { app.EnableSGenConc = true; });
            options.Add("marshal-objectivec-exceptions:", "Specify how Objective-C exceptions should be marshalled. Valid values: default, unwindmanagedcode, throwmanagedexception, abort and disable. The default depends on the target platform (on watchOS the default is 'throwmanagedexception', while on all other platforms it's 'disable').", v => {
                switch (v)
                {
                case "default":
                    app.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.Default;
                    break;

                case "unwindmanaged":
                case "unwindmanagedcode":
                    app.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.UnwindManagedCode;
                    break;

                case "throwmanaged":
                case "throwmanagedexception":
                    app.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.ThrowManagedException;
                    break;

                case "abort":
                    app.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.Abort;
                    break;

                case "disable":
                    app.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.Disable;
                    break;

                default:
                    throw ErrorHelper.CreateError(26, "Could not parse the command line argument '{0}': {1}", "--marshal-objective-exceptions", $"Invalid value: {v}. Valid values are: default, unwindmanagedcode, throwmanagedexception, abort and disable.");
                }
            });
            options.Add("marshal-managed-exceptions:", "Specify how managed exceptions should be marshalled. Valid values: default, unwindnativecode, throwobjectivecexception, abort and disable. The default depends on the target platform (on watchOS the default is 'throwobjectivecexception', while on all other platform it's 'disable').", v => {
                switch (v)
                {
                case "default":
                    app.MarshalManagedExceptions = MarshalManagedExceptionMode.Default;
                    break;

                case "unwindnative":
                case "unwindnativecode":
                    app.MarshalManagedExceptions = MarshalManagedExceptionMode.UnwindNativeCode;
                    break;

                case "throwobjectivec":
                case "throwobjectivecexception":
                    app.MarshalManagedExceptions = MarshalManagedExceptionMode.ThrowObjectiveCException;
                    break;

                case "abort":
                    app.MarshalManagedExceptions = MarshalManagedExceptionMode.Abort;
                    break;

                case "disable":
                    app.MarshalManagedExceptions = MarshalManagedExceptionMode.Disable;
                    break;

                default:
                    throw ErrorHelper.CreateError(26, "Could not parse the command line argument '{0}': {1}", "--marshal-managed-exceptions", $"Invalid value: {v}. Valid values are: default, unwindnativecode, throwobjectivecexception, abort and disable.");
                }
            });
            options.Add("j|jobs=", "The level of concurrency. Default is the number of processors.", v => {
                Jobs = int.Parse(v);
            });
        }
Exemple #6
0
        static void AddSharedOptions(Application app, Mono.Options.OptionSet options)
        {
            options.Add("sdkroot=", "Specify the location of Apple SDKs, default to 'xcode-select' value.", v => sdk_root = v);
            options.Add("no-xcode-version-check", "Ignores the Xcode version check.", v => { min_xcode_version = null; }, true /* This is a non-documented option. Please discuss any customers running into the xcode version check on the maciosdev@ list before giving this option out to customers. */);
            options.Add("warnaserror:", "An optional comma-separated list of warning codes that should be reported as errors (if no warnings are specified all warnings are reported as errors).", v =>
            {
                try {
                    if (!string.IsNullOrEmpty(v))
                    {
                        foreach (var code in v.Split(new char [] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                        {
                            ErrorHelper.SetWarningLevel(ErrorHelper.WarningLevel.Error, int.Parse(code));
                        }
                    }
                    else
                    {
                        ErrorHelper.SetWarningLevel(ErrorHelper.WarningLevel.Error);
                    }
                } catch (Exception ex) {
                    ErrorHelper.Error(26, ex, "Could not parse the command line argument '{0}': {1}", "--warnaserror", ex.Message);
                }
            });
            options.Add("nowarn:", "An optional comma-separated list of warning codes to ignore (if no warnings are specified all warnings are ignored).", v =>
            {
                try {
                    if (!string.IsNullOrEmpty(v))
                    {
                        foreach (var code in v.Split(new char [] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                        {
                            ErrorHelper.SetWarningLevel(ErrorHelper.WarningLevel.Disable, int.Parse(code));
                        }
                    }
                    else
                    {
                        ErrorHelper.SetWarningLevel(ErrorHelper.WarningLevel.Disable);
                    }
                } catch (Exception ex) {
                    ErrorHelper.Error(26, ex, "Could not parse the command line argument '{0}': {1}", "--nowarn", ex.Message);
                }
            });
            options.Add("coop:", "If the GC should run in cooperative mode.", v => { app.EnableCoopGC = ParseBool(v, "coop"); }, hidden: true);
            options.Add("sgen-conc", "Enable the *experimental* concurrent garbage collector.", v => { app.EnableSGenConc = true; });
            options.Add("marshal-objectivec-exceptions:", "Specify how Objective-C exceptions should be marshalled. Valid values: default, unwindmanagedcode, throwmanagedexception, abort and disable. The default depends on the target platform (on watchOS the default is 'throwmanagedexception', while on all other platforms it's 'disable').", v => {
                switch (v)
                {
                case "default":
                    app.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.Default;
                    break;

                case "unwindmanaged":
                case "unwindmanagedcode":
                    app.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.UnwindManagedCode;
                    break;

                case "throwmanaged":
                case "throwmanagedexception":
                    app.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.ThrowManagedException;
                    break;

                case "abort":
                    app.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.Abort;
                    break;

                case "disable":
                    app.MarshalObjectiveCExceptions = MarshalObjectiveCExceptionMode.Disable;
                    break;

                default:
                    throw ErrorHelper.CreateError(26, "Could not parse the command line argument '{0}': {1}", "--marshal-objective-exceptions", $"Invalid value: {v}. Valid values are: default, unwindmanagedcode, throwmanagedexception, abort and disable.");
                }
            });
            options.Add("marshal-managed-exceptions:", "Specify how managed exceptions should be marshalled. Valid values: default, unwindnativecode, throwobjectivecexception, abort and disable. The default depends on the target platform (on watchOS the default is 'throwobjectivecexception', while on all other platform it's 'disable').", v => {
                switch (v)
                {
                case "default":
                    app.MarshalManagedExceptions = MarshalManagedExceptionMode.Default;
                    break;

                case "unwindnative":
                case "unwindnativecode":
                    app.MarshalManagedExceptions = MarshalManagedExceptionMode.UnwindNativeCode;
                    break;

                case "throwobjectivec":
                case "throwobjectivecexception":
                    app.MarshalManagedExceptions = MarshalManagedExceptionMode.ThrowObjectiveCException;
                    break;

                case "abort":
                    app.MarshalManagedExceptions = MarshalManagedExceptionMode.Abort;
                    break;

                case "disable":
                    app.MarshalManagedExceptions = MarshalManagedExceptionMode.Disable;
                    break;

                default:
                    throw ErrorHelper.CreateError(26, "Could not parse the command line argument '{0}': {1}", "--marshal-managed-exceptions", $"Invalid value: {v}. Valid values are: default, unwindnativecode, throwobjectivecexception, abort and disable.");
                }
            });
            options.Add("j|jobs=", "The level of concurrency. Default is the number of processors.", v => {
                Jobs = int.Parse(v);
            });
            options.Add("embeddinator", "Enables Embeddinator targetting mode.", v => {
                app.Embeddinator = true;
            }, true);
            options.Add("dynamic-symbol-mode:", "Specify how dynamic symbols are treated so that they're not linked away by the native linker. Valid values: linker (pass \"-u symbol\" to the native linker), code (generate native code that uses the dynamic symbol), ignore (do nothing and hope for the best). The default is 'code' when using bitcode, and 'linker' otherwise.", (v) => {
                switch (v.ToLowerInvariant())
                {
                case "default":
                    app.SymbolMode = SymbolMode.Default;
                    break;

                case "linker":
                    app.SymbolMode = SymbolMode.Linker;
                    break;

                case "code":
                    app.SymbolMode = SymbolMode.Code;
                    break;

                case "ignore":
                    app.SymbolMode = SymbolMode.Ignore;
                    break;

                default:
                    throw ErrorHelper.CreateError(26, "Could not parse the command line argument '{0}': {1}", "--dynamic-symbol-mode", $"Invalid value: {v}. Valid values are: default, linker, code and ignore.");
                }
            });
            options.Add("ignore-dynamic-symbol:", "Specify that Xamarin.iOS/Xamarin.Mac should not try to prevent the linker from removing the specified symbol.", (v) => {
                app.IgnoredSymbols.Add(v);
            });
            options.Add("root-assembly=", "Specifies any root assemblies. There must be at least one root assembly, usually the main executable.", (v) => {
                app.RootAssemblies.Add(v);
            });
            options.Add("optimize=", "A comma-delimited list of optimizations to enable/disable. To enable an optimization, use --optimize=[+]remove-uithread-checks. To disable an optimizations: --optimize=-remove-uithread-checks. Use '+all' to enable or '-all' disable all optimizations. Only compiler-generated code or code otherwise marked as safe to optimize will be optimized.\n" +
                        "Available optimizations:\n" +
                        "    dead-code-elimination: By default always enabled (requires the linker). Removes IL instructions the linker can determine will never be executed. This is most useful in combination with the inline-* optimizations, since inlined conditions almost always also results in blocks of code that will never be executed.\n" +
                        "    remove-uithread-checks: By default enabled for release builds (requires the linker). Remove all UI Thread checks (makes the app smaller, and slightly faster at runtime).\n" +
#if MONOTOUCH
                        "    inline-isdirectbinding: By default enabled (requires the linker). Tries to inline calls to NSObject.IsDirectBinding to load a constant value. Makes the app smaller, and slightly faster at runtime.\n" +
#else
                        "    inline-isdirectbinding: By default disabled, because it may require the linker. Tries to inline calls to NSObject.IsDirectBinding to load a constant value. Makes the app smaller, and slightly faster at runtime.\n" +
#endif
#if MONOTOUCH
                        "    remove-dynamic-registrar: By default enabled when the static registrar is enabled. Removes the dynamic registrar (makes the app smaller).\n" +
                        "    inline-runtime-arch: By default always enabled (requires the linker). Inlines calls to ObjCRuntime.Runtime.Arch to load a constant value. Makes the app smaller, and slightly faster at runtime.\n" +
#endif
                        "    blockliteral-setupblock: By default enabled when using the static registrar. Optimizes calls to BlockLiteral.SetupBlock to avoid having to calculate the block signature at runtime.\n" +
                        "    inline-intptr-size: By default enabled for builds that target a single architecture (requires the linker). Inlines calls to IntPtr.Size to load a constant value. Makes the app smaller, and slightly faster at runtime.\n" +
                        "    inline-dynamic-registration-supported: By default always enabled (requires the linker). Optimizes calls to Runtime.DynamicRegistrationSupported to be a constant value. Makes the app smaller, and slightly faster at runtime.\n" +
                        "    register-protocols: Remove unneeded metadata for protocol support. Makes the app smaller and reduces memory requirements.\n" +
#if !MONOTOUCH
                        "    trim-architectures: Remove unneeded architectures from bundled native libraries. Makes the app smaller and is required for macOS App Store submissions.\n" +
#else
                        "    remove-unsupported-il-for-bitcode: Remove IL that is not supported when compiling to bitcode, and replace with a NotSupportedException.\n" +
#endif
                        "",
                        (v) => {
                app.Optimizations.Parse(v);
            });
            options.Add(new Mono.Options.ResponseFileSource());
        }