Exemplo n.º 1
0
 static void LogLinkWithAttribute(LinkWithAttribute linkWith)
 {
     Driver.Log(3, "    ForceLoad: {0}", linkWith.ForceLoad);
     Driver.Log(3, "    Frameworks: {0}", linkWith.Frameworks);
     Driver.Log(3, "    IsCxx: {0}", linkWith.IsCxx);
     Driver.Log(3, "    LinkerFlags: {0}", linkWith.LinkerFlags);
     Driver.Log(3, "    LinkTarget: {0}", linkWith.LinkTarget);
     Driver.Log(3, "    NeedsGccExceptionHandling: {0}", linkWith.NeedsGccExceptionHandling);
     Driver.Log(3, "    SmartLink: {0}", linkWith.SmartLink);
     Driver.Log(3, "    WeakFrameworks: {0}", linkWith.WeakFrameworks);
 }
Exemplo n.º 2
0
 public NativeReferenceMetadata(LinkWithAttribute attribute)
 {
     ForceLoad                 = attribute.ForceLoad;
     Frameworks                = attribute.Frameworks;
     WeakFrameworks            = attribute.WeakFrameworks;
     LibraryName               = attribute.LibraryName;
     LinkerFlags               = attribute.LinkerFlags;
     LinkTarget                = attribute.LinkTarget;
     NeedsGccExceptionHandling = attribute.NeedsGccExceptionHandling;
     IsCxx     = attribute.IsCxx;
     SmartLink = attribute.SmartLink;
     Dlsym     = attribute.Dlsym;
     Attribute = attribute;
 }
Exemplo n.º 3
0
        void ProcessLinkWithAttributes(AssemblyDefinition assembly)
        {
            //
            // Tasks:
            // * Remove LinkWith attribute: this is done in the linker.
            // * Remove embedded resources related to LinkWith attribute from assembly: this is done at a later stage,
            //   here we just compile a list of resources to remove.
            // * Extract embedded resources related to LinkWith attribute to a file
            // * Modify the linker flags used to build/link the dylib (if fastdev) or the main binary (if !fastdev)
            //

            for (int i = 0; i < assembly.CustomAttributes.Count; i++)
            {
                CustomAttribute attr = assembly.CustomAttributes [i];

                if (attr.Constructor == null)
                {
                    continue;
                }

                TypeReference type = attr.Constructor.DeclaringType;
                if (!type.IsPlatformType("ObjCRuntime", "LinkWithAttribute"))
                {
                    continue;
                }

                // Let the linker remove it the attribute from the assembly
                HasLinkWithAttributes = true;

                LinkWithAttribute       linkWith = GetLinkWithAttribute(attr);
                NativeReferenceMetadata metadata = new NativeReferenceMetadata(linkWith);

                // If we've already processed this native library, skip it
                if (LinkWith.Any(x => Path.GetFileName(x) == metadata.LibraryName) || Frameworks.Any(x => Path.GetFileName(x) == metadata.LibraryName))
                {
                    continue;
                }

                // Remove the resource from the assembly at a later stage.
                if (!string.IsNullOrEmpty(metadata.LibraryName))
                {
                    AddResourceToBeRemoved(metadata.LibraryName);
                }

                ProcessNativeReferenceOptions(metadata);

                if (!string.IsNullOrEmpty(linkWith.LibraryName))
                {
                    if (linkWith.LibraryName.EndsWith(".framework", StringComparison.OrdinalIgnoreCase))
                    {
                        AssertiOSVersionSupportsUserFrameworks(linkWith.LibraryName);

                        Frameworks.Add(ExtractFramework(assembly, metadata));
                    }
                    else
                    {
                        LinkWith.Add(ExtractNativeLibrary(assembly, metadata));
                    }
                }
            }
        }
Exemplo n.º 4
0
    static int Main2(string [] args)
    {
        bool          show_help = false;
        bool          zero_copy = false;
        bool          alpha = false;
        string        basedir = null;
        string        tmpdir = null;
        string        ns = null;
        string        outfile = null;
        bool          delete_temp = true, debug = false;
        bool          verbose          = false;
        bool          unsafef          = true;
        bool          external         = false;
        bool          pmode            = true;
        bool          nostdlib         = false;
        bool          clean_mono_path  = false;
        bool          inline_selectors = false;
        List <string> sources;
        var           resources = new List <string> ();

#if !MONOMAC
        var linkwith = new List <string> ();
#endif
        var    references          = new List <string> ();
        var    libs                = new List <string> ();
        var    core_sources        = new List <string> ();
        var    extra_sources       = new List <string> ();
        var    defines             = new List <string> ();
        bool   binding_third_party = true;
        string generate_file_list  = null;

        var os = new OptionSet()
        {
            { "h|?|help", "Displays the help", v => show_help = true },
            { "a", "Include alpha bindings", v => alpha = true },
            { "outdir=", "Sets the output directory for the temporary binding files", v => { basedir = v; } },
            { "o|out=", "Sets the name of the output library", v => outfile = v },
            { "tmpdir=", "Sets the working directory for temp files", v => { tmpdir = v; delete_temp = false; } },
            { "debug", "Generates a debugging build of the binding", v => debug = true },
            { "sourceonly=", "Only generates the source", v => generate_file_list = v },
            { "ns=", "Sets the namespace for storing helper classes", v => ns = v },
            { "unsafe", "Sets the unsafe flag for the build", v => unsafef = true },
#if MONOMAC
            { "core", "Use this to build monomac.dll", v => binding_third_party = false },
#else
            { "core", "Use this to build monotouch.dll", v => binding_third_party = false },
#endif
            { "r=", "Adds a reference", v => references.Add(v) },
            { "lib=", "Adds the directory to the search path for the compiler", v => libs.Add(v) },
            { "compiler=", "Sets the compiler to use", v => compiler = v },
            { "d=", "Defines a symbol", v => defines.Add(v) },
            { "s=", "Adds a source file required to build the API", v => core_sources.Add(v) },
            { "v", "Sets verbose mode", v => verbose = true },
            { "x=", "Adds the specified file to the build, used after the core files are compiled", v => extra_sources.Add(v) },
            { "e", "Generates smaller classes that can not be subclassed (previously called 'external mode')", v => external = true },
            { "p", "Sets private mode", v => pmode = false },
            { "baselib=", "Sets the base library", v => baselibdll = v },
            { "use-zero-copy", v => zero_copy = true },
            { "nostdlib", "Does not reference mscorlib.dll library", l => nostdlib = true },
            { "no-mono-path", "Launches compiler with empty MONO_PATH", l => clean_mono_path = true },
            { "inline-selectors:", "If Selector.GetHandle is inlined and does not need to be cached (default: false)", v => inline_selectors = string.Equals("true", v, StringComparison.OrdinalIgnoreCase) || string.IsNullOrEmpty(v) },
#if !MONOMAC
            { "link-with=,", "Link with a native library {0:FILE} to the binding, embedded as a resource named {1:ID}",
              (path, id) => {
                  if (path == null || path.Length == 0)
                  {
                      throw new Exception("-link-with=FILE,ID requires a filename.");
                  }

                  if (id == null || id.Length == 0)
                  {
                      id = Path.GetFileName(path);
                  }

                  if (linkwith.Contains(id))
                  {
                      throw new Exception("-link-with=FILE,ID cannot assign the same resource id to multiple libraries.");
                  }

                  resources.Add(string.Format("-res:{0},{1}", path, id));
                  linkwith.Add(id);
              } },
#endif
        };

        try {
            sources = os.Parse(args);
        } catch (Exception e) {
            Console.Error.WriteLine("{0}: {1}", tool_name, e.Message);
            Console.Error.WriteLine("see {0} --help for more information", tool_name);
            return(1);
        }

        if (show_help || sources.Count == 0)
        {
            Console.WriteLine("Error: no api file provided");
            ShowHelp(os);
            return(0);
        }

        if (alpha)
        {
            defines.Add("ALPHA");
        }

        if (tmpdir == null)
        {
            tmpdir = GetWorkDir();
        }

        if (outfile == null)
        {
            outfile = Path.GetFileNameWithoutExtension(sources [0]) + ".dll";
        }

        string refs  = (references.Count > 0 ? "-r:" + String.Join(" -r:", references.ToArray()) : "");
        string paths = (libs.Count > 0 ? "-lib:" + String.Join(" -lib:", libs.ToArray()) : "");

        try {
            var api_file = sources [0];
            var tmpass   = Path.Combine(tmpdir, "temp.dll");

            // -nowarn:436 is to avoid conflicts in definitions between core.dll and the sources
            var cargs = String.Format("-unsafe -target:library {0} -nowarn:436 -out:{1} -r:{2} {3} {4} {5} -r:{6} {7} {8} {9}",
                                      string.Join(" ", sources.ToArray()),
                                      tmpass, Environment.GetCommandLineArgs()[0],
                                      string.Join(" ", core_sources.ToArray()), refs, unsafef ? "-unsafe" : "",
                                      baselibdll, string.Join(" ", defines.Select(x => "-define:" + x).ToArray()), paths,
                                      nostdlib ? "-nostdlib" : null);

            var si = new ProcessStartInfo(compiler, cargs)
            {
                UseShellExecute = false,
            };

            if (clean_mono_path)
            {
                // HACK: We are calling btouch with forced 2.1 path but we need working mono for compiler
                si.EnvironmentVariables.Remove("MONO_PATH");
            }

            if (verbose)
            {
                Console.WriteLine("{0} {1}", si.FileName, si.Arguments);
            }

            var p = Process.Start(si);
            p.WaitForExit();
            if (p.ExitCode != 0)
            {
                Console.WriteLine("{0}: API binding contains errors.", tool_name);
                return(1);
            }

            Assembly api;
            try {
                api = Assembly.LoadFrom(tmpass);
            } catch (Exception e) {
                if (verbose)
                {
                    Console.WriteLine(e);
                }

                Console.Error.WriteLine("Error loading API definition from {0}", tmpass);
                return(1);
            }

            Assembly baselib;
            try {
                baselib = Assembly.LoadFrom(baselibdll);
            } catch (Exception e) {
                if (verbose)
                {
                    Console.WriteLine(e);
                }

                Console.Error.WriteLine("Error loading base library {0}", baselibdll);
                return(1);
            }

#if !MONOMAC
            foreach (object attr in api.GetCustomAttributes(typeof(LinkWithAttribute), true))
            {
                LinkWithAttribute linkWith = (LinkWithAttribute)attr;

                if (!linkwith.Contains(linkWith.LibraryName))
                {
                    Console.Error.WriteLine("Missing native library {0}, please use `--link-with' to specify the path to this library.", linkWith.LibraryName);
                    return(1);
                }
            }
#endif

            var types = new List <Type> ();
            foreach (var t in api.GetTypes())
            {
                if (t.GetCustomAttributes(typeof(BaseTypeAttribute), true).Length > 0 ||
                    t.GetCustomAttributes(typeof(StaticAttribute), true).Length > 0)
                {
                    types.Add(t);
                }
            }

            var g = new Generator(pmode, external, debug, types.ToArray())
            {
                MessagingNS = ns == null?Path.GetFileNameWithoutExtension(api_file) : ns,
                                  CoreMessagingNS       = RootNS + ".ObjCRuntime",
                                  BindThirdPartyLibrary = binding_third_party,
                                  CoreNSObject          = CoreObject,
                                  BaseDir         = basedir != null ? basedir : tmpdir,
                                  ZeroCopyStrings = zero_copy,
#if MONOMAC
                                  OnlyX86 = true,
#endif
                                  Alpha           = alpha,
                                  InlineSelectors = inline_selectors,
            };

            foreach (var mi in baselib.GetType(RootNS + ".ObjCRuntime.Messaging").GetMethods())
            {
                if (mi.Name.IndexOf("_objc_msgSend") != -1)
                {
                    g.RegisterMethodName(mi.Name);
                }
            }

            g.Go();

            if (generate_file_list != null)
            {
                using (var f = File.CreateText(generate_file_list)){
                    g.GeneratedFiles.ForEach(x => f.WriteLine(x));
                }
                return(0);
            }

            cargs = String.Format("{0} -target:library -out:{1} {2} {3} {4} {5} {6} {7} -r:{8} {9} {10}",
                                  unsafef ? "-unsafe" : "",                                        /* 0 */
                                  outfile,                                                         /* 1 */
                                  string.Join(" ", defines.Select(x => "-define:" + x).ToArray()), /* 2 */
                                  String.Join(" ", g.GeneratedFiles.ToArray()),                    /* 3 */
                                  String.Join(" ", core_sources.ToArray()),                        /* 4 */
                                  String.Join(" ", sources.Skip(1).ToArray()),                     /* 5 */
                                  String.Join(" ", extra_sources.ToArray()),                       /* 6 */
                                  refs,                                                            /* 7 */
                                  baselibdll,                                                      /* 8 */
                                  String.Join(" ", resources.ToArray()),                           /* 9 */
                                  nostdlib ? "-nostdlib" : null
                                  );

            si = new ProcessStartInfo(compiler, cargs)
            {
                UseShellExecute = false,
            };

            if (verbose)
            {
                Console.WriteLine("{0} {1}", si.FileName, si.Arguments);
            }

            p = Process.Start(si);
            p.WaitForExit();
            if (p.ExitCode != 0)
            {
                Console.WriteLine("{0}: API binding contains errors.", tool_name);
                return(1);
            }
        } finally {
            if (delete_temp)
            {
                Directory.Delete(tmpdir, true);
            }
        }
        return(0);
    }
Exemplo n.º 5
0
        public static LinkWithAttribute GetLinkWithAttribute(CustomAttribute attr)
        {
            LinkWithAttribute linkWith;

            var cargs = attr.ConstructorArguments;

            switch (cargs.Count)
            {
            case 3:
                linkWith = new LinkWithAttribute((string)cargs [0].Value, (LinkTarget)cargs [1].Value, (string)cargs [2].Value);
                break;

            case 2:
                linkWith = new LinkWithAttribute((string)cargs [0].Value, (LinkTarget)cargs [1].Value);
                break;

            default:
            case 1:
                linkWith = new LinkWithAttribute((string)cargs [0].Value);
                break;
            }

            foreach (var property in attr.Properties)
            {
                switch (property.Name)
                {
                case "NeedsGccExceptionHandling":
                    linkWith.NeedsGccExceptionHandling = (bool)property.Argument.Value;
                    break;

                case "WeakFrameworks":
                    linkWith.WeakFrameworks = (string)property.Argument.Value;
                    break;

                case "Frameworks":
                    linkWith.Frameworks = (string)property.Argument.Value;
                    break;

                case "LinkerFlags":
                    linkWith.LinkerFlags = (string)property.Argument.Value;
                    break;

                case "LinkTarget":
                    linkWith.LinkTarget = (LinkTarget)property.Argument.Value;
                    break;

                case "ForceLoad":
                    linkWith.ForceLoad = (bool)property.Argument.Value;
                    break;

                case "IsCxx":
                    linkWith.IsCxx = (bool)property.Argument.Value;
                    break;

                case "SmartLink":
                    linkWith.SmartLink = (bool)property.Argument.Value;
                    break;

                default:
                    break;
                }
            }

            return(linkWith);
        }
Exemplo n.º 6
0
        // Executed in parallel
        public void ExtractNativeLinkInfo()
        {
            // ignore framework assemblies, they won't have any LinkWith attributes
            if (IsFrameworkAssembly)
            {
                return;
            }

            var assembly = AssemblyDefinition;

            if (!assembly.HasCustomAttributes)
            {
                return;
            }

            var    exceptions = new List <Exception> ();
            string path;

            //
            // Tasks:
            // * Remove LinkWith attribute: this is done in the linker.
            // * Remove embedded resources related to LinkWith attribute from assembly: this is done at a later stage,
            //   here we just compile a list of resources to remove.
            // * Extract embedded resources related to LinkWith attribute to a file
            // * Modify the linker flags used to build/link the dylib (if fastdev) or the main binary (if !fastdev)
            //

            for (int i = 0; i < assembly.CustomAttributes.Count; i++)
            {
                CustomAttribute attr = assembly.CustomAttributes[i];

                if (attr.Constructor == null)
                {
                    continue;
                }

                TypeReference type = attr.Constructor.DeclaringType;
                if (!type.IsPlatformType("ObjCRuntime", "LinkWithAttribute"))
                {
                    continue;
                }

                // we know we'll modify this assembly, so load its symbols to keep them in sync
                LoadSymbols();

                // Let the linker remove it the attribute from the assembly

                LinkWithAttribute linkWith    = GetLinkWithAttribute(attr);
                string            libraryName = linkWith.LibraryName;

                // Remove the resource from the assembly at a later stage.
                AddResourceToBeRemoved(libraryName);

                // We can't add -dead_strip if there are any LinkWith attributes where smart linking is disabled.
                if (!linkWith.SmartLink)
                {
                    App.DeadStrip = false;
                }

                // Don't add -force_load if the binding's SmartLink value is set and the static registrar is being used.
                if (linkWith.ForceLoad && !(linkWith.SmartLink && App.Registrar == RegistrarMode.Static))
                {
                    ForceLoad = true;
                }

                if (!string.IsNullOrEmpty(linkWith.LinkerFlags))
                {
                    if (LinkerFlags == null)
                    {
                        LinkerFlags = new List <string> ();
                    }
                    LinkerFlags.Add(linkWith.LinkerFlags);
                }

                if (!string.IsNullOrEmpty(linkWith.Frameworks))
                {
                    foreach (var f in linkWith.Frameworks.Split(new char[] { ' ' }))
                    {
                        if (Frameworks == null)
                        {
                            Frameworks = new HashSet <string> ();
                        }
                        Frameworks.Add(f);
                    }
                }

                if (!string.IsNullOrEmpty(linkWith.WeakFrameworks))
                {
                    foreach (var f in linkWith.WeakFrameworks.Split(new char[] { ' ' }))
                    {
                        if (WeakFrameworks == null)
                        {
                            WeakFrameworks = new HashSet <string> ();
                        }
                        WeakFrameworks.Add(f);
                    }
                }

                if (linkWith.NeedsGccExceptionHandling)
                {
                    NeedsGccExceptionHandling = true;
                }

                if (linkWith.IsCxx)
                {
                    EnableCxx = true;
                }

                path = Path.Combine(Cache.Location, libraryName);
                if (path.EndsWith(".framework"))
                {
#if MONOTOUCH
                    if (App.DeploymentTarget.Major < 8)
                    {
                        throw ErrorHelper.CreateError(1305, "The binding library '{0}' contains a user framework ({0}), but embedded user frameworks require iOS 8.0 (the deployment target is {1}). Please set the deployment target in the Info.plist file to at least 8.0.",
                                                      FileName, Path.GetFileName(path), App.DeploymentTarget);
                    }
#endif
                    var zipPath = path + ".zip";
                    if (!Application.IsUptodate(FullPath, zipPath))
                    {
                        Application.ExtractResource(assembly.MainModule, libraryName, zipPath, false);
                        Driver.Log(3, "Extracted third-party framework '{0}' from '{1}' to '{2}'", libraryName, FullPath, zipPath);
                    }
                    else
                    {
                        Driver.Log(3, "Target '{0}' is up-to-date.", path);
                    }

                    if (!File.Exists(zipPath))
                    {
                        ErrorHelper.Warning(1302, "Could not extract the native framework '{0}' from '{1}'. " +
                                            "Please ensure the native framework was properly embedded in the managed assembly " +
                                            "(if the assembly was built using a binding project, the native framework must be included in the project, and its Build Action must be 'ObjcBindingNativeFramework').",
                                            libraryName, zipPath);
                    }
                    else
                    {
                        if (!Directory.Exists(path))
                        {
                            Directory.CreateDirectory(path);
                        }

                        if (Driver.RunCommand("/usr/bin/unzip", string.Format("-u -o -d {0} {1}", Driver.Quote(path), Driver.Quote(zipPath))) != 0)
                        {
                            throw ErrorHelper.CreateError(1303, "Could not decompress the native framework '{0}' from '{1}'. Please review the build log for more information from the native 'unzip' command.", libraryName, zipPath);
                        }
                    }

                    if (Frameworks == null)
                    {
                        Frameworks = new HashSet <string> ();
                    }
                    Frameworks.Add(path);
                }
                else
                {
                    if (!Application.IsUptodate(FullPath, path))
                    {
                        Application.ExtractResource(assembly.MainModule, libraryName, path, false);
                        Driver.Log(3, "Extracted third-party binding '{0}' from '{1}' to '{2}'", libraryName, FullPath, path);
                    }
                    else
                    {
                        Driver.Log(3, "Target '{0}' is up-to-date.", path);
                    }

                    if (!File.Exists(path))
                    {
                        ErrorHelper.Warning(1302, "Could not extract the native library '{0}' from '{1}'. " +
                                            "Please ensure the native library was properly embedded in the managed assembly " +
                                            "(if the assembly was built using a binding project, the native library must be included in the project, and its Build Action must be 'ObjcBindingNativeLibrary').",
                                            libraryName, path);
                    }

                    if (LinkWith == null)
                    {
                        LinkWith = new List <string> ();
                    }
                    LinkWith.Add(path);
                }
            }

            if (exceptions != null && exceptions.Count > 0)
            {
                throw new AggregateException(exceptions);
            }

            // Make sure there are no duplicates between frameworks and weak frameworks.
            // Keep the weak ones.
            if (Frameworks != null && WeakFrameworks != null)
            {
                Frameworks.ExceptWith(WeakFrameworks);
            }

            if (NeedsGccExceptionHandling)
            {
                if (LinkerFlags == null)
                {
                    LinkerFlags = new List <string> ();
                }
                LinkerFlags.Add("-lgcc_eh");
            }
        }
Exemplo n.º 7
0
        void ProcessLinkWithAttributes(AssemblyDefinition assembly)
        {
            //
            // Tasks:
            // * Remove LinkWith attribute: this is done in the linker.
            // * Remove embedded resources related to LinkWith attribute from assembly: this is done at a later stage,
            //   here we just compile a list of resources to remove.
            // * Extract embedded resources related to LinkWith attribute to a file
            // * Modify the linker flags used to build/link the dylib (if fastdev) or the main binary (if !fastdev)
            //

            for (int i = 0; i < assembly.CustomAttributes.Count; i++)
            {
                CustomAttribute attr = assembly.CustomAttributes [i];

                if (attr.Constructor == null)
                {
                    continue;
                }

                TypeReference type = attr.Constructor.DeclaringType;
                if (!type.Is("ObjCRuntime", "LinkWithAttribute"))
                {
                    continue;
                }

                // Let the linker remove it the attribute from the assembly
                HasLinkWithAttributes = true;

                LinkWithAttribute       linkWith = GetLinkWithAttribute(attr);
                NativeReferenceMetadata metadata = new NativeReferenceMetadata(linkWith);

                // If we've already processed this native library, skip it
                if (LinkWith.Any(x => Path.GetFileName(x) == metadata.LibraryName) || Frameworks.Any(x => Path.GetFileName(x) == metadata.LibraryName))
                {
                    continue;
                }

                // Remove the resource from the assembly at a later stage.
                if (!string.IsNullOrEmpty(metadata.LibraryName))
                {
                    AddResourceToBeRemoved(metadata.LibraryName);
                }

                ProcessNativeReferenceOptions(metadata);

                if (!string.IsNullOrEmpty(linkWith.LibraryName))
                {
                    switch (Path.GetExtension(linkWith.LibraryName).ToLowerInvariant())
                    {
                    case ".framework":
                        AssertiOSVersionSupportsUserFrameworks(linkWith.LibraryName);
                        Frameworks.Add(ExtractFramework(assembly, metadata));
                        break;

                    case ".xcframework":
                        // this is resolved, at msbuild time, into a framework
                        // but we must ignore it here (can't be the `default` case)
                        break;

                    default:
                        LinkWith.Add(ExtractNativeLibrary(assembly, metadata));
                        break;
                    }
                }
            }
        }
Exemplo n.º 8
0
    static int Main2(string [] args)
    {
        bool          show_help = false;
        bool          zero_copy = false;
        string        basedir = null;
        string        tmpdir = null;
        string        ns = null;
        string        outfile = null;
        bool          delete_temp = true, debug = false;
        bool          verbose          = false;
        bool          unsafef          = true;
        bool          external         = false;
        bool          public_mode      = true;
        bool          nostdlib         = false;
        bool          inline_selectors = Unified && CurrentPlatform != PlatformName.MacOSX;
        List <string> sources;
        var           resources           = new List <string> ();
        var           linkwith            = new List <string> ();
        var           references          = new List <string> ();
        var           libs                = new List <string> ();
        var           api_sources         = new List <string> ();
        var           core_sources        = new List <string> ();
        var           extra_sources       = new List <string> ();
        var           defines             = new List <string> ();
        bool          binding_third_party = true;
        string        generate_file_list  = null;
        bool          process_enums       = false;

        // .NET treats ' as part of the command name when running an app so we must use " on Windows
        PlatformID pid = Environment.OSVersion.Platform;

        if (((int)pid != 128 && pid != PlatformID.Unix && pid != PlatformID.MacOSX))
        {
            shellQuoteChar = '"';             // Windows
        }
        else
        {
            shellQuoteChar = '\'';             // !Windows
        }
        var os = new OptionSet()
        {
            { "h|?|help", "Displays the help", v => show_help = true },
            { "a", "Include alpha bindings (Obsolete).", v => {}, true },
            { "outdir=", "Sets the output directory for the temporary binding files", v => { basedir = v; } },
            { "o|out=", "Sets the name of the output library", v => outfile = v },
            { "tmpdir=", "Sets the working directory for temp files", v => { tmpdir = v; delete_temp = false; } },
            { "debug", "Generates a debugging build of the binding", v => debug = true },
            { "sourceonly=", "Only generates the source", v => generate_file_list = v },
            { "ns=", "Sets the namespace for storing helper classes", v => ns = v },
            { "unsafe", "Sets the unsafe flag for the build", v => unsafef = true },
            { "core", "Use this to build product assemblies", v => binding_third_party = false },
            { "r=", "Adds a reference", v => references.Add(v) },
            { "lib=", "Adds the directory to the search path for the compiler", v => libs.Add(Quote(v)) },
            { "compiler=", "Sets the compiler to use", v => compiler = v },
            { "sdk=", "Sets the .NET SDK to use", v => net_sdk = v },
            { "new-style", "Build for Unified (Obsolete).", v => { Console.WriteLine("The --new-style option is obsolete and ignored."); }, true },
            { "d=", "Defines a symbol", v => defines.Add(v) },
            { "api=", "Adds a API definition source file", v => api_sources.Add(Quote(v)) },
            { "s=", "Adds a source file required to build the API", v => core_sources.Add(Quote(v)) },
            { "v", "Sets verbose mode", v => verbose = true },
            { "x=", "Adds the specified file to the build, used after the core files are compiled", v => extra_sources.Add(Quote(v)) },
            { "e", "Generates smaller classes that can not be subclassed (previously called 'external mode')", v => external = true },
            { "p", "Sets private mode", v => public_mode = false },
            { "baselib=", "Sets the base library", v => baselibdll = v },
            { "use-zero-copy", v => zero_copy = true },
            { "nostdlib", "Does not reference mscorlib.dll library", l => nostdlib = true },
            { "no-mono-path", "Launches compiler with empty MONO_PATH", l => { } },
            { "native-exception-marshalling", "Enable the marshalling support for Objective-C exceptions", (v) => { /* no-op */ } },
            { "inline-selectors:", "If Selector.GetHandle is inlined and does not need to be cached (enabled by default in Xamarin.iOS, disabled in Xamarin.Mac)",
              v => inline_selectors = string.Equals("true", v, StringComparison.OrdinalIgnoreCase) || string.IsNullOrEmpty(v) },
            { "process-enums", "Process enums as bindings, not external, types.", v => process_enums = true },
            { "link-with=,", "Link with a native library {0:FILE} to the binding, embedded as a resource named {1:ID}",
              (path, id) => {
                  if (path == null || path.Length == 0)
                  {
                      throw new Exception("-link-with=FILE,ID requires a filename.");
                  }

                  if (id == null || id.Length == 0)
                  {
                      id = Path.GetFileName(path);
                  }

                  if (linkwith.Contains(id))
                  {
                      throw new Exception("-link-with=FILE,ID cannot assign the same resource id to multiple libraries.");
                  }

                  resources.Add(string.Format("-res:{0},{1}", path, id));
                  linkwith.Add(id);
              } },
            { "unified-full-profile", "Launches compiler pointing to XM Full Profile", l => { /* no-op*/ }, true },
            { "unified-mobile-profile", "Launches compiler pointing to XM Mobile Profile", l => { /* no-op*/ }, true },
        };

        try {
            sources = os.Parse(args);
        } catch (Exception e) {
            Console.Error.WriteLine("{0}: {1}", tool_name, e.Message);
            Console.Error.WriteLine("see {0} --help for more information", tool_name);
            return(1);
        }

        if (show_help)
        {
            ShowHelp(os);
            return(0);
        }

        if (sources.Count > 0)
        {
            api_sources.Insert(0, Quote(sources [0]));
            for (int i = 1; i < sources.Count; i++)
            {
                core_sources.Insert(i - 1, Quote(sources [i]));
            }
        }

        if (api_sources.Count == 0)
        {
            Console.WriteLine("Error: no api file provided");
            ShowHelp(os);
            return(1);
        }

        if (tmpdir == null)
        {
            tmpdir = GetWorkDir();
        }

        string firstApiDefinitionName = Path.GetFileNameWithoutExtension(Unquote(api_sources [0]));

        firstApiDefinitionName = firstApiDefinitionName.Replace('-', '_');          // This is not exhaustive, but common.
        if (outfile == null)
        {
            outfile = firstApiDefinitionName + ".dll";
        }

        string refs = string.Empty;

        foreach (var r in references)
        {
            if (refs != string.Empty)
            {
                refs += " ";
            }
            refs += "-r:" + Quote(r);
        }
        string paths = (libs.Count > 0 ? "-lib:" + String.Join(" -lib:", libs.ToArray()) : "");

        try {
            var tmpass = Path.Combine(tmpdir, "temp.dll");

            // -nowarn:436 is to avoid conflicts in definitions between core.dll and the sources
            // Keep source files at the end of the command line - csc will create TWO assemblies if any sources preceed the -out parameter
            var cargs = new StringBuilder();

            if (CurrentPlatform == PlatformName.MacOSX)
            {
                if (!string.IsNullOrEmpty(net_sdk) && net_sdk != "mobile")
                {
                    cargs.Append("-sdk:").Append(net_sdk).Append(' ');
                }
            }
            else
            {
                if (!string.IsNullOrEmpty(net_sdk))
                {
                    cargs.Append("-sdk:").Append(net_sdk).Append(' ');
                }
            }
            cargs.Append("-debug -unsafe -target:library -nowarn:436").Append(' ');
            cargs.Append("-out:").Append(Quote(tmpass)).Append(' ');
            cargs.Append("-r:").Append(Environment.GetCommandLineArgs()[0]).Append(' ');
            cargs.Append(refs).Append(' ');
            if (unsafef)
            {
                cargs.Append("-unsafe ");
            }
            cargs.Append("-r:").Append(Quote(baselibdll)).Append(' ');
            foreach (var def in defines)
            {
                cargs.Append("-define:").Append(def).Append(' ');
            }
            cargs.Append(paths).Append(' ');
            if (nostdlib)
            {
                cargs.Append("-nostdlib ");
            }
            foreach (var qs in api_sources)
            {
                cargs.Append(qs).Append(' ');
            }
            foreach (var cs in core_sources)
            {
                cargs.Append(cs).Append(' ');
            }
            if (!string.IsNullOrEmpty(Path.GetDirectoryName(baselibdll)))
            {
                cargs.Append("-lib:").Append(Path.GetDirectoryName(baselibdll)).Append(' ');
            }


            var si = new ProcessStartInfo(compiler, cargs.ToString())
            {
                UseShellExecute = false,
            };

            // HACK: We are calling btouch with forced 2.1 path but we need working mono for compiler
            si.EnvironmentVariables.Remove("MONO_PATH");

            if (verbose)
            {
                Console.WriteLine("{0} {1}", si.FileName, si.Arguments);
            }

            var p = Process.Start(si);
            p.WaitForExit();
            if (p.ExitCode != 0)
            {
                Console.WriteLine("{0}: API binding contains errors.", tool_name);
                return(1);
            }

            Assembly api;
            try {
                api = Assembly.LoadFrom(tmpass);
            } catch (Exception e) {
                if (verbose)
                {
                    Console.WriteLine(e);
                }

                Console.Error.WriteLine("Error loading API definition from {0}", tmpass);
                return(1);
            }

            Assembly baselib;
            try {
                baselib = Assembly.LoadFrom(baselibdll);
            } catch (Exception e) {
                if (verbose)
                {
                    Console.WriteLine(e);
                }

                Console.Error.WriteLine("Error loading base library {0}", baselibdll);
                return(1);
            }
            GC.KeepAlive(baselib);              // Fixes a compiler warning (unused variable).

            foreach (object attr in api.GetCustomAttributes(typeof(LinkWithAttribute), true))
            {
                LinkWithAttribute linkWith = (LinkWithAttribute)attr;

                if (!linkwith.Contains(linkWith.LibraryName))
                {
                    Console.Error.WriteLine("Missing native library {0}, please use `--link-with' to specify the path to this library.", linkWith.LibraryName);
                    return(1);
                }
            }

            foreach (var r in references)
            {
                if (File.Exists(r))
                {
                    try {
                        Assembly.LoadFrom(r);
                    } catch (Exception ex) {
                        ErrorHelper.Show(new BindingException(1104, false, "Could not load the referenced library '{0}': {1}.", r, ex.Message));
                    }
                }
            }

            var types = new List <Type> ();
            var strong_dictionaries = new List <Type> ();
            foreach (var t in api.GetTypes())
            {
                if ((process_enums && t.IsEnum) ||
                    t.GetCustomAttributes(typeof(BaseTypeAttribute), true).Length > 0 ||
                    t.GetCustomAttributes(typeof(ProtocolAttribute), true).Length > 0 ||
                    t.GetCustomAttributes(typeof(StaticAttribute), true).Length > 0 ||
                    t.GetCustomAttributes(typeof(PartialAttribute), true).Length > 0)
                {
                    types.Add(t);
                }
                if (t.GetCustomAttributes(typeof(StrongDictionaryAttribute), true).Length > 0)
                {
                    strong_dictionaries.Add(t);
                }
            }

            bool addSystemDrawingReferences =
#if NO_SYSTEM_DRAWING
                true;
#else
                false;
#endif

            string nsManagerPrefix;
            switch (CurrentPlatform)
            {
            case PlatformName.MacOSX:
                nsManagerPrefix = Unified ? null : "MonoMac";
                break;

            case PlatformName.iOS:
                nsManagerPrefix = Unified ? null : "MonoTouch";
                break;

            default:
                nsManagerPrefix = null;
                break;
            }

            var nsManager = new NamespaceManager(
                nsManagerPrefix,
                ns == null ? firstApiDefinitionName : ns,
                addSystemDrawingReferences
                );

            Generator.CurrentPlatform = CurrentPlatform;
            var g = new Generator(nsManager, public_mode, external, debug, types.ToArray(), strong_dictionaries.ToArray())
            {
                BindThirdPartyLibrary = binding_third_party,
                CoreNSObject          = CoreObject,
                BaseDir           = basedir != null ? basedir : tmpdir,
                ZeroCopyStrings   = zero_copy,
                Compat            = !Unified,
                InlineSelectors   = inline_selectors,
                SkipSystemDrawing = addSystemDrawingReferences
            };

            if (!Unified && !binding_third_party)
            {
                foreach (var mi in baselib.GetType(nsManager.CoreObjCRuntime + ".Messaging").GetMethods())
                {
                    if (mi.Name.IndexOf("_objc_msgSend") != -1)
                    {
                        g.RegisterMethodName(mi.Name);
                    }
                }
            }

            g.Go();

            if (generate_file_list != null)
            {
                using (var f = File.CreateText(generate_file_list)){
                    foreach (var x in g.GeneratedFiles.OrderBy((v) => v))
                    {
                        f.WriteLine(x);
                    }
                }
                return(0);
            }

            cargs.Clear();
            if (unsafef)
            {
                cargs.Append("-unsafe ");
            }
            cargs.Append("-target:library ");
            cargs.Append("-out:").Append(Quote(outfile)).Append(' ');
            foreach (var def in defines)
            {
                cargs.Append("-define:").Append(def).Append(' ');
            }
            foreach (var gf in g.GeneratedFiles)
            {
                cargs.Append(gf).Append(' ');
            }
            foreach (var cs in core_sources)
            {
                cargs.Append(cs).Append(' ');
            }
            foreach (var es in extra_sources)
            {
                cargs.Append(es).Append(' ');
            }
            cargs.Append(refs).Append(' ');
            cargs.Append("-r:").Append(Quote(baselibdll)).Append(' ');
            foreach (var res in resources)
            {
                cargs.Append(res).Append(' ');
            }
            if (nostdlib)
            {
                cargs.Append("-nostdlib ");
            }
            if (!string.IsNullOrEmpty(Path.GetDirectoryName(baselibdll)))
            {
                cargs.Append("-lib:").Append(Path.GetDirectoryName(baselibdll)).Append(' ');
            }

            si = new ProcessStartInfo(compiler, cargs.ToString())
            {
                UseShellExecute = false,
            };

            // HACK: We are calling btouch with forced 2.1 path but we need working mono for compiler
            si.EnvironmentVariables.Remove("MONO_PATH");

            if (verbose)
            {
                Console.WriteLine("{0} {1}", si.FileName, si.Arguments);
            }

            p = Process.Start(si);
            p.WaitForExit();
            if (p.ExitCode != 0)
            {
                Console.WriteLine("{0}: API binding contains errors.", tool_name);
                return(1);
            }
        } finally {
            if (delete_temp)
            {
                Directory.Delete(tmpdir, true);
            }
        }
        return(0);
    }