Пример #1
0
    int Main3(string [] args)
    {
        bool          show_help = false;
        bool          zero_copy = false;
        string        basedir = null;
        string        tmpdir = null;
        string        ns = 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 = null;
        List <string> sources;
        var           resources          = new List <string> ();
        var           linkwith           = new List <string> ();
        var           references         = 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> ();
        string        generate_file_list = null;
        bool          process_enums      = false;
        string        compiler           = "/Library/Frameworks/Mono.framework/Versions/Current/bin/csc";

        ErrorHelper.ClearWarningLevels();

        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 => BindThirdPartyLibrary = false },
            { "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 (Obsolete) ", v => compiler = v, true },
            { "sdk=", "Sets the .NET SDK to use (Obsolete)", v => {}, true },
            { "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(v) },
            { "s=", "Adds a source file required to build the API", v => core_sources.Add(v) },
            { "q", "Quiet", v => verbose = false },
            { "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 => public_mode = false },
            { "baselib=", "Sets the base library", v => baselibdll = v },
            { "attributelib=", "Sets the attribute library", v => attributedll = 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 => { }, true },
            { "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 },
            { "target-framework=", "Specify target framework to use. Always required, and the currently supported values are: 'MonoTouch,v1.0', 'Xamarin.iOS,v1.0', 'Xamarin.TVOS,v1.0', 'Xamarin.WatchOS,v1.0', 'XamMac,v1.0', 'Xamarin.Mac,Version=v2.0,Profile=Mobile', 'Xamarin.Mac,Version=v4.5,Profile=Full' and 'Xamarin.Mac,Version=v4.5,Profile=System')", v => SetTargetFramework(v) },
            { "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) {
                      throw ErrorHelper.CreateError(26, $"Could not parse the command line argument '--warnaserror': {ex.Message}");
                  }
              } },
            { "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) {
                      throw ErrorHelper.CreateError(26, $"Could not parse the command line argument '--nowarn': {ex.Message}");
                  }
              } },
            new Mono.Options.ResponseFileSource(),
        };

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

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

        if (!target_framework.HasValue)
        {
            throw ErrorHelper.CreateError(86, "A target framework (--target-framework) must be specified.");
        }

        switch (target_framework.Value.Identifier.ToLowerInvariant())
        {
        case "xamarin.ios":
            CurrentPlatform = PlatformName.iOS;
            nostdlib        = true;
            if (string.IsNullOrEmpty(baselibdll))
            {
                baselibdll = Path.Combine(GetSDKRoot(), "lib/mono/Xamarin.iOS/Xamarin.iOS.dll");
            }
            references.Add("Facades/System.Drawing.Common");
            ReferenceFixer.FixSDKReferences(GetSDKRoot(), "lib/mono/Xamarin.iOS", references);
            break;

        case "xamarin.tvos":
            CurrentPlatform = PlatformName.TvOS;
            nostdlib        = true;
            if (string.IsNullOrEmpty(baselibdll))
            {
                baselibdll = Path.Combine(GetSDKRoot(), "lib/mono/Xamarin.TVOS/Xamarin.TVOS.dll");
            }
            references.Add("Facades/System.Drawing.Common");
            ReferenceFixer.FixSDKReferences(GetSDKRoot(), "lib/mono/Xamarin.TVOS", references);
            break;

        case "xamarin.watchos":
            CurrentPlatform = PlatformName.WatchOS;
            nostdlib        = true;
            if (string.IsNullOrEmpty(baselibdll))
            {
                baselibdll = Path.Combine(GetSDKRoot(), "lib/mono/Xamarin.WatchOS/Xamarin.WatchOS.dll");
            }
            references.Add("Facades/System.Drawing.Common");
            ReferenceFixer.FixSDKReferences(GetSDKRoot(), "lib/mono/Xamarin.WatchOS", references);
            break;

        case "xamarin.mac":
            CurrentPlatform = PlatformName.MacOSX;
            nostdlib        = true;
            if (string.IsNullOrEmpty(baselibdll))
            {
                if (target_framework == TargetFramework.Xamarin_Mac_2_0_Mobile)
                {
                    baselibdll = Path.Combine(GetSDKRoot(), "lib", "reference", "mobile", "Xamarin.Mac.dll");
                }
                else if (target_framework == TargetFramework.Xamarin_Mac_4_5_Full || target_framework == TargetFramework.Xamarin_Mac_4_5_System)
                {
                    baselibdll = Path.Combine(GetSDKRoot(), "lib", "reference", "full", "Xamarin.Mac.dll");
                }
                else
                {
                    throw ErrorHelper.CreateError(1043, "Internal error: unknown target framework '{0}'.", target_framework);
                }
            }
            if (target_framework == TargetFramework.Xamarin_Mac_2_0_Mobile)
            {
                skipSystemDrawing = true;
                references.Add("Facades/System.Drawing.Common");
                ReferenceFixer.FixSDKReferences(GetSDKRoot(), "lib/mono/Xamarin.Mac", references);
            }
            else if (target_framework == TargetFramework.Xamarin_Mac_4_5_Full)
            {
                skipSystemDrawing = true;
                references.Add("Facades/System.Drawing.Common");
                ReferenceFixer.FixSDKReferences(GetSDKRoot(), "lib/mono/4.5", references);
            }
            else if (target_framework == TargetFramework.Xamarin_Mac_4_5_System)
            {
                skipSystemDrawing = false;
                ReferenceFixer.FixSDKReferences("/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5", references, forceSystemDrawing: true);
            }
            else
            {
                throw ErrorHelper.CreateError(1043, "Internal error: unknown target framework '{0}'.", target_framework);
            }

            break;

        default:
            throw ErrorHelper.CreateError(1043, "Internal error: unknown target framework '{0}'.", target_framework);
        }

        if (sources.Count > 0)
        {
            api_sources.Insert(0, sources [0]);
            for (int i = 1; i < sources.Count; i++)
            {
                core_sources.Insert(i - 1, 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(api_sources [0]);

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

        var refs  = references.Select((v) => "-r:" + v);
        var paths = libs.Select((v) => "-lib:" + v);

        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 List <string> ();

            cargs.Add("-debug");
            cargs.Add("-unsafe");
            cargs.Add("-target:library");
            cargs.Add("-nowarn:436");
            cargs.Add("-out:" + tmpass);
            cargs.Add("-r:" + GetAttributeLibraryPath());
            cargs.AddRange(refs);
            if (unsafef)
            {
                cargs.Add("-unsafe");
            }
            cargs.Add("-r:" + baselibdll);
            foreach (var def in defines)
            {
                cargs.Add("-define:" + def);
            }
            cargs.AddRange(paths);
            if (nostdlib)
            {
                cargs.Add("-nostdlib");
                cargs.Add("-noconfig");
            }
            cargs.AddRange(api_sources);
            cargs.AddRange(core_sources);
            if (!string.IsNullOrEmpty(Path.GetDirectoryName(baselibdll)))
            {
                cargs.Add("-lib:" + Path.GetDirectoryName(baselibdll));
            }

            if (Driver.RunCommand(compiler, cargs, null, out var compile_output, true, verbose ? 1 : 0) != 0)
            {
                throw ErrorHelper.CreateError(2, "Could not compile the API bindings.\n\t" + compile_output.ToString().Replace("\n", "\n\t"));
            }

            universe = new Universe(UniverseOptions.EnableFunctionPointers | UniverseOptions.ResolveMissingMembers | UniverseOptions.MetadataOnly);

            Assembly api;
            try {
                api = universe.LoadFile(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 = universe.LoadFile(baselibdll);
            } catch (Exception e) {
                if (verbose)
                {
                    Console.WriteLine(e);
                }

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

            AttributeManager = new AttributeManager(this);
            Frameworks       = new Frameworks(CurrentPlatform);

            Assembly corlib_assembly   = universe.LoadFile(LocateAssembly("mscorlib"));
            Assembly platform_assembly = baselib;
            Assembly system_assembly   = universe.LoadFile(LocateAssembly("System"));
            Assembly binding_assembly  = universe.LoadFile(GetAttributeLibraryPath());
            TypeManager.Initialize(this, api, corlib_assembly, platform_assembly, system_assembly, binding_assembly);

            foreach (var linkWith in AttributeManager.GetCustomAttributes <LinkWithAttribute> (api))
            {
                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 {
                        universe.LoadFile(r);
                    } catch (Exception ex) {
                        ErrorHelper.Warning(1104, "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) ||
                    AttributeManager.HasAttribute <BaseTypeAttribute> (t) ||
                    AttributeManager.HasAttribute <ProtocolAttribute> (t) ||
                    AttributeManager.HasAttribute <StaticAttribute> (t) ||
                    AttributeManager.HasAttribute <PartialAttribute> (t))
                {
                    types.Add(t);
                }
                if (AttributeManager.HasAttribute <StrongDictionaryAttribute> (t))
                {
                    strong_dictionaries.Add(t);
                }
            }

            var nsManager = new NamespaceManager(
                this,
                ns == null ? firstApiDefinitionName : ns,
                skipSystemDrawing
                );

            var g = new Generator(this, nsManager, public_mode, external, debug, types.ToArray(), strong_dictionaries.ToArray())
            {
                BaseDir         = basedir != null ? basedir : tmpdir,
                ZeroCopyStrings = zero_copy,
                InlineSelectors = inline_selectors ?? (CurrentPlatform != PlatformName.MacOSX),
            };

            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.Add("-unsafe");
            }
            cargs.Add("-target:library");
            cargs.Add("-out:" + outfile);
            foreach (var def in defines)
            {
                cargs.Add("-define:" + def);
            }
            cargs.AddRange(g.GeneratedFiles);
            cargs.AddRange(core_sources);
            cargs.AddRange(extra_sources);
            cargs.AddRange(refs);
            cargs.Add("-r:" + baselibdll);
            cargs.AddRange(resources);
            if (nostdlib)
            {
                cargs.Add("-nostdlib");
                cargs.Add("-noconfig");
            }
            if (!string.IsNullOrEmpty(Path.GetDirectoryName(baselibdll)))
            {
                cargs.Add("-lib:" + Path.GetDirectoryName(baselibdll));
            }

            if (Driver.RunCommand(compiler, cargs, null, out var generated_compile_output, true, verbose ? 1 : 0) != 0)
            {
                throw ErrorHelper.CreateError(1000, "Could not compile the generated API bindings.\n\t" + generated_compile_output.ToString().Replace("\n", "\n\t"));
            }
        } finally {
            if (delete_temp)
            {
                Directory.Delete(tmpdir, true);
            }
        }
        return(0);
    }