Exemple #1
0
        public static Assembly Compile(Xamarin.Android.Binder.CodeGeneratorOptions options,
                                       string assemblyFileName, IEnumerable <string> AdditionalSourceDirectories, out string[] errors)
        {
            var generatedCodePath = options.ManagedCallableWrapperSourceOutputDirectory;
            var sourceFiles       = Directory.EnumerateFiles(generatedCodePath, "*.cs",
                                                             SearchOption.AllDirectories).ToList();

            sourceFiles = sourceFiles.Select(x => Path.GetFullPath(x)).ToList();

            var supportFiles = Directory.EnumerateFiles(Path.Combine(Path.GetDirectoryName(supportFilePath), "SupportFiles"),
                                                        "*.cs", SearchOption.AllDirectories);

            sourceFiles.AddRange(supportFiles);

            foreach (var dir in AdditionalSourceDirectories)
            {
                var additonal = Directory.EnumerateFiles(dir, "*.cs", SearchOption.AllDirectories);
                sourceFiles.AddRange(additonal);
            }

            CompilerParameters parameters = new CompilerParameters();

            parameters.GenerateExecutable = false;
            parameters.GenerateInMemory   = true;
            parameters.CompilerOptions    = "/unsafe";
            parameters.OutputAssembly     = assemblyFileName;
            parameters.ReferencedAssemblies.Add(unitTestFrameworkAssemblyPath);

            var binDir = Path.GetDirectoryName(typeof(BaseGeneratorTest).Assembly.Location);
            var facDir = GetFacadesPath();

            parameters.ReferencedAssemblies.Add(Path.Combine(binDir, "Java.Interop.dll"));
            parameters.ReferencedAssemblies.Add(Path.Combine(facDir, "System.Runtime.dll"));
#if DEBUG
            parameters.IncludeDebugInformation = true;
#else
            parameters.IncludeDebugInformation = false;
#endif

            CSharpCodeProvider codeProvider = new CSharpCodeProvider();
            CompilerResults    results      = codeProvider.CompileAssemblyFromFile(parameters, sourceFiles.ToArray());

            List <string> errs = new List <string> ();
            foreach (CompilerError message in results.Errors)
            {
                if (message.IsWarning)
                {
                    continue;
                }
                errs.Add(message.ToString());
            }

            errors = errs.ToArray();

            return(results.CompiledAssembly);
        }
        public static CodeGeneratorOptions Parse(string[] args)
        {
            var opts = new CodeGeneratorOptions();

            bool show_help = false;

            var parser = new OptionSet {
                "Usage: generator.exe OPTIONS+ API_DESCRIPTION",
                "",
                "Generates C# source files to bind Java code described by API_DESCRIPTION.",
                "",
                "Copyright 2012 Xamarin, Inc.",
                "",
                "Options:",
                { "assembly=",
                  "Fully Qualified Assembly Name ({FQAN}) of the eventual assembly (.dll) that will be built.",
                  v => opts.AssemblyQualifiedName = v },
                { "codegen-target=",
                  "{STYLE} of Binding Assembly to generate",
                  v => opts.CodeGenerationTarget = ParseCodeGenerationTarget(v) },
                { "fixup=",
                  "XML {FILE} controlling the generated API.\n" +
                  "http://www.mono-project.com/GAPI#Altering_and_Extending_the_API_File",
                  v => opts.FixupFiles.Add(v) },
                { "global",
                  "Prefix type names with `global::`.",
                  v => opts.GlobalTypeNames = v != null },
                { "javadir=",
                  "Ignored; for compatibility.",
                  v => {} },
                { "L=",
                  "{PATH} to look for referenced assemblies..",
                  v => opts.LibraryPaths.Add(v) },
                { "o|csdir=",
                  "{DIRECTORY} to place C# source into.",
                  v => opts.ManagedCallableWrapperSourceOutputDirectory = v },
                { "public",
                  "Obsolete option. It binds only public types now",
                  v => opts.OnlyBindPublicTypes = v != null },
                { "r|ref=",
                  "{ASSEMBLY} to reference.",
                  v => opts.AssemblyReferences.Add(v) },
                { "sdk-platform|api-level=",
                  "SDK Platform {VERSION}/API level.",
                  v => opts.ApiLevel = v },
                { "lang-features=",
                  "For internal use. (Flags: interface-constants)",
                  v => opts.SupportInterfaceConstants = v?.Contains("interface-constants") == true },
                { "preserve-enums",
                  "For internal use.",
                  v => opts.PreserveEnums = v != null },
                { "use-short-file-names",
                  "Generates short file name.",
                  v => opts.UseShortFileNames = v != null },
                { "product-version=",
                  "Xamarin.Android Major Product Version",
                  (int?v) => opts.ProductVersion = v.HasValue ? v.Value : 0 },
                { "v:",
                  "Logging Verbosity",
                  (int?v) => Report.Verbosity = v.HasValue ? v.Value : (Report.Verbosity ?? 0) + 1 },
                { "type-map-report=",
                  "Java-Managed Mapping report file.",
                  v => opts.MappingReportFile = v },
                { "only-xml-adjuster",
                  "Run only API XML adjuster for class-parse input.",
                  v => opts.OnlyRunApiXmlAdjuster = v != null },
                { "xml-adjuster-output=",
                  "specify API XML adjuster output XML for class-parse input.",
                  v => opts.ApiXmlAdjusterOutput = v },
                { "h|?|help",
                  "Show this message and exit.",
                  v => show_help = v != null },
                "",
                "C# Enumeration Support:",
                { "enumdir=",
                  "{DIRECTORY} to write enumeration declarations.",
                  v => opts.EnumOutputDirectory = v },
                { "enumfields=",
                  "For internal use.",
                  v => opts.EnumFieldsMapFile = v },
                { "enumflags=",
                  "For internal use.",
                  v => opts.EnumFlagsFile = v },
                { "enummetadata=",
                  "XML {FILENAME} to create.",
                  v => opts.EnumMetadataOutputFile = v },
                { "enummethods=",
                  "For internal use.",
                  v => opts.EnumMethodsMapFile = v },
                { "apiversions=",
                  "For internal use.",
                  v => opts.ApiVersionsXmlFile = v },
                { "annotations=",
                  "For internal use.",
                  v => opts.AnnotationsZipFiles.Add(v) },
            };

            var apis = parser.Parse(args);

            if (args.Length < 2 || show_help)
            {
                parser.WriteOptionDescriptions(Console.Out);
                return(null);
            }

            if (apis.Count == 0)
            {
                throw new InvalidOperationException("A .xml file must be specified.");
            }
            if (apis.Count != 1)
            {
                Console.Error.WriteLine("generator: Found {0} API descriptions; only one is supported", apis.Count);
                foreach (var api in apis)
                {
                    Console.Error.WriteLine("generator:   API description: {0}", api);
                }
                throw new InvalidOperationException("Only one .xml file may be specified.");
            }

            opts.ApiDescriptionFile = apis [0];

            return(opts);
        }
Exemple #3
0
        static void Run(CodeGeneratorOptions options, DirectoryAssemblyResolver resolver)
        {
            string assemblyQN              = options.AssemblyQualifiedName;
            string api_level               = options.ApiLevel;
            int    product_version         = options.ProductVersion;
            bool   preserve_enums          = options.PreserveEnums;
            string csdir                   = options.ManagedCallableWrapperSourceOutputDirectory ?? "cs";
            string javadir                 = "java";
            string enumdir                 = options.EnumOutputDirectory ?? "enum";
            string enum_metadata           = options.EnumMetadataOutputFile ?? "enummetadata";
            var    references              = options.AssemblyReferences;
            string enum_fields_map         = options.EnumFieldsMapFile;
            string enum_flags              = options.EnumFlagsFile;
            string enum_methods_map        = options.EnumMethodsMapFile;
            var    fixups                  = options.FixupFiles;
            var    annotations_zips        = options.AnnotationsZipFiles;
            string filename                = options.ApiDescriptionFile;
            string mapping_file            = options.MappingReportFile;
            bool   only_xml_adjuster       = options.OnlyRunApiXmlAdjuster;
            string api_xml_adjuster_output = options.ApiXmlAdjusterOutput;
            var    apiSource               = "";
            var    opt = new CodeGenerationOptions()
            {
                CodeGenerationTarget           = options.CodeGenerationTarget,
                UseGlobal                      = options.GlobalTypeNames,
                IgnoreNonPublicType            = true,
                UseShortFileNames              = options.UseShortFileNames,
                ProductVersion                 = options.ProductVersion,
                SupportInterfaceConstants      = options.SupportInterfaceConstants,
                SupportDefaultInterfaceMethods = options.SupportDefaultInterfaceMethods,
                SupportNestedInterfaceTypes    = options.SupportNestedInterfaceTypes,
                SupportNullableReferenceTypes  = options.SupportNullableReferenceTypes,
            };
            var resolverCache = new TypeDefinitionCache();

            // Load reference libraries

            foreach (var lib in options.LibraryPaths)
            {
                resolver.SearchDirectories.Add(lib);
            }
            foreach (var reference in references)
            {
                resolver.SearchDirectories.Add(Path.GetDirectoryName(reference));
            }

            // Figure out if this is class-parse
            string apiXmlFile    = filename;
            string apiSourceAttr = null;

            using (var xr = XmlReader.Create(filename)) {
                xr.MoveToContent();
                apiSourceAttr = xr.GetAttribute("api-source");
            }

            // We don't use shallow referenced types with class-parse because the Adjuster process
            // enumerates every ctor/method/property/field to build its model, so we will need
            // every type to be fully populated.
            opt.UseShallowReferencedTypes = apiSourceAttr != "class-parse";

            foreach (var reference in references.Distinct())
            {
                try {
                    Report.Verbose(0, "resolving assembly {0}.", reference);
                    var assembly = resolver.Load(reference);
                    foreach (var md in assembly.Modules)
                    {
                        foreach (var td in md.Types)
                        {
                            // FIXME: at some stage we want to import generic types.
                            // For now generator fails to load generic types that have conflicting type e.g.
                            // AdapterView`1 and AdapterView cannot co-exist.
                            // It is mostly because generator primarily targets jar (no real generics land).
                            var nonGenericOverload = td.HasGenericParameters
                                                                ? md.GetType(td.FullName.Substring(0, td.FullName.IndexOf('`')))
                                                                : null;
                            if (BindSameType(td, nonGenericOverload, resolverCache))
                            {
                                continue;
                            }
                            ProcessReferencedType(td, opt);
                        }
                    }
                } catch (Exception ex) {
                    Report.Warning(0, Report.WarningCodeGenerator + 0, ex, "failed to parse assembly {0}: {1}", reference, ex.Message);
                }
            }

            // For class-parse API description, transform it to jar2xml style.
            if (apiSourceAttr == "class-parse")
            {
                apiXmlFile = api_xml_adjuster_output ?? Path.Combine(Path.GetDirectoryName(filename), Path.GetFileName(filename) + ".adjusted");
                new Adjuster().Process(filename, opt, opt.SymbolTable.AllRegisteredSymbols(opt).OfType <GenBase> ().ToArray(), apiXmlFile, Report.Verbosity ?? 0);
            }
            if (only_xml_adjuster)
            {
                return;
            }

            // load XML API definition with fixups.

            Dictionary <string, EnumMappings.EnumDescription> enums = null;

            EnumMappings enummap = null;

            if (enum_fields_map != null || enum_methods_map != null)
            {
                enummap = new EnumMappings(enumdir, enum_metadata, api_level, preserve_enums);
                enums   = enummap.Process(enum_fields_map, enum_flags, enum_methods_map);
                fixups.Add(enum_metadata);
            }

            Parser         p    = new Parser(opt);
            List <GenBase> gens = p.Parse(apiXmlFile, fixups, api_level, product_version);

            if (gens == null)
            {
                return;
            }
            apiSource = p.ApiSource;

            // disable interface default methods here, especially before validation.
            gens = gens.Where(g => !g.IsObfuscated && g.Visibility != "private").ToList();
            foreach (var gen in gens)
            {
                gen.StripNonBindables(opt);
                if (gen.IsGeneratable)
                {
                    AddTypeToTable(opt, gen);
                }
            }

            // Apply fixups
            KotlinFixups.Fixup(gens);

            Validate(gens, opt, new CodeGeneratorContext());

            foreach (var api_versions_xml in options.ApiVersionsXmlFiles)
            {
                ApiVersionsSupport.AssignApiLevels(gens, api_versions_xml);
            }

            foreach (GenBase gen in gens)
            {
                gen.FillProperties();
            }

            var cache = new AncestorDescendantCache(gens);

            foreach (var gen in gens)
            {
                gen.UpdateEnums(opt, cache);
            }

            foreach (GenBase gen in gens)
            {
                gen.FixupMethodOverrides(opt);
            }

            foreach (GenBase gen in gens)
            {
                gen.FixupExplicitImplementation();
            }

            SealedProtectedFixups.Fixup(gens);

            GenerateAnnotationAttributes(gens, annotations_zips);

            //SymbolTable.Dump ();

            GenerationInfo gen_info = new GenerationInfo(csdir, javadir, assemblyQN);

            opt.AssemblyName = gen_info.Assembly;

            if (mapping_file != null)
            {
                GenerateMappingReportFile(gens, mapping_file);
            }

            new NamespaceMapping(gens).Generate(opt, gen_info);

            foreach (IGeneratable gen in gens)
            {
                if (gen.IsGeneratable)
                {
                    gen.Generate(opt, gen_info);
                }
            }


            ClassGen.GenerateTypeRegistrations(opt, gen_info);
            ClassGen.GenerateEnumList(gen_info);

            // Create the .cs files for the enums
            var enumFiles = enums == null
                                ? null
                                : enummap.WriteEnumerations(enumdir, enums, FlattenNestedTypes(gens).ToArray(), opt.UseShortFileNames);

            gen_info.GenerateLibraryProjectFile(options, enumFiles);
        }
        public static CodeGeneratorOptions Parse(string[] args)
        {
            var opts = new CodeGeneratorOptions();

            bool show_help = false;

            var parser = new OptionSet {
                "Usage: generator.exe OPTIONS+ API_DESCRIPTION [@RESPONSE-FILES]",
                "",
                "Generates C# source files to bind Java code described by API_DESCRIPTION.",
                "",
                "Copyright 2012 Xamarin, Inc.",
                "",
                "Options:",
                { "assembly=",
                  "Fully Qualified Assembly Name ({FQAN}) of the eventual assembly (.dll) that will be built.",
                  v => opts.AssemblyQualifiedName = v },
                { "codegen-target=",
                  "{STYLE} of Binding Assembly to generate",
                  v => opts.CodeGenerationTarget = ParseCodeGenerationTarget(v) },
                { "fixup=",
                  "XML {FILE} controlling the generated API.\n" +
                  "http://www.mono-project.com/GAPI#Altering_and_Extending_the_API_File",
                  v => opts.FixupFiles.Add(v) },
                { "global",
                  "Prefix type names with `global::`.",
                  v => opts.GlobalTypeNames = v != null },
                { "javadir=",
                  "Ignored; for compatibility.",
                  v => {} },
                { "L=",
                  "{PATH} to look for referenced assemblies..",
                  v => opts.LibraryPaths.Add(v) },
                { "o|csdir=",
                  "{DIRECTORY} to place C# source into.",
                  v => opts.ManagedCallableWrapperSourceOutputDirectory = v },
                { "public",
                  "Obsolete option. It binds only public types now",
                  v => opts.OnlyBindPublicTypes = v != null },
                { "r|ref=",
                  "{ASSEMBLY} to reference.",
                  v => opts.AssemblyReferences.Add(v) },
                { "sdk-platform|api-level=",
                  "SDK Platform {VERSION}/API level.",
                  v => opts.ApiLevel = v },
                { "lang-features=",
                  "For internal use. (Flags: interface-constants,default-interface-methods,nullable-reference-types)",
                  v => {
                      opts.SupportInterfaceConstants      = v?.Contains("interface-constants") == true;
                      opts.SupportDefaultInterfaceMethods = v?.Contains("default-interface-methods") == true;
                      opts.SupportNestedInterfaceTypes    = v?.Contains("nested-interface-types") == true;
                      opts.SupportNullableReferenceTypes  = v?.Contains("nullable-reference-types") == true;
                  } },
                { "preserve-enums",
                  "For internal use.",
                  v => opts.PreserveEnums = v != null },
                { "use-short-file-names",
                  "Generates short file name.",
                  v => opts.UseShortFileNames = v != null },
                { "product-version=",
                  "Xamarin.Android Major Product Version",
                  (int?v) => opts.ProductVersion = v.HasValue ? v.Value : 0 },
                { "v:",
                  "Logging Verbosity",
                  (int?v) => Report.Verbosity = v.HasValue ? v.Value : (Report.Verbosity ?? 0) + 1 },
                { "type-map-report=",
                  "Java-Managed Mapping report file.",
                  v => opts.MappingReportFile = v },
                { "only-xml-adjuster",
                  "Run only API XML adjuster for class-parse input.",
                  v => opts.OnlyRunApiXmlAdjuster = v != null },
                { "xml-adjuster-output=",
                  "specify API XML adjuster output XML for class-parse input.",
                  v => opts.ApiXmlAdjusterOutput = v },
                { "h|?|help",
                  "Show this message and exit.",
                  v => show_help = v != null },
                "",
                "Javadoc to C# Documentation Comments Support:",
                { "doc-comment-verbosity=",
                  "{STYLE} of C# documentation comments to emit.\n" +
                  "Defaults to `full`.  {STYLE} may be:\n" +
                  "  * `intellisense`: emit <summary>, <param>,\n" +
                  "    <returns>, <exception>.\n" +
                  "  * `full`: plus <remarks>, <seealso>, ...",
                  v => opts.XmldocStyle = ParseXmldocStyle(v) },
                { "with-javadoc-xml=",
                  "{PATH} to `api.xml` containing Javadoc docs in\n`<javadoc/>` elements",
                  v => opts.JavadocXmlFiles.Add(v) },
                "",
                "C# Enumeration Support:",
                { "enumdir=",
                  "{DIRECTORY} to write enumeration declarations.",
                  v => opts.EnumOutputDirectory = v },
                { "enumfields=",
                  "For internal use.",
                  v => opts.EnumFieldsMapFile = v },
                { "enumflags=",
                  "For internal use.",
                  v => opts.EnumFlagsFile = v },
                { "enummetadata=",
                  "XML {FILENAME} to create.",
                  v => opts.EnumMetadataOutputFile = v },
                { "enummethods=",
                  "For internal use.",
                  v => opts.EnumMethodsMapFile = v },
                { "apiversions=",
                  "For internal use.",
                  v => opts.ApiVersionsXmlFiles.Add(v) },
                { "annotations=",
                  "For internal use.",
                  v => opts.AnnotationsZipFiles.Add(v) },
                { "use-legacy-java-resolver",
                  "Uses the legacy ApiXmlAdjuster to resolve Java types, this is a *temporary* fallback in case there are unknown issues with JavaTypeSystem.",
                  v => opts.UseLegacyJavaResolver = v != null },
                new ResponseFileSource(),
            };

            var apis = parser.Parse(args);

            if (args.Length < 2 || show_help)
            {
                parser.WriteOptionDescriptions(Console.Out);
                return(null);
            }

            if (apis.Count == 0)
            {
                throw new InvalidOperationException("A .xml file must be specified.");
            }
            if (apis.Count != 1)
            {
                Console.Error.WriteLine("generator: Found {0} API descriptions; only one is supported", apis.Count);
                foreach (var api in apis)
                {
                    Console.Error.WriteLine("generator:   API description: {0}", api);
                }
                throw new InvalidOperationException("Only one .xml file may be specified.");
            }

            opts.ApiDescriptionFile = apis [0];

            if (opts.SupportDefaultInterfaceMethods && opts.CodeGenerationTarget == CodeGenerationTarget.XamarinAndroid)
            {
                Console.Error.WriteLine(Report.FormatCodedMessage(true, Report.ErrorInvalidDIMArgument));
                return(null);
            }

            return(opts);
        }