public override bool Execute()
        {
            Log.LogDebugMessage ("CheckTargetFrameworks Task");
            Log.LogDebugMessage ("  TargetFrameworkVersion: {0}", TargetFrameworkVersion);
            Log.LogDebugMessage ("  ProjectFile: {0}", ProjectFile);
            Log.LogDebugTaskItems ("  ResolvedUserAssemblies: {0}", ResolvedAssemblies);

            res = new DirectoryAssemblyResolver (Log.LogWarning, loadDebugSymbols: false);
            foreach (var assembly in ResolvedAssemblies) {
                res.Load (Path.GetFullPath (assembly.ItemSpec));
                var apiLevel = ExtractApiLevel (assembly);
                if (apiLevel > 0) {
                    Log.LogDebugMessage ("{0}={1}", Path.GetFileNameWithoutExtension (assembly.ItemSpec), apiLevel);
                    apiLevels.Add (assembly, apiLevel);
                }
            }

            var mainapiLevel = AndroidVersion.TryOSVersionToApiLevel (TargetFrameworkVersion);
            foreach (var item in apiLevels.Where (x => mainapiLevel < x.Value)) {
                var itemOSVersion = AndroidVersion.TryApiLevelToOSVersion (item.Value);
                Log.LogWarning (null, "XA0105", null, ProjectFile, 0, 0, 0, 0,
                    "The $(TargetFrameworkVersion) for {0} (v{1}) is greater than the $(TargetFrameworkVersion) for your project ({2}). " +
                    "You need to increase the $(TargetFrameworkVersion) for your project.", Path.GetFileName (item.Key.ItemSpec), itemOSVersion, TargetFrameworkVersion);
            }

            return !Log.HasLoggedErrors;
        }
        public override bool Execute()
        {
            Log.LogDebugMessage ("StripEmbeddedLibraries Task");
            Log.LogDebugTaskItems ("  Assemblies: ", Assemblies);

            var res = new DirectoryAssemblyResolver (Log.LogWarning, true);
            foreach (var assembly in Assemblies)
                res.Load (Path.GetFullPath (assembly.ItemSpec));

            foreach (var assemblyName in Assemblies) {
                var suffix = assemblyName.ItemSpec.EndsWith (".dll") ? String.Empty : ".dll";
                string hintPath = assemblyName.GetMetadata ("HintPath").Replace (Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
                string fileName = assemblyName.ItemSpec + suffix;
                if (!String.IsNullOrEmpty (hintPath) && !File.Exists (hintPath)) // ignore invalid HintPath
                    hintPath = null;
                string assemblyPath = String.IsNullOrEmpty (hintPath) ? fileName : hintPath;
                if (MonoAndroidHelper.IsFrameworkAssembly (fileName) && !MonoAndroidHelper.FrameworkEmbeddedJarLookupTargets.Contains (Path.GetFileName (fileName)))
                    continue;

                var assembly = res.GetAssembly (assemblyPath);
                bool assembly_modified = false;
                foreach (var mod in assembly.Modules) {
                    // embedded jars
                    var resjars = mod.Resources.Where (r => r.Name.EndsWith (".jar", StringComparison.InvariantCultureIgnoreCase)).Select (r => (EmbeddedResource) r);
                    foreach (var resjar in resjars.ToArray ()) {
                        Log.LogDebugMessage ("    Stripped {0}", resjar.Name);
                        mod.Resources.Remove (resjar);
                        assembly_modified = true;
                    }
                    // embedded AndroidNativeLibrary archive
                    var nativezip = mod.Resources.FirstOrDefault (r => r.Name == "__AndroidNativeLibraries__.zip") as EmbeddedResource;
                    if (nativezip != null) {
                        Log.LogDebugMessage ("    Stripped {0}", nativezip.Name);
                        mod.Resources.Remove (nativezip);
                        assembly_modified = true;
                    }
                    // embedded AndroidResourceLibrary archive
                    var reszip = mod.Resources.FirstOrDefault (r => r.Name == "__AndroidLibraryProjects__.zip") as EmbeddedResource;
                    if (reszip != null) {
                        Log.LogDebugMessage ("    Stripped {0}", reszip.Name);
                        mod.Resources.Remove (reszip);
                        assembly_modified = true;
                    }
                }
                if (assembly_modified) {
                    Log.LogDebugMessage ("    The stripped library is saved as {0}", assemblyPath);

                    // Output assembly needs to regenerate symbol file even if no IL/metadata was touched
                    // because Cecil still rewrites all assembly types in Cecil order (type A, nested types of A, type B, etc)
                    // and not in the original order causing symbols if original order doesn't match Cecil order
                    var wp = new WriterParameters () {
                        WriteSymbols = assembly.MainModule.HasSymbols
                    };

                    assembly.Write (assemblyPath, wp);
                }
            }
            return true;
        }
        // Extracts library project contents under e.g. obj/Debug/[__library_projects__/*.jar | res/*/*]
        void Extract(
            ICollection<string> jars,
            ICollection<string> resolvedResourceDirectories,
            ICollection<string> resolvedAssetDirectories,
            ICollection<string> resolvedEnvironments)
        {
            var outdir = new DirectoryInfo (OutputImportDirectory);
            if (!outdir.Exists)
                outdir.Create ();

            var res = new DirectoryAssemblyResolver (Log.LogWarning, loadDebugSymbols: false);
            foreach (var assembly in Assemblies)
                res.Load (assembly.ItemSpec);

            // FIXME: reorder references by import priority (not sure how to do that yet)
            foreach (var assemblyPath in Assemblies
                    .Select (a => GetTargetAssembly (a))
                    .Where (a => a != null)
                    .Distinct ()) {
                foreach (var imp in new string [] {imports_dir, "library_project_imports"}.Distinct ()) {
                    string assemblyIdentName = Path.GetFileNameWithoutExtension (assemblyPath);
                    if (UseShortFileNames) {
                        assemblyIdentName = Xamarin.Android.Tasks.MonoAndroidHelper.GetLibraryImportDirectoryNameForAssembly (assemblyIdentName);
                    }
                    string outDirForDll = Path.Combine (OutputImportDirectory, assemblyIdentName);
                    string importsDir = Path.Combine (outDirForDll, imp);
            #if SEPARATE_CRUNCH
                    // FIXME: review these binResDir thing and enable this. Eclipse does this.
                    // Enabling these blindly causes build failure on ActionBarSherlock.
                    //string binResDir = Path.Combine (importsDir, "bin", "res");
                    //string binAssemblyDir = Path.Combine (importsDir, "bin", "assets");
            #endif
                    string resDir = Path.Combine (importsDir, "res");
                    string assemblyDir = Path.Combine (importsDir, "assets");

                    // Skip already-extracted resources.
                    var stamp = new FileInfo (Path.Combine (outdir.FullName, assemblyIdentName + ".stamp"));
                    if (stamp.Exists && stamp.LastWriteTime > new FileInfo (assemblyPath).LastWriteTime) {
                        Log.LogDebugMessage ("Skipped resource lookup for {0}: extracted files are up to date", assemblyPath);
            #if SEPARATE_CRUNCH
                        // FIXME: review these binResDir/binAssemblyDir thing and enable this. Eclipse does this.
                        // Enabling these blindly causes build failure on ActionBarSherlock.
                        if (Directory.Exists (binResDir))
                            resolvedResourceDirectories.Add (binResDir);
                        if (Directory.Exists (binAssemblyDir))
                            resolvedAssetDirectories.Add (binAssemblyDir);
            #endif
                        if (Directory.Exists (resDir))
                            resolvedResourceDirectories.Add (resDir);
                        if (Directory.Exists (assemblyDir))
                            resolvedAssetDirectories.Add (assemblyDir);
                        continue;
                    }

                    if (Directory.Exists (outDirForDll))
                        Directory.Delete (outDirForDll, true);

                    Directory.CreateDirectory (importsDir);

                    var assembly = res.GetAssembly (assemblyPath);

                    foreach (var mod in assembly.Modules) {
                        // android environment files
                        foreach (var envtxt in mod.Resources
                                .Where (r => r.Name.StartsWith ("__AndroidEnvironment__", StringComparison.OrdinalIgnoreCase))
                                .Where (r => r is EmbeddedResource)
                                .Cast<EmbeddedResource> ()) {
                            if (!Directory.Exists (outDirForDll))
                                Directory.CreateDirectory (outDirForDll);
                            var finfo = new FileInfo (Path.Combine (outDirForDll, envtxt.Name));
                            using (var fs = finfo.Create ()) {
                                var data = envtxt.GetResourceData ();
                                fs.Write (data, 0, data.Length);
                            }
                            resolvedEnvironments.Add (finfo.FullName);
                        }

                        // embedded jars (EmbeddedJar, EmbeddedReferenceJar)
                        var resjars = mod.Resources
                            .Where (r => r.Name.EndsWith (".jar", StringComparison.InvariantCultureIgnoreCase))
                            .Select (r => (EmbeddedResource) r);
                        foreach (var resjar in resjars) {
                            var data = resjar.GetResourceData ();
                            using (var outfs = File.Create (Path.Combine (importsDir, resjar.Name)))
                                outfs.Write (data, 0, data.Length);
                        }

                        // embedded AndroidResourceLibrary archive
                        var reszip = mod.Resources.FirstOrDefault (r => r.Name == "__AndroidLibraryProjects__.zip") as EmbeddedResource;
                        if (reszip != null) {
                            if (!Directory.Exists (outDirForDll))
                                Directory.CreateDirectory (outDirForDll);
                            var finfo = new FileInfo (Path.Combine (outDirForDll, reszip.Name));
                            using (var fs = finfo.Create ()) {
                                var data = reszip.GetResourceData ();
                                fs.Write (data, 0, data.Length);
                            }

                            // temporarily extracted directory will look like:
                            //    __library_projects__/[dllname]/[library_project_imports | jlibs]/bin
                            using (var zip = new ZipFile (finfo.FullName)) {
                                Files.ExtractAll (zip, outDirForDll);
                            }

                            // We used to *copy* the resources to overwrite other resources,
                            // which resulted in missing resource issue.
                            // Here we replaced copy with use of '-S' option and made it to work.
            #if SEPARATE_CRUNCH
                            // FIXME: review these binResDir/binAssemblyDir thing and enable this. Eclipse does this.
                            // Enabling these blindly causes build failure on ActionBarSherlock.
                            if (Directory.Exists (binResDir))
                                resolvedResourceDirectories.Add (binResDir);
                            if (Directory.Exists (binAssemblyDir))
                                resolvedAssetDirectories.Add (binAssemblyDir);
            #endif
                            if (Directory.Exists (resDir))
                                resolvedResourceDirectories.Add (resDir);
                            if (Directory.Exists (assemblyDir))
                                resolvedAssetDirectories.Add (assemblyDir);

                            finfo.Delete ();
                        }
                    }

                    stamp.Create ().Close ();
                }
            }

            foreach (var f in outdir.GetFiles ("*.jar")
                    .Select (fi => fi.FullName))
                jars.Add (f);
        }
Example #4
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()
            {
                ApiXmlFile                     = options.ApiDescriptionFile,
                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, new XmlReaderSettings {
                XmlResolver = null
            })) {
                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.LogCodedWarning(0, Report.WarningAssemblyParseFailure, ex, 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);
            JavadocFixups.Fixup(gens, options);

            //SymbolTable.Dump ();

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

            opt.AssemblyName = gen_info.Assembly;

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

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

            new NamespaceMapping(gens).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);
        }
Example #5
0
        void Run(DirectoryAssemblyResolver res)
        {
            PackageNamingPolicy pnp;

            JniType.PackageNamingPolicy = Enum.TryParse(PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseHash;
            var temp = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());

            Directory.CreateDirectory(temp);

            var selectedWhitelistAssemblies = new List <string> ();

            // Put every assembly we'll need in the resolver
            foreach (var assembly in ResolvedAssemblies)
            {
                res.Load(Path.GetFullPath(assembly.ItemSpec));
                if (MonoAndroidHelper.FrameworkAttributeLookupTargets.Any(a => Path.GetFileName(assembly.ItemSpec) == a))
                {
                    selectedWhitelistAssemblies.Add(Path.GetFullPath(assembly.ItemSpec));
                }
            }

            // However we only want to look for JLO types in user code
            var assemblies  = ResolvedUserAssemblies.Select(p => p.ItemSpec).ToList();
            var fxAdditions = MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies(ResolvedAssemblies)
                              .Where(a => assemblies.All(x => Path.GetFileName(x) != Path.GetFileName(a)));

            assemblies = assemblies.Concat(fxAdditions).ToList();

            // Step 1 - Find all the JLO types
            var all_java_types = JavaTypeScanner.GetJavaTypes(assemblies, res, Log.LogWarning);

            WriteTypeMappings(all_java_types);

            var java_types = all_java_types.Where(t => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(t));

            // Step 2 - Generate Java stub code
            var keep_going = Generator.CreateJavaSources(
                Log,
                java_types,
                temp,
                ApplicationJavaClass,
                UseSharedRuntime,
                int.Parse(AndroidSdkPlatform) <= 10,
                ResolvedAssemblies.Any(assembly => Path.GetFileName(assembly.ItemSpec) == "Mono.Android.Export.dll"));

            var temp_map_file = Path.Combine(temp, "acw-map.temp");

            // We need to save a map of .NET type -> ACW type for resource file fixups
            var managed = new Dictionary <string, TypeDefinition> ();
            var java    = new Dictionary <string, TypeDefinition> ();
            var acw_map = new StreamWriter(temp_map_file);

            foreach (var type in java_types)
            {
                string managedKey = type.FullName.Replace('/', '.');
                string javaKey    = JniType.ToJniName(type).Replace('/', '.');

                acw_map.WriteLine("{0};{1}", type.GetPartialAssemblyQualifiedName(), javaKey);
                acw_map.WriteLine("{0};{1}", type.GetAssemblyQualifiedName(), javaKey);

                TypeDefinition conflict;
                if (managed.TryGetValue(managedKey, out conflict))
                {
                    Log.LogWarning(
                        "Duplicate managed type found! Mappings between managed types and Java types must be unique. " +
                        "First Type: '{0}'; Second Type: '{1}'.",
                        conflict.GetAssemblyQualifiedName(),
                        type.GetAssemblyQualifiedName());
                    Log.LogWarning(
                        "References to the type '{0}' will refer to '{1}'.",
                        managedKey, conflict.GetAssemblyQualifiedName());
                    continue;
                }
                if (java.TryGetValue(javaKey, out conflict))
                {
                    Log.LogError(
                        "Duplicate Java type found! Mappings between managed types and Java types must be unique. " +
                        "First Type: '{0}'; Second Type: '{1}'",
                        conflict.GetAssemblyQualifiedName(),
                        type.GetAssemblyQualifiedName());
                    keep_going = false;
                    continue;
                }
                managed.Add(managedKey, type);
                java.Add(javaKey, type);
                acw_map.WriteLine("{0};{1}", managedKey, javaKey);
                acw_map.WriteLine("{0};{1}", JniType.ToCompatJniName(type).Replace('/', '.'), javaKey);
            }

            acw_map.Close();

            //The previous steps found an error, so we must abort and not generate any further output
            //We must do so subsequent unchanged builds fail too.
            if (!keep_going)
            {
                File.Delete(temp_map_file);
                return;
            }

            MonoAndroidHelper.CopyIfChanged(temp_map_file, AcwMapFile);

            try { File.Delete(temp_map_file); } catch (Exception) { }

            // Only overwrite files if the contents actually changed
            foreach (var file in Directory.GetFiles(temp, "*", SearchOption.AllDirectories))
            {
                var dest = Path.GetFullPath(Path.Combine(OutputDirectory, "src", file.Substring(temp.Length + 1)));

                MonoAndroidHelper.CopyIfChanged(file, dest);
            }

            // Step 3 - Merge [Activity] and friends into AndroidManifest.xml
            var manifest = new ManifestDocument(ManifestTemplate, this.Log);

            manifest.PackageName     = PackageName;
            manifest.ApplicationName = ApplicationName ?? PackageName;
            manifest.Assemblies.AddRange(assemblies);
            manifest.Resolver      = res;
            manifest.SdkDir        = AndroidSdkDir;
            manifest.SdkVersion    = AndroidSdkPlatform;
            manifest.Debug         = Debug;
            manifest.NeedsInternet = NeedsInternet;

            var additionalProviders = manifest.Merge(all_java_types, selectedWhitelistAssemblies, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments);

            var temp_manifest = Path.Combine(temp, "AndroidManifest.xml");
            var real_manifest = Path.GetFullPath(MergedAndroidManifestOutput);

            manifest.Save(temp_manifest);

            // Only write the new manifest if it actually changed
            MonoAndroidHelper.CopyIfChanged(temp_manifest, real_manifest);

            // Create additional runtime provider java sources.
            string providerTemplateFile = UseSharedRuntime ? "MonoRuntimeProvider.Shared.java" : "MonoRuntimeProvider.Bundled.java";
            string providerTemplate     = new StreamReader(typeof(JavaCallableWrapperGenerator).Assembly.GetManifestResourceStream(providerTemplateFile)).ReadToEnd();

            foreach (var provider in additionalProviders)
            {
                var temp_provider = Path.Combine(temp, provider + ".java");
                File.WriteAllText(temp_provider, providerTemplate.Replace("MonoRuntimeProvider", provider));
                var real_provider_dir = Path.GetFullPath(Path.Combine(OutputDirectory, "src", "mono"));
                Directory.CreateDirectory(real_provider_dir);
                var real_provider = Path.Combine(real_provider_dir, provider + ".java");
                MonoAndroidHelper.CopyIfChanged(temp_provider, real_provider);
            }

            // Create additional application java sources.

            Action <string, string, string, Func <string, string> > save = (resource, filename, destDir, applyTemplate) => {
                string temp_file = Path.Combine(temp, filename);
                string template  = applyTemplate(new StreamReader(typeof(GenerateJavaStubs).Assembly.GetManifestResourceStream(resource)).ReadToEnd());
                File.WriteAllText(temp_file, template);
                Directory.CreateDirectory(destDir);
                var real_file = Path.Combine(destDir, filename);
                MonoAndroidHelper.CopyIfChanged(temp_file, real_file);
            };

            StringWriter regCallsWriter = new StringWriter();

            regCallsWriter.WriteLine("\t\t// Application and Instrumentation ACWs must be registered first.");
            foreach (var type in java_types)
            {
                if (JniType.IsApplication(type) || JniType.IsInstrumentation(type))
                {
                    string javaKey = JniType.ToJniName(type).Replace('/', '.');
                    regCallsWriter.WriteLine("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);",
                                             type.GetAssemblyQualifiedName(), javaKey);
                }
            }
            regCallsWriter.Close();

            var    real_app_dir            = Path.GetFullPath(Path.Combine(OutputDirectory, "src", "mono", "android", "app"));
            string applicationTemplateFile = "ApplicationRegistration.java";

            save(applicationTemplateFile, applicationTemplateFile, real_app_dir,
                 template => template.Replace("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString()));

            // Create NotifyTimeZoneChanges java sources.
            string notifyTimeZoneChangesFile = "NotifyTimeZoneChanges.java";

            save(notifyTimeZoneChangesFile, notifyTimeZoneChangesFile, real_app_dir, template => template);

            // Delete our temp directory
            try { Directory.Delete(temp, true); } catch (Exception) { }
        }
Example #6
0
        void ResolveI18nAssembly(DirectoryAssemblyResolver resolver, string name, Dictionary <string, string> assemblies)
        {
            var assembly = resolver.Resolve(AssemblyNameReference.Parse(name));

            assemblies [name] = Path.GetFullPath(assembly.MainModule.FileName);
        }
        // Extracts library project contents under e.g. obj/Debug/[__library_projects__/*.jar | res/*/*]
        void Extract(
            ICollection <string> jars,
            ICollection <string> resolvedResourceDirectories,
            ICollection <string> resolvedAssetDirectories,
            ICollection <string> resolvedEnvironments)
        {
            var outdir = new DirectoryInfo(OutputImportDirectory);

            if (!outdir.Exists)
            {
                outdir.Create();
            }

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

            foreach (var assembly in Assemblies)
            {
                res.Load(assembly.ItemSpec);
            }

            // FIXME: reorder references by import priority (not sure how to do that yet)
            foreach (var assemblyPath in Assemblies
                     .Select(a => GetTargetAssembly(a))
                     .Where(a => a != null)
                     .Distinct())
            {
                foreach (var imp in new string [] { imports_dir, "library_project_imports" }.Distinct())
                {
                    string assemblyIdentName = Path.GetFileNameWithoutExtension(assemblyPath);
                    if (UseShortFileNames)
                    {
                        assemblyIdentName = Xamarin.Android.Tasks.MonoAndroidHelper.GetLibraryImportDirectoryNameForAssembly(assemblyIdentName);
                    }
                    string outDirForDll = Path.Combine(OutputImportDirectory, assemblyIdentName);
                    string importsDir   = Path.Combine(outDirForDll, imp);
#if SEPARATE_CRUNCH
                    // FIXME: review these binResDir thing and enable this. Eclipse does this.
                    // Enabling these blindly causes build failure on ActionBarSherlock.
                    //string binResDir = Path.Combine (importsDir, "bin", "res");
                    //string binAssemblyDir = Path.Combine (importsDir, "bin", "assets");
#endif
                    string resDir      = Path.Combine(importsDir, "res");
                    string assemblyDir = Path.Combine(importsDir, "assets");

                    // Skip already-extracted resources.
                    var stamp = new FileInfo(Path.Combine(outdir.FullName, assemblyIdentName + ".stamp"));
                    if (stamp.Exists && stamp.LastWriteTime > new FileInfo(assemblyPath).LastWriteTime)
                    {
                        Log.LogDebugMessage("Skipped resource lookup for {0}: extracted files are up to date", assemblyPath);
#if SEPARATE_CRUNCH
                        // FIXME: review these binResDir/binAssemblyDir thing and enable this. Eclipse does this.
                        // Enabling these blindly causes build failure on ActionBarSherlock.
                        if (Directory.Exists(binResDir))
                        {
                            resolvedResourceDirectories.Add(binResDir);
                        }
                        if (Directory.Exists(binAssemblyDir))
                        {
                            resolvedAssetDirectories.Add(binAssemblyDir);
                        }
#endif
                        if (Directory.Exists(resDir))
                        {
                            resolvedResourceDirectories.Add(resDir);
                        }
                        if (Directory.Exists(assemblyDir))
                        {
                            resolvedAssetDirectories.Add(assemblyDir);
                        }
                        continue;
                    }

                    if (Directory.Exists(outDirForDll))
                    {
                        Directory.Delete(outDirForDll, true);
                    }

                    Directory.CreateDirectory(importsDir);

                    var assembly = res.GetAssembly(assemblyPath);

                    foreach (var mod in assembly.Modules)
                    {
                        // android environment files
                        foreach (var envtxt in mod.Resources
                                 .Where(r => r.Name.StartsWith("__AndroidEnvironment__", StringComparison.OrdinalIgnoreCase))
                                 .Where(r => r is EmbeddedResource)
                                 .Cast <EmbeddedResource> ())
                        {
                            if (!Directory.Exists(outDirForDll))
                            {
                                Directory.CreateDirectory(outDirForDll);
                            }
                            var finfo = new FileInfo(Path.Combine(outDirForDll, envtxt.Name));
                            using (var fs = finfo.Create()) {
                                var data = envtxt.GetResourceData();
                                fs.Write(data, 0, data.Length);
                            }
                            resolvedEnvironments.Add(finfo.FullName);
                        }

                        // embedded jars (EmbeddedJar, EmbeddedReferenceJar)
                        var resjars = mod.Resources
                                      .Where(r => r.Name.EndsWith(".jar", StringComparison.InvariantCultureIgnoreCase))
                                      .Select(r => (EmbeddedResource)r);
                        foreach (var resjar in resjars)
                        {
                            var data = resjar.GetResourceData();
                            using (var outfs = File.Create(Path.Combine(importsDir, resjar.Name)))
                                outfs.Write(data, 0, data.Length);
                        }

                        // embedded AndroidResourceLibrary archive
                        var reszip = mod.Resources.FirstOrDefault(r => r.Name == "__AndroidLibraryProjects__.zip") as EmbeddedResource;
                        if (reszip != null)
                        {
                            if (!Directory.Exists(outDirForDll))
                            {
                                Directory.CreateDirectory(outDirForDll);
                            }
                            var finfo = new FileInfo(Path.Combine(outDirForDll, reszip.Name));
                            using (var fs = finfo.Create()) {
                                var data = reszip.GetResourceData();
                                fs.Write(data, 0, data.Length);
                            }

                            // temporarily extracted directory will look like:
                            //    __library_projects__/[dllname]/[library_project_imports | jlibs]/bin
                            using (var zip = new ZipFile(finfo.FullName)) {
                                Files.ExtractAll(zip, outDirForDll);
                            }

                            // We used to *copy* the resources to overwrite other resources,
                            // which resulted in missing resource issue.
                            // Here we replaced copy with use of '-S' option and made it to work.
#if SEPARATE_CRUNCH
                            // FIXME: review these binResDir/binAssemblyDir thing and enable this. Eclipse does this.
                            // Enabling these blindly causes build failure on ActionBarSherlock.
                            if (Directory.Exists(binResDir))
                            {
                                resolvedResourceDirectories.Add(binResDir);
                            }
                            if (Directory.Exists(binAssemblyDir))
                            {
                                resolvedAssetDirectories.Add(binAssemblyDir);
                            }
#endif
                            if (Directory.Exists(resDir))
                            {
                                resolvedResourceDirectories.Add(resDir);
                            }
                            if (Directory.Exists(assemblyDir))
                            {
                                resolvedAssetDirectories.Add(assemblyDir);
                            }

                            finfo.Delete();
                        }
                    }

                    stamp.Create().Close();
                }
            }

            foreach (var f in outdir.GetFiles("*.jar")
                     .Select(fi => fi.FullName))
            {
                jars.Add(f);
            }
        }
 public FixAbstractMethodsStep(DirectoryAssemblyResolver resolver, TypeDefinitionCache cache, TaskLoggingHelper logger)
     : base(cache)
 {
     this.resolver = resolver;
     this.logger   = logger;
 }
Example #9
0
        AssemblyDefinition ResolveRuntimeAssemblyForReferenceAssembly(LockFile lockFile, DirectoryAssemblyResolver resolver, string assemblyPath)
        {
            if (string.IsNullOrEmpty(TargetMoniker))
            {
                return(null);
            }

            var framework = NuGetFramework.Parse(TargetMoniker);

            if (framework == null)
            {
                LogWarning($"Could not parse '{TargetMoniker}'");
                return(null);
            }
            var target = lockFile.GetTarget(framework, string.Empty);

            if (target == null)
            {
                LogWarning($"Could not resolve target for '{TargetMoniker}'");
                return(null);
            }
            foreach (var folder in lockFile.PackageFolders)
            {
                var path        = assemblyPath.Replace(folder.Path, string.Empty);
                var libraryPath = lockFile.Libraries.FirstOrDefault(x => path.StartsWith(x.Path.Replace('/', Path.DirectorySeparatorChar), StringComparison.OrdinalIgnoreCase));
                if (libraryPath == null)
                {
                    continue;
                }
                var library = target.Libraries.FirstOrDefault(x => String.Compare(x.Name, libraryPath.Name, StringComparison.OrdinalIgnoreCase) == 0);
                if (libraryPath == null)
                {
                    continue;
                }
                var runtime = library.RuntimeAssemblies.FirstOrDefault();
                if (runtime == null)
                {
                    continue;
                }
                path = Path.Combine(folder.Path, libraryPath.Path, runtime.Path).Replace('/', Path.DirectorySeparatorChar);
                if (!File.Exists(path))
                {
                    continue;
                }
                LogDebugMessage($"Attempting to load {path}");
                return(resolver.Load(path, forceLoad: true));
            }
            return(null);
        }
        string ResolveI18nAssembly(DirectoryAssemblyResolver resolver, string name)
        {
            var assembly = resolver.Resolve(AssemblyNameReference.Parse(name));

            return(Path.GetFullPath(assembly.MainModule.FullyQualifiedName));
        }
 public override bool Execute()
 {
     using (var resolver = new DirectoryAssemblyResolver(Log.LogWarning, loadDebugSymbols: false)) {
         return(Execute(resolver));
     }
 }
Example #12
0
        // Extracts library project contents under e.g. obj/Debug/[__library_projects__/*.jar | res/*/*]
        // Extracts library project contents under e.g. obj/Debug/[lp/*.jar | res/*/*]
        public override bool Execute()
        {
            var jars = new Dictionary <string, ITaskItem> ();
            var resolvedResourceDirectories = new List <ITaskItem> ();
            var resolvedAssetDirectories    = new List <ITaskItem> ();
            var resolvedEnvironmentFiles    = new List <ITaskItem> ();

            assemblyMap.Load(AssemblyIdentityMapFile);
            assembliesToSkipCaseFixup  = new HashSet <string> (StringComparer.OrdinalIgnoreCase);
            assembliestoSkipExtraction = new HashSet <string> (StringComparer.OrdinalIgnoreCase);
            bool metaDataValue;

            foreach (var asm in Assemblies)
            {
                if (bool.TryParse(asm.GetMetadata(AndroidSkipResourceProcessing), out metaDataValue) && metaDataValue)
                {
                    assembliesToSkipCaseFixup.Add(asm.ItemSpec);
                }
                if (bool.TryParse(asm.GetMetadata(GetAdditionalResourcesFromAssemblies.AndroidSkipResourceExtraction), out metaDataValue) && metaDataValue)
                {
                    assembliestoSkipExtraction.Add(asm.ItemSpec);
                }
            }

            using (var resolver = new DirectoryAssemblyResolver(this.CreateTaskLogger(), loadDebugSymbols: false)) {
                try {
                    Extract(resolver, jars, resolvedResourceDirectories, resolvedAssetDirectories, resolvedEnvironmentFiles);
                } catch (ZipIOException ex) {
                    Log.LogCodedError("XA1004", ex.Message);
                    Log.LogDebugMessage(ex.ToString());
                }
            }

            Jars = jars.Values.ToArray();
            ResolvedResourceDirectories = resolvedResourceDirectories.ToArray();
            ResolvedAssetDirectories    = resolvedAssetDirectories.ToArray();
            ResolvedEnvironmentFiles    = resolvedEnvironmentFiles.ToArray();

            ResolvedResourceDirectoryStamps = ResolvedResourceDirectories
                                              .Select(s => new TaskItem(Path.GetFullPath(Path.Combine(s.ItemSpec, "../..")) + ".stamp"))
                                              .ToArray();

            foreach (var directory in ResolvedResourceDirectories)
            {
                MonoAndroidHelper.SetDirectoryWriteable(directory.ItemSpec);
            }

            foreach (var directory in ResolvedAssetDirectories)
            {
                MonoAndroidHelper.SetDirectoryWriteable(directory.ItemSpec);
            }

            if (!string.IsNullOrEmpty(CacheFile))
            {
                var document = new XDocument(
                    new XDeclaration("1.0", "UTF-8", null),
                    new XElement("Paths",
                                 new XElement("Jars",
                                              Jars.Select(e => new XElement("Jar", e))),
                                 new XElement("ResolvedResourceDirectories",
                                              XDocumentExtensions.ToXElements(ResolvedResourceDirectories, "ResolvedResourceDirectory", knownMetadata)
                                              ),
                                 new XElement("ResolvedAssetDirectories",
                                              XDocumentExtensions.ToXElements(ResolvedAssetDirectories, "ResolvedAssetDirectory", knownMetadata)),
                                 new XElement("ResolvedEnvironmentFiles",
                                              XDocumentExtensions.ToXElements(ResolvedEnvironmentFiles, "ResolvedEnvironmentFile", knownMetadata)),
                                 new XElement("ResolvedResourceDirectoryStamps",
                                              XDocumentExtensions.ToXElements(ResolvedResourceDirectoryStamps, "ResolvedResourceDirectoryStamp", knownMetadata))
                                 ));
                document.SaveIfChanged(CacheFile);
            }

            assemblyMap.Save(AssemblyIdentityMapFile);

            Log.LogDebugTaskItems("  Jars: ", Jars);
            Log.LogDebugTaskItems("  ResolvedResourceDirectories: ", ResolvedResourceDirectories);
            Log.LogDebugTaskItems("  ResolvedAssetDirectories: ", ResolvedAssetDirectories);
            Log.LogDebugTaskItems("  ResolvedEnvironmentFiles: ", ResolvedEnvironmentFiles);
            Log.LogDebugTaskItems("  ResolvedResourceDirectoryStamps: ", ResolvedResourceDirectoryStamps);

            return(!Log.HasLoggedErrors);
        }
Example #13
0
        public override bool Execute()
        {
            LogDebugMessage("GetAdditionalResourcesFromAssemblies Task");
            LogDebugMessage("  AndroidSdkDirectory: {0}", AndroidSdkDirectory);
            LogDebugMessage("  AndroidNdkDirectory: {0}", AndroidNdkDirectory);
            LogDebugTaskItems("  Assemblies: ", Assemblies);

            if (Environment.GetEnvironmentVariable("XA_DL_IGNORE_CERT_ERRROS") == "yesyesyes")
            {
                ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
                LogDebugMessage("    Disabling download certificate validation callback.");
            }
            var androidResources = new HashSet <string> ();
            var javaLibraries    = new HashSet <string> ();
            var nativeLibraries  = new HashSet <string> ();
            var assemblies       = new HashSet <string> ();

            if (Assemblies == null)
            {
                return(true);
            }

            System.Threading.Tasks.Task.Run(() => {
                // The cache location can be overriden by the (to be documented) XAMARIN_CACHEPATH
                CachePath = Environment.ExpandEnvironmentVariables(CachePathEnvironmentVar);
                CachePath = CachePath != CachePathEnvironmentVar
                                ? CachePath
                                : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), CacheBaseDir);

                using (var resolver = new DirectoryAssemblyResolver(this.CreateTaskLogger(), loadDebugSymbols: false)) {
                    foreach (var assemblyItem in Assemblies)
                    {
                        string fullPath = Path.GetFullPath(assemblyItem.ItemSpec);
                        if (assemblies.Contains(fullPath))
                        {
                            LogDebugMessage("  Skip assembly: {0}, it was already processed", fullPath);
                            continue;
                        }
                        assemblies.Add(fullPath);
                        resolver.Load(fullPath);
                        // Append source file name (without the Xamarin. prefix or extension) to the base folder
                        // This would help avoid potential collisions.
                        foreach (var ca in resolver.GetAssembly(assemblyItem.ItemSpec).CustomAttributes)
                        {
                            switch (ca.AttributeType.FullName)
                            {
                            case "Android.IncludeAndroidResourcesFromAttribute":
                                AddAttributeValue(androidResources, ca, "XA5206", "{0}. Android resource directory {1} doesn't exist.", true, fullPath);
                                break;

                            case "Java.Interop.JavaLibraryReferenceAttribute":
                                AddAttributeValue(javaLibraries, ca, "XA5207", "{0}. Java library file {1} doesn't exist.", false, fullPath);
                                break;

                            case "Android.NativeLibraryReferenceAttribute":
                                AddAttributeValue(nativeLibraries, ca, "XA5210", "{0}. Native library file {1} doesn't exist.", false, fullPath);
                                break;
                            }
                        }
                    }
                }
            }).ContinueWith((t) => {
                if (t.Exception != null)
                {
                    Log.LogErrorFromException(t.Exception.GetBaseException());
                }
                Complete();
            });

            var result = base.Execute();

            if (!result || Log.HasLoggedErrors)
            {
                if (File.Exists(CacheFile))
                {
                    File.Delete(CacheFile);
                }
                return(false);
            }

            var AdditionalAndroidResourcePaths    = androidResources.ToArray();
            var AdditionalJavaLibraryReferences   = javaLibraries.ToArray();
            var AdditionalNativeLibraryReferences = nativeLibraries
                                                    .Where(x => MonoAndroidHelper.GetNativeLibraryAbi(x) != null)
                                                    .ToArray();

            var document = new XDocument(
                new XDeclaration("1.0", "UTF-8", null),
                new XElement("Paths",
                             new XElement("AdditionalAndroidResourcePaths",
                                          AdditionalAndroidResourcePaths.Select(e => new XElement("AdditionalAndroidResourcePath", e))),
                             new XElement("AdditionalJavaLibraryReferences",
                                          AdditionalJavaLibraryReferences.Select(e => new XElement("AdditionalJavaLibraryReference", e))),
                             new XElement("AdditionalNativeLibraryReferences",
                                          AdditionalNativeLibraryReferences.Select(e => new XElement("AdditionalNativeLibraryReference", e)))
                             ));

            document.Save(CacheFile);

            LogDebugTaskItems("  AdditionalAndroidResourcePaths: ", AdditionalAndroidResourcePaths);
            LogDebugTaskItems("  AdditionalJavaLibraryReferences: ", AdditionalJavaLibraryReferences);
            LogDebugTaskItems("  AdditionalNativeLibraryReferences: ", AdditionalNativeLibraryReferences);

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

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

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

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

            var skiplist = new List <string> ();

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

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

            options.SkippedAssemblies = skiplist;

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

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

                var copydst = OptionalDestinationDirectory ?? OutputDirectory;

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

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

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

            return(true);
        }
Example #15
0
        public override bool RunTask()
        {
            if (SourceFiles.Length != DestinationFiles.Length)
            {
                throw new ArgumentException("source and destination count mismatch");
            }

            var readerParameters = new ReaderParameters {
                ReadSymbols = true,
            };
            var writerParameters = new WriterParameters {
                DeterministicMvid = true,
            };

            using (var resolver = new DirectoryAssemblyResolver(this.CreateTaskLogger(), loadDebugSymbols: true, loadReaderParameters: readerParameters)) {
                // Add SearchDirectories with ResolvedAssemblies
                foreach (var assembly in ResolvedAssemblies)
                {
                    var path = Path.GetFullPath(Path.GetDirectoryName(assembly.ItemSpec));
                    if (!resolver.SearchDirectories.Contains(path))
                    {
                        resolver.SearchDirectories.Add(path);
                    }
                }

                // Run the FixAbstractMethodsStep
                var step = new FixAbstractMethodsStep(resolver, Log);
                for (int i = 0; i < SourceFiles.Length; i++)
                {
                    var source      = SourceFiles [i];
                    var destination = DestinationFiles [i];

                    // Only run the step on "MonoAndroid" assemblies
                    if (MonoAndroidHelper.IsMonoAndroidAssembly(source) && !MonoAndroidHelper.IsSharedRuntimeAssembly(source.ItemSpec))
                    {
                        var assemblyDefinition = resolver.GetAssembly(source.ItemSpec);
                        if (step.FixAbstractMethods(assemblyDefinition))
                        {
                            Log.LogDebugMessage($"Saving modified assembly: {destination.ItemSpec}");
                            writerParameters.WriteSymbols = assemblyDefinition.MainModule.HasSymbols;
                            assemblyDefinition.Write(destination.ItemSpec, writerParameters);
                            continue;
                        }
                    }

                    if (MonoAndroidHelper.CopyAssemblyAndSymbols(source.ItemSpec, destination.ItemSpec))
                    {
                        Log.LogDebugMessage($"Copied: {destination.ItemSpec}");
                    }
                    else
                    {
                        Log.LogDebugMessage($"Skipped unchanged file: {destination.ItemSpec}");

                        // NOTE: We still need to update the timestamp on this file, or this target would run again
                        File.SetLastWriteTimeUtc(destination.ItemSpec, DateTime.UtcNow);
                    }
                }
            }

            return(!Log.HasLoggedErrors);
        }
Example #16
0
 public FixAbstractMethodsStep(DirectoryAssemblyResolver resolver, TaskLoggingHelper logger)
 {
     this.resolver = resolver;
     this.logger   = logger;
 }
        void Run()
        {
            PackageNamingPolicy pnp;
            JniType.PackageNamingPolicy = Enum.TryParse (PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseHash;
            var temp = Path.Combine (Path.GetTempPath (), Path.GetRandomFileName ());
            Directory.CreateDirectory (temp);

            // We're going to do 3 steps here instead of separate tasks so
            // we can share the list of JLO TypeDefinitions between them
            var res = new DirectoryAssemblyResolver (Log.LogWarning, loadDebugSymbols:true);

            var selectedWhitelistAssemblies = new List<string> ();

            // Put every assembly we'll need in the resolver
            foreach (var assembly in ResolvedAssemblies) {
                res.Load (Path.GetFullPath (assembly.ItemSpec));
                if (MonoAndroidHelper.FrameworkAttributeLookupTargets.Any (a => Path.GetFileName (assembly.ItemSpec) == a))
                    selectedWhitelistAssemblies.Add (Path.GetFullPath (assembly.ItemSpec));
            }

            // However we only want to look for JLO types in user code
            var assemblies = ResolvedUserAssemblies.Select (p => p.ItemSpec).ToList ();
            var fxAdditions = MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies (ResolvedAssemblies)
                .Where (a => assemblies.All (x => Path.GetFileName (x) != Path.GetFileName (a)));
            assemblies = assemblies.Concat (fxAdditions).ToList ();

            // Step 1 - Find all the JLO types
            var all_java_types = JavaTypeScanner.GetJavaTypes (assemblies, res, Log.LogWarning);

            WriteTypeMappings (all_java_types);

            var java_types = all_java_types.Where (t => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration (t));

            // Step 2 - Generate Java stub code
            var keep_going = Generator.CreateJavaSources (
                Log,
                java_types,
                temp,
                UseSharedRuntime,
                int.Parse (AndroidSdkPlatform) <= 10,
                ResolvedAssemblies.Any (assembly => Path.GetFileName (assembly.ItemSpec) == "Mono.Android.Export.dll"));

            var temp_map_file = Path.Combine (temp, "acw-map.temp");

            // We need to save a map of .NET type -> ACW type for resource file fixups
            var managed = new Dictionary<string, TypeDefinition> ();
            var java    = new Dictionary<string, TypeDefinition> ();
            var acw_map = new StreamWriter (temp_map_file);

            foreach (var type in java_types) {
                string managedKey = type.FullName.Replace ('/', '.');
                string javaKey    = JniType.ToJniName (type).Replace ('/', '.');

                acw_map.WriteLine ("{0};{1}", type.GetPartialAssemblyQualifiedName (), javaKey);
                acw_map.WriteLine ("{0};{1}", type.GetAssemblyQualifiedName (), javaKey);

                TypeDefinition conflict;
                if (managed.TryGetValue (managedKey, out conflict)) {
                    Log.LogWarning (
                            "Duplicate managed type found! Mappings between managed types and Java types must be unique. " +
                            "First Type: '{0}'; Second Type: '{1}'.",
                            conflict.GetAssemblyQualifiedName (),
                            type.GetAssemblyQualifiedName ());
                    Log.LogWarning (
                            "References to the type '{0}' will refer to '{1}'.",
                            managedKey, conflict.GetAssemblyQualifiedName ());
                    continue;
                }
                if (java.TryGetValue (javaKey, out conflict)) {
                    Log.LogError (
                            "Duplicate Java type found! Mappings between managed types and Java types must be unique. " +
                            "First Type: '{0}'; Second Type: '{1}'",
                            conflict.GetAssemblyQualifiedName (),
                            type.GetAssemblyQualifiedName ());
                    keep_going = false;
                    continue;
                }
                managed.Add (managedKey, type);
                java.Add (javaKey, type);
                acw_map.WriteLine ("{0};{1}", managedKey, javaKey);
                acw_map.WriteLine ("{0};{1}", JniType.ToCompatJniName (type).Replace ('/', '.'), javaKey);
            }

            acw_map.Close ();

            //The previous steps found an error, so we must abort and not generate any further output
            //We must do so subsequent unchanged builds fail too.
            if (!keep_going) {
                File.Delete (temp_map_file);
                return;
            }

            MonoAndroidHelper.CopyIfChanged (temp_map_file, AcwMapFile);

            try { File.Delete (temp_map_file); } catch (Exception) { }

            // Only overwrite files if the contents actually changed
            foreach (var file in Directory.GetFiles (temp, "*", SearchOption.AllDirectories)) {
                var dest = Path.GetFullPath (Path.Combine (OutputDirectory, "src", file.Substring (temp.Length + 1)));

                MonoAndroidHelper.CopyIfChanged (file, dest);
            }

            // Step 3 - Merge [Activity] and friends into AndroidManifest.xml
            var manifest = new ManifestDocument (ManifestTemplate, this.Log);

            manifest.PackageName = PackageName;
            manifest.ApplicationName = ApplicationName ?? PackageName;
            manifest.Assemblies.AddRange (assemblies);
            manifest.Resolver = res;
            manifest.SdkDir = AndroidSdkDir;
            manifest.SdkVersion = AndroidSdkPlatform;
            manifest.Debug = Debug;
            manifest.NeedsInternet = NeedsInternet;

            var additionalProviders = manifest.Merge (all_java_types, selectedWhitelistAssemblies, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments);

            var temp_manifest = Path.Combine (temp, "AndroidManifest.xml");
            var real_manifest = Path.GetFullPath (MergedAndroidManifestOutput);

            manifest.Save (temp_manifest);

            // Only write the new manifest if it actually changed
            MonoAndroidHelper.CopyIfChanged (temp_manifest, real_manifest);

            // Create additional runtime provider java sources.
            string providerTemplateFile = UseSharedRuntime ? "MonoRuntimeProvider.Shared.java" : "MonoRuntimeProvider.Bundled.java";
            string providerTemplate = new StreamReader (typeof (JavaCallableWrapperGenerator).Assembly.GetManifestResourceStream (providerTemplateFile)).ReadToEnd ();

            foreach (var provider in additionalProviders) {
                var temp_provider = Path.Combine (temp, provider + ".java");
                File.WriteAllText (temp_provider, providerTemplate.Replace ("MonoRuntimeProvider", provider));
                var real_provider_dir = Path.GetFullPath (Path.Combine (OutputDirectory, "src", "mono"));
                Directory.CreateDirectory (real_provider_dir);
                var real_provider = Path.Combine (real_provider_dir, provider + ".java");
                MonoAndroidHelper.CopyIfChanged (temp_provider, real_provider);
            }

            // Create additional application java sources.

            Action<string,string,string,Func<string,string>> save = (resource, filename, destDir, applyTemplate) => {
                string temp_file = Path.Combine (temp, filename);
                string template = applyTemplate (new StreamReader (typeof (GenerateJavaStubs).Assembly.GetManifestResourceStream (resource)).ReadToEnd ());
                File.WriteAllText (temp_file, template);
                Directory.CreateDirectory (destDir);
                var real_file = Path.Combine (destDir, filename);
                MonoAndroidHelper.CopyIfChanged (temp_file, real_file);
            };

            StringWriter regCallsWriter = new StringWriter ();
            regCallsWriter.WriteLine ("\t\t// Application and Instrumentation ACWs must be registered first.");
            foreach (var type in java_types) {
                if (JniType.IsApplication (type) || JniType.IsInstrumentation (type)) {
                    string javaKey = JniType.ToJniName (type).Replace ('/', '.');
                    regCallsWriter.WriteLine ("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);",
                        type.GetAssemblyQualifiedName (), javaKey);
                }
            }
            regCallsWriter.Close ();

            var real_app_dir = Path.GetFullPath (Path.Combine (OutputDirectory, "src", "mono", "android", "app"));
            string applicationTemplateFile = "ApplicationRegistration.java";
            save (applicationTemplateFile, applicationTemplateFile, real_app_dir,
                template => template.Replace ("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString ()));

            // Create NotifyTimeZoneChanges java sources.
            string notifyTimeZoneChangesFile = "NotifyTimeZoneChanges.java";
            save (notifyTimeZoneChangesFile, notifyTimeZoneChangesFile, real_app_dir, template => template);

            // Delete our temp directory
            try { Directory.Delete (temp, true); } catch (Exception) { }
        }
        bool Execute(DirectoryAssemblyResolver resolver)
        {
            Log.LogDebugMessage("ResolveAssemblies Task");
            Log.LogDebugMessage("  ReferenceAssembliesDirectory: {0}", ReferenceAssembliesDirectory);
            Log.LogDebugMessage("  I18nAssemblies: {0}", I18nAssemblies);
            Log.LogDebugMessage("  LinkMode: {0}", LinkMode);
            Log.LogDebugTaskItems("  Assemblies:", Assemblies);

            foreach (var dir in ReferenceAssembliesDirectory.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
            {
                resolver.SearchDirectories.Add(dir);
            }

            var assemblies = new HashSet <string> ();

            var topAssemblyReferences = new List <AssemblyDefinition> ();

            try {
                foreach (var assembly in Assemblies)
                {
                    var assembly_path = Path.GetDirectoryName(assembly.ItemSpec);

                    if (!resolver.SearchDirectories.Contains(assembly_path))
                    {
                        resolver.SearchDirectories.Add(assembly_path);
                    }

                    // Add each user assembly and all referenced assemblies (recursive)
                    var assemblyDef = resolver.Load(assembly.ItemSpec);
                    if (assemblyDef == null)
                    {
                        throw new InvalidOperationException("Failed to load assembly " + assembly.ItemSpec);
                    }
                    topAssemblyReferences.Add(assemblyDef);
                    assemblies.Add(Path.GetFullPath(assemblyDef.MainModule.FullyQualifiedName));
                }
            } catch (Exception ex) {
                Log.LogError("Exception while loading assemblies: {0}", ex);
                return(false);
            }
            try {
                foreach (var assembly in topAssemblyReferences)
                {
                    AddAssemblyReferences(resolver, assemblies, assembly, true);
                }
            } catch (Exception ex) {
                Log.LogError("Exception while loading assemblies: {0}", ex);
                return(false);
            }

            // Add I18N assemblies if needed
            AddI18nAssemblies(resolver, assemblies);

            ResolvedAssemblies = assemblies.Select(a => new TaskItem(a)).ToArray();
            ResolvedSymbols    = assemblies.Select(a => a + ".mdb").Where(a => File.Exists(a)).Select(a => new TaskItem(a)).ToArray();
            ResolvedSymbols    = ResolvedSymbols.Concat(
                assemblies.Select(a => Path.ChangeExtension(a, "pdb"))
                .Where(a => File.Exists(a) && Files.IsPortablePdb(a))
                .Select(a => new TaskItem(a)))
                                 .ToArray();
            ResolvedFrameworkAssemblies    = ResolvedAssemblies.Where(p => MonoAndroidHelper.IsFrameworkAssembly(p.ItemSpec, true)).ToArray();
            ResolvedUserAssemblies         = ResolvedAssemblies.Where(p => !MonoAndroidHelper.IsFrameworkAssembly(p.ItemSpec, true)).ToArray();
            ResolvedDoNotPackageAttributes = do_not_package_atts.ToArray();

            Log.LogDebugTaskItems("  [Output] ResolvedAssemblies:", ResolvedAssemblies);
            Log.LogDebugTaskItems("  [Output] ResolvedUserAssemblies:", ResolvedUserAssemblies);
            Log.LogDebugTaskItems("  [Output] ResolvedFrameworkAssemblies:", ResolvedFrameworkAssemblies);
            Log.LogDebugTaskItems("  [Output] ResolvedDoNotPackageAttributes:", ResolvedDoNotPackageAttributes);

            return(!Log.HasLoggedErrors);
        }
        public override bool Execute()
        {
            // In Xamarin Studio, if the project name isn't a valid C# identifier
            // then $(RootNamespace) is not set, and the generated Activity is
            // placed into the "Application" namespace. VS just munges the project
            // name to be a valid C# identifier.
            // Use "Application" as the default namespace name to work with XS.
            Namespace = Namespace ?? "Application";

            Log.LogDebugMessage ("GenerateResourceDesigner Task");
            Log.LogDebugMessage ("  NetResgenOutputFile: {0}", NetResgenOutputFile);
            Log.LogDebugMessage ("  JavaResgenInputFile: {0}", JavaResgenInputFile);
            Log.LogDebugMessage ("  Namespace: {0}", Namespace);
            Log.LogDebugMessage ("  ResourceDirectory: {0}", ResourceDirectory);
            Log.LogDebugTaskItemsAndLogical ("  AdditionalResourceDirectories:", AdditionalResourceDirectories);
            Log.LogDebugMessage ("  IsApplication: {0}", IsApplication);
            Log.LogDebugTaskItemsAndLogical ("  Resources:", Resources);
            Log.LogDebugTaskItemsAndLogical ("  References:", References);

            if (!File.Exists (JavaResgenInputFile))
                return true;

            // ResourceDirectory may be a relative path, and
            // we need to compare it to absolute paths
            ResourceDirectory = Path.GetFullPath (ResourceDirectory);

            // Create our capitalization maps so we can support mixed case resources
            foreach (var item in Resources) {
                if (!item.ItemSpec.StartsWith (ResourceDirectory))
                    continue;

                var name = item.ItemSpec.Substring (ResourceDirectory.Length);
                var logical_name = item.GetMetadata ("LogicalName");

                AddRename (name.Replace ('/', Path.DirectorySeparatorChar), logical_name.Replace ('/', Path.DirectorySeparatorChar));
            }
            if (AdditionalResourceDirectories != null) {
                foreach (var additionalDir in AdditionalResourceDirectories) {
                    var file = Path.Combine (ProjectDir, Path.GetDirectoryName (additionalDir.ItemSpec), "__res_name_case_map.txt");
                    if (File.Exists (file)) {
                        foreach (var line in File.ReadAllLines (file).Where (l => !string.IsNullOrEmpty (l))) {
                            string [] tok = line.Split (';');
                            AddRename (tok [1].Replace ('/', Path.DirectorySeparatorChar), tok [0].Replace ('/', Path.DirectorySeparatorChar));
                        }
                    }
                }
            }

            // Parse out the resources from the R.java file
            JavaResourceParser.Log = Log;
            var resources = JavaResourceParser.Parse (JavaResgenInputFile, IsApplication, resource_fixup);

            var extension = Path.GetExtension (NetResgenOutputFile);
            var language = string.Compare (extension, ".fs", StringComparison.OrdinalIgnoreCase) == 0 ? "F#" : CodeDomProvider.GetLanguageFromExtension (extension);
            bool isVB = string.Equals (extension, ".vb", StringComparison.OrdinalIgnoreCase);
            bool isFSharp = string.Equals (language, "F#", StringComparison.OrdinalIgnoreCase);
            bool isCSharp = string.Equals (language, "C#", StringComparison.OrdinalIgnoreCase);

            // Let VB put this in the default namespace
            if (isVB)
                Namespace = string.Empty;

            // Create static resource overwrite methods for each Resource class in libraries.
            var assemblyNames = new List<string> ();
            if (IsApplication && References != null && References.Any ()) {
                // FIXME: should this be unified to some better code with ResolveLibraryProjectImports?
                var resolver = new DirectoryAssemblyResolver (Log.LogWarning, loadDebugSymbols: false);
                foreach (var assemblyName in References) {
                    var suffix = assemblyName.ItemSpec.EndsWith (".dll") ? String.Empty : ".dll";
                    string hintPath = assemblyName.GetMetadata ("HintPath").Replace (Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
                    string fileName = assemblyName.ItemSpec + suffix;
                    resolver.Load (Path.GetFullPath (assemblyName.ItemSpec));
                    if (!String.IsNullOrEmpty (hintPath) && !File.Exists (hintPath)) // ignore invalid HintPath
                        hintPath = null;
                    string assemblyPath = String.IsNullOrEmpty (hintPath) ? fileName : hintPath;
                    if (MonoAndroidHelper.IsFrameworkAssembly (fileName) && !MonoAndroidHelper.FrameworkEmbeddedJarLookupTargets.Contains (Path.GetFileName (fileName)))
                        continue;
                    Log.LogDebugMessage ("Scan assembly {0} for resource generator", fileName);
                    assemblyNames.Add (assemblyPath);
                }
                var assemblies = assemblyNames.Select (assembly => resolver.GetAssembly (assembly));
                new ResourceDesignerImportGenerator (Namespace, resources)
                    .CreateImportMethods (assemblies);
            }

            AdjustConstructor (isFSharp, resources);
            foreach (var member in resources.Members)
                if (member is CodeTypeDeclaration)
                    AdjustConstructor (isFSharp, (CodeTypeDeclaration) member);

            // Write out our Resources.Designer.cs file

            WriteFile (NetResgenOutputFile, resources, language, isFSharp, isCSharp);

            return !Log.HasLoggedErrors;
        }
Example #20
0
        // Extracts library project contents under e.g. obj/Debug/[__library_projects__/*.jar | res/*/*]
        // Extracts library project contents under e.g. obj/Debug/[lp/*.jar | res/*/*]
        public override bool Execute()
        {
            var jars = new List <string> ();
            var resolvedResourceDirectories = new List <ITaskItem> ();
            var resolvedAssetDirectories    = new List <string> ();
            var resolvedEnvironmentFiles    = new List <string> ();

            assemblyMap.Load(AssemblyIdentityMapFile);
            assembliesToSkip = new HashSet <string> (AssembliesToSkipCases ?? new string [0], StringComparer.OrdinalIgnoreCase);

            using (var resolver = new DirectoryAssemblyResolver(this.CreateTaskLogger(), loadDebugSymbols: false)) {
                try {
                    Extract(resolver, jars, resolvedResourceDirectories, resolvedAssetDirectories, resolvedEnvironmentFiles);
                } catch (ZipIOException ex) {
                    Log.LogCodedError("XA1004", ex.Message);
                    Log.LogDebugMessage(ex.ToString());
                }
            }

            Jars = jars.ToArray();
            ResolvedResourceDirectories = resolvedResourceDirectories.ToArray();
            ResolvedAssetDirectories    = resolvedAssetDirectories.ToArray();
            ResolvedEnvironmentFiles    = resolvedEnvironmentFiles.ToArray();

            ResolvedResourceDirectoryStamps = ResolvedResourceDirectories
                                              .Select(s => new TaskItem(Path.GetFullPath(Path.Combine(s.ItemSpec, "../..")) + ".stamp"))
                                              .ToArray();

            foreach (var directory in ResolvedResourceDirectories)
            {
                MonoAndroidHelper.SetDirectoryWriteable(directory.ItemSpec);
            }

            foreach (var directory in ResolvedAssetDirectories)
            {
                MonoAndroidHelper.SetDirectoryWriteable(directory);
            }

            if (!string.IsNullOrEmpty(CacheFile))
            {
                var document = new XDocument(
                    new XDeclaration("1.0", "UTF-8", null),
                    new XElement("Paths",
                                 new XElement("Jars",
                                              Jars.Select(e => new XElement("Jar", e))),
                                 new XElement("ResolvedResourceDirectories",
                                              ResolvedResourceDirectories.Select(dir => {
                    var e = new XElement("ResolvedResourceDirectory", dir.ItemSpec);
                    foreach (var name in knownMetadata)
                    {
                        var value = dir.GetMetadata(name);
                        if (!string.IsNullOrEmpty(value))
                        {
                            e.SetAttributeValue(name, value);
                        }
                    }
                    return(e);
                })),
                                 new XElement("ResolvedAssetDirectories",
                                              ResolvedAssetDirectories.Select(e => new XElement("ResolvedAssetDirectory", e))),
                                 new XElement("ResolvedEnvironmentFiles",
                                              ResolvedEnvironmentFiles.Select(e => new XElement("ResolvedEnvironmentFile", e))),
                                 new XElement("ResolvedResourceDirectoryStamps",
                                              ResolvedResourceDirectoryStamps.Select(e => new XElement("ResolvedResourceDirectoryStamp", e)))
                                 ));
                document.SaveIfChanged(CacheFile);
            }

            assemblyMap.Save(AssemblyIdentityMapFile);

            Log.LogDebugTaskItems("  Jars: ", Jars);
            Log.LogDebugTaskItems("  ResolvedResourceDirectories: ", ResolvedResourceDirectories);
            Log.LogDebugTaskItems("  ResolvedAssetDirectories: ", ResolvedAssetDirectories);
            Log.LogDebugTaskItems("  ResolvedEnvironmentFiles: ", ResolvedEnvironmentFiles);
            Log.LogDebugTaskItems("  ResolvedResourceDirectoryStamps: ", ResolvedResourceDirectoryStamps);

            return(!Log.HasLoggedErrors);
        }
Example #21
0
        void Execute(DirectoryAssemblyResolver resolver)
        {
            foreach (var dir in ReferenceAssembliesDirectory.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
            {
                resolver.SearchDirectories.Add(dir);
            }

            var assemblies = new Dictionary <string, string> ();

            var topAssemblyReferences = new List <AssemblyDefinition> ();
            var logger = new NuGetLogger((s) => {
                LogDebugMessage("{0}", s);
            });

            LockFile lockFile = null;

            if (!string.IsNullOrEmpty(ProjectAssetFile) && File.Exists(ProjectAssetFile))
            {
                lockFile = LockFileUtilities.GetLockFile(ProjectAssetFile, logger);
            }

            try {
                foreach (var assembly in Assemblies)
                {
                    var assembly_path = Path.GetDirectoryName(assembly.ItemSpec);

                    if (!resolver.SearchDirectories.Contains(assembly_path))
                    {
                        resolver.SearchDirectories.Add(assembly_path);
                    }

                    // Add each user assembly and all referenced assemblies (recursive)
                    var assemblyDef = resolver.Load(assembly.ItemSpec);
                    if (assemblyDef == null)
                    {
                        throw new InvalidOperationException("Failed to load assembly " + assembly.ItemSpec);
                    }
                    if (MonoAndroidHelper.IsReferenceAssembly(assemblyDef))
                    {
                        // Resolve "runtime" library
                        var asmFullPath = Path.GetFullPath(assembly.ItemSpec);
                        if (lockFile != null)
                        {
                            assemblyDef = ResolveRuntimeAssemblyForReferenceAssembly(lockFile, resolver, asmFullPath);
                        }
                        if (lockFile == null || assemblyDef == null)
                        {
                            LogCodedWarning("XA0107", asmFullPath, 0, "Ignoring {0} as it is a Reference Assembly", asmFullPath);
                            continue;
                        }
                    }
                    topAssemblyReferences.Add(assemblyDef);
                    assemblies [assemblyDef.Name.Name] = Path.GetFullPath(assemblyDef.MainModule.FileName);
                }
            } catch (Exception ex) {
                LogError("Exception while loading assemblies: {0}", ex);
                return;
            }
            try {
                foreach (var assembly in topAssemblyReferences)
                {
                    AddAssemblyReferences(resolver, assemblies, assembly, null);
                }
            } catch (Exception ex) {
                LogError("Exception while loading assemblies: {0}", ex);
                return;
            }

            // Add I18N assemblies if needed
            AddI18nAssemblies(resolver, assemblies);

            var mainapiLevel = MonoAndroidHelper.SupportedVersions.GetApiLevelFromFrameworkVersion(TargetFrameworkVersion);

            foreach (var item in api_levels.Where(x => mainapiLevel < x.Value))
            {
                var itemOSVersion = MonoAndroidHelper.SupportedVersions.GetFrameworkVersionFromApiLevel(item.Value);
                Log.LogCodedWarning("XA0105", ProjectFile, 0,
                                    "The $(TargetFrameworkVersion) for {0} ({1}) is greater than the $(TargetFrameworkVersion) for your project ({2}). " +
                                    "You need to increase the $(TargetFrameworkVersion) for your project.", Path.GetFileName(item.Key), itemOSVersion, TargetFrameworkVersion);
            }

            var resolvedAssemblies          = new List <ITaskItem> (assemblies.Count);
            var resolvedSymbols             = new List <ITaskItem> (assemblies.Count);
            var resolvedFrameworkAssemblies = new List <ITaskItem> (assemblies.Count);
            var resolvedUserAssemblies      = new List <ITaskItem> (assemblies.Count);

            foreach (var assembly in assemblies.Values)
            {
                var mdb = assembly + ".mdb";
                var pdb = Path.ChangeExtension(assembly, "pdb");
                if (File.Exists(mdb))
                {
                    resolvedSymbols.Add(new TaskItem(mdb));
                }
                if (File.Exists(pdb) && Files.IsPortablePdb(pdb))
                {
                    resolvedSymbols.Add(new TaskItem(pdb));
                }
                var assemblyItem = new TaskItem(assembly);
                resolvedAssemblies.Add(assemblyItem);
                if (MonoAndroidHelper.IsFrameworkAssembly(assembly, checkSdkPath: true))
                {
                    resolvedFrameworkAssemblies.Add(assemblyItem);
                }
                else
                {
                    resolvedUserAssemblies.Add(assemblyItem);
                }
            }
            ResolvedAssemblies             = resolvedAssemblies.ToArray();
            ResolvedSymbols                = resolvedSymbols.ToArray();
            ResolvedFrameworkAssemblies    = resolvedFrameworkAssemblies.ToArray();
            ResolvedUserAssemblies         = resolvedUserAssemblies.ToArray();
            ResolvedDoNotPackageAttributes = do_not_package_atts.ToArray();
        }
Example #22
0
        // Extracts library project contents under e.g. obj/Debug/[__library_projects__/*.jar | res/*/*]
        // Extracts library project contents under e.g. obj/Debug/[lp/*.jar | res/*/*]
        void Extract(
            DirectoryAssemblyResolver res,
            ICollection <string> jars,
            ICollection <ITaskItem> resolvedResourceDirectories,
            ICollection <string> resolvedAssetDirectories,
            ICollection <string> resolvedEnvironments)
        {
            // lets "upgrade" the old directory.
            string oldPath = Path.GetFullPath(Path.Combine(OutputImportDirectory, "..", "__library_projects__"));

            if (!OutputImportDirectory.Contains("__library_projects__") && Directory.Exists(oldPath))
            {
                MonoAndroidHelper.SetDirectoryWriteable(Path.Combine(oldPath, ".."));
                Directory.Delete(oldPath, recursive: true);
            }
            var outdir = Path.GetFullPath(OutputImportDirectory);

            Directory.CreateDirectory(outdir);

            foreach (var assembly in Assemblies)
            {
                res.Load(assembly.ItemSpec);
            }

            // FIXME: reorder references by import priority (not sure how to do that yet)
            foreach (var assemblyPath in Assemblies
                     .Select(a => GetTargetAssembly(a))
                     .Where(a => a != null)
                     .Distinct())
            {
                if (DesignTimeBuild && !File.Exists(assemblyPath))
                {
                    Log.LogDebugMessage("Skipping non existant dependancy '{0}' due to design time build.", assemblyPath);
                    continue;
                }
                string assemblyFileName  = Path.GetFileNameWithoutExtension(assemblyPath);
                string assemblyIdentName = assemblyFileName;
                if (UseShortFileNames)
                {
                    assemblyIdentName = assemblyMap.GetLibraryImportDirectoryNameForAssembly(assemblyFileName);
                }
                string outDirForDll     = Path.Combine(OutputImportDirectory, assemblyIdentName);
                string importsDir       = Path.Combine(outDirForDll, ImportsDirectory);
                string nativeimportsDir = Path.Combine(outDirForDll, NativeImportsDirectory);
#if SEPARATE_CRUNCH
                // FIXME: review these binResDir thing and enable this. Eclipse does this.
                // Enabling these blindly causes build failure on ActionBarSherlock.
                //string binResDir = Path.Combine (importsDir, "bin", "res");
                //string binAssemblyDir = Path.Combine (importsDir, "bin", "assets");
#endif
                string resDir    = Path.Combine(importsDir, "res");
                string assetsDir = Path.Combine(importsDir, "assets");

                // Skip already-extracted resources.
                bool   updated      = false;
                string assemblyHash = MonoAndroidHelper.HashFile(assemblyPath);
                string stamp        = Path.Combine(outdir, assemblyIdentName + ".stamp");
                string stampHash    = File.Exists(stamp) ? File.ReadAllText(stamp) : null;
                if (assemblyHash == stampHash)
                {
                    Log.LogDebugMessage("Skipped resource lookup for {0}: extracted files are up to date", assemblyPath);
#if SEPARATE_CRUNCH
                    // FIXME: review these binResDir/binAssemblyDir thing and enable this. Eclipse does this.
                    // Enabling these blindly causes build failure on ActionBarSherlock.
                    if (Directory.Exists(binResDir))
                    {
                        resolvedResourceDirectories.Add(binResDir);
                    }
                    if (Directory.Exists(binAssemblyDir))
                    {
                        resolvedAssetDirectories.Add(binAssemblyDir);
                    }
#endif
                    if (Directory.Exists(resDir))
                    {
                        var taskItem = new TaskItem(Path.GetFullPath(resDir), new Dictionary <string, string> {
                            { OriginalFile, assemblyPath },
                        });
                        if (assembliesToSkip.Contains(assemblyFileName))
                        {
                            taskItem.SetMetadata(SkipAndroidResourceProcessing, "True");
                        }
                        resolvedResourceDirectories.Add(taskItem);
                    }
                    if (Directory.Exists(assetsDir))
                    {
                        resolvedAssetDirectories.Add(Path.GetFullPath(assetsDir));
                    }
                    foreach (var env in Directory.EnumerateFiles(outDirForDll, "__AndroidEnvironment__*", SearchOption.TopDirectoryOnly))
                    {
                        resolvedEnvironments.Add(env);
                    }
                    continue;
                }

                Log.LogDebugMessage($"Refreshing {assemblyFileName}.dll");

                var assembly = res.GetAssembly(assemblyPath);
                foreach (var mod in assembly.Modules)
                {
                    // android environment files
                    foreach (var envtxt in mod.Resources
                             .Where(r => r.Name.StartsWith("__AndroidEnvironment__", StringComparison.OrdinalIgnoreCase))
                             .Where(r => r is EmbeddedResource)
                             .Cast <EmbeddedResource> ())
                    {
                        var outFile = Path.Combine(outDirForDll, envtxt.Name);
                        using (var stream = envtxt.GetResourceStream()) {
                            updated |= MonoAndroidHelper.CopyIfStreamChanged(stream, outFile);
                        }
                        resolvedEnvironments.Add(Path.GetFullPath(outFile));
                    }

                    // embedded jars (EmbeddedJar, EmbeddedReferenceJar)
                    var resjars = mod.Resources
                                  .Where(r => r.Name.EndsWith(".jar", StringComparison.InvariantCultureIgnoreCase))
                                  .Select(r => (EmbeddedResource)r);
                    foreach (var resjar in resjars)
                    {
                        using (var stream = resjar.GetResourceStream()) {
                            AddJar(jars, importsDir, resjar.Name);
                            updated |= MonoAndroidHelper.CopyIfStreamChanged(stream, Path.Combine(importsDir, resjar.Name));
                        }
                    }

                    var libzip = mod.Resources.FirstOrDefault(r => r.Name == "__AndroidNativeLibraries__.zip") as EmbeddedResource;
                    if (libzip != null)
                    {
                        List <string> files = new List <string> ();
                        using (var stream = libzip.GetResourceStream())
                            using (var zip = Xamarin.Tools.Zip.ZipArchive.Open(stream)) {
                                try {
                                    updated |= Files.ExtractAll(zip, nativeimportsDir, modifyCallback: (entryFullName) => {
                                        files.Add(Path.GetFullPath(Path.Combine(nativeimportsDir, entryFullName)));
                                        return(entryFullName
                                               .Replace("native_library_imports\\", "")
                                               .Replace("native_library_imports/", ""));
                                    }, deleteCallback: (fileToDelete) => {
                                        return(!files.Contains(fileToDelete));
                                    });
                                } catch (PathTooLongException ex) {
                                    Log.LogCodedError("XA4303", $"Error extracting resources from \"{assemblyPath}\": {ex}");
                                    return;
                                } catch (NotSupportedException ex) {
                                    Log.LogCodedError("XA4303", $"Error extracting resources from \"{assemblyPath}\": {ex}");
                                    return;
                                }
                            }
                    }

                    // embedded AndroidResourceLibrary archive
                    var reszip = mod.Resources.FirstOrDefault(r => r.Name == "__AndroidLibraryProjects__.zip") as EmbeddedResource;
                    if (reszip != null)
                    {
                        // temporarily extracted directory will look like:
                        //    __library_projects__/[dllname]/[library_project_imports | jlibs]/bin
                        using (var stream = reszip.GetResourceStream())
                            using (var zip = Xamarin.Tools.Zip.ZipArchive.Open(stream)) {
                                try {
                                    updated |= Files.ExtractAll(zip, importsDir, modifyCallback: (entryFullName) => {
                                        var path = entryFullName
                                                   .Replace("library_project_imports\\", "")
                                                   .Replace("library_project_imports/", "");
                                        if (path.EndsWith(".jar", StringComparison.OrdinalIgnoreCase))
                                        {
                                            AddJar(jars, importsDir, path);
                                        }
                                        return(path);
                                    }, deleteCallback: (fileToDelete) => {
                                        return(!jars.Contains(fileToDelete));
                                    });
                                } catch (PathTooLongException ex) {
                                    Log.LogCodedError("XA4303", $"Error extracting resources from \"{assemblyPath}\": {ex}");
                                    return;
                                } catch (NotSupportedException ex) {
                                    Log.LogCodedError("XA4303", $"Error extracting resources from \"{assemblyPath}\": {ex}");
                                    return;
                                }
                            }

                        // We used to *copy* the resources to overwrite other resources,
                        // which resulted in missing resource issue.
                        // Here we replaced copy with use of '-S' option and made it to work.
#if SEPARATE_CRUNCH
                        // FIXME: review these binResDir/binAssemblyDir thing and enable this. Eclipse does this.
                        // Enabling these blindly causes build failure on ActionBarSherlock.
                        if (Directory.Exists(binResDir))
                        {
                            resolvedResourceDirectories.Add(binResDir);
                        }
                        if (Directory.Exists(binAssemblyDir))
                        {
                            resolvedAssetDirectories.Add(binAssemblyDir);
                        }
#endif
                        if (Directory.Exists(resDir))
                        {
                            var taskItem = new TaskItem(Path.GetFullPath(resDir), new Dictionary <string, string> {
                                { OriginalFile, assemblyPath }
                            });
                            if (assembliesToSkip.Contains(assemblyFileName))
                            {
                                taskItem.SetMetadata(SkipAndroidResourceProcessing, "True");
                            }
                            resolvedResourceDirectories.Add(taskItem);
                        }
                        if (Directory.Exists(assetsDir))
                        {
                            resolvedAssetDirectories.Add(Path.GetFullPath(assetsDir));
                        }
                    }
                }

                if (Directory.Exists(importsDir) && assemblyHash != stampHash)
                {
                    Log.LogDebugMessage($"Saving hash to {stamp}, changes: {updated}");
                    //NOTE: if the hash is different we always want to write the file, but preserve the timestamp if no changes
                    WriteAllText(stamp, assemblyHash, preserveTimestamp: !updated);
                }
            }
            foreach (var aarFile in AarLibraries ?? new ITaskItem[0])
            {
                if (!File.Exists(aarFile.ItemSpec))
                {
                    continue;
                }
                string aarIdentityName = Path.GetFileNameWithoutExtension(aarFile.ItemSpec);
                if (UseShortFileNames)
                {
                    aarIdentityName = assemblyMap.GetLibraryImportDirectoryNameForAssembly(aarIdentityName);
                }
                string outDirForDll = Path.Combine(OutputImportDirectory, aarIdentityName);
                string importsDir   = Path.Combine(outDirForDll, ImportsDirectory);
                string resDir       = Path.Combine(importsDir, "res");
                string assetsDir    = Path.Combine(importsDir, "assets");

                bool   updated   = false;
                string aarHash   = MonoAndroidHelper.HashFile(aarFile.ItemSpec);
                string stamp     = Path.Combine(outdir, Path.GetFileNameWithoutExtension(aarFile.ItemSpec) + ".stamp");
                string stampHash = File.Exists(stamp) ? File.ReadAllText(stamp) : null;
                if (aarHash == stampHash)
                {
                    Log.LogDebugMessage("Skipped {0}: extracted files are up to date", aarFile.ItemSpec);
                    if (Directory.Exists(resDir))
                    {
                        resolvedResourceDirectories.Add(new TaskItem(Path.GetFullPath(resDir), new Dictionary <string, string> {
                            { OriginalFile, Path.GetFullPath(aarFile.ItemSpec) },
                            { SkipAndroidResourceProcessing, "True" },
                        }));
                    }
                    if (Directory.Exists(assetsDir))
                    {
                        resolvedAssetDirectories.Add(Path.GetFullPath(assetsDir));
                    }
                    continue;
                }

                Log.LogDebugMessage($"Refreshing {aarFile.ItemSpec}");

                // temporarily extracted directory will look like:
                // _lp_/[aarFile]
                using (var zip = MonoAndroidHelper.ReadZipFile(aarFile.ItemSpec)) {
                    try {
                        updated |= Files.ExtractAll(zip, importsDir, modifyCallback: (entryFullName) => {
                            var entryFileName = Path.GetFileName(entryFullName);
                            var entryPath     = Path.GetDirectoryName(entryFullName);
                            if (entryFileName.StartsWith("internal_impl", StringComparison.InvariantCulture))
                            {
                                var hash = Files.HashString(entryFileName);
                                var jar  = Path.Combine(entryPath, $"internal_impl-{hash}.jar");
                                AddJar(jars, importsDir, jar);
                                return(jar);
                            }
                            if (entryFullName.EndsWith(".jar", StringComparison.OrdinalIgnoreCase))
                            {
                                AddJar(jars, importsDir, entryFullName);
                            }
                            return(entryFullName);
                        }, deleteCallback: (fileToDelete) => {
                            return(!jars.Contains(fileToDelete));
                        });

                        if (Directory.Exists(importsDir) && aarHash != stampHash)
                        {
                            Log.LogDebugMessage($"Saving hash to {stamp}, changes: {updated}");
                            //NOTE: if the hash is different we always want to write the file, but preserve the timestamp if no changes
                            WriteAllText(stamp, aarHash, preserveTimestamp: !updated);
                        }
                    } catch (PathTooLongException ex) {
                        Log.LogErrorFromException(new PathTooLongException($"Error extracting resources from \"{aarFile.ItemSpec}\"", ex));
                    }
                }
                if (Directory.Exists(resDir))
                {
                    resolvedResourceDirectories.Add(new TaskItem(Path.GetFullPath(resDir), new Dictionary <string, string> {
                        { OriginalFile, Path.GetFullPath(aarFile.ItemSpec) },
                        { SkipAndroidResourceProcessing, "True" },
                    }));
                }
                if (Directory.Exists(assetsDir))
                {
                    resolvedAssetDirectories.Add(Path.GetFullPath(assetsDir));
                }
            }
        }
Example #23
0
        void AddAssemblyReferences(DirectoryAssemblyResolver resolver, Dictionary <string, string> assemblies, AssemblyDefinition assembly, List <string> resolutionPath)
        {
            var assemblyName = assembly.Name.Name;
            var fullPath     = Path.GetFullPath(assembly.MainModule.FileName);

            // Don't repeat assemblies we've already done
            bool topLevel = resolutionPath == null;

            if (!topLevel && assemblies.ContainsKey(assemblyName))
            {
                return;
            }

            if (resolutionPath == null)
            {
                resolutionPath = new List <string>();
            }

            CheckAssemblyAttributes(assembly);

            LogMessage("{0}Adding assembly reference for {1}, recursively...", new string (' ', indent), assembly.Name);
            resolutionPath.Add(assembly.Name.Name);
            indent += 2;

            // Add this assembly
            if (!topLevel)
            {
                assemblies [assemblyName] = fullPath;
            }

            // Recurse into each referenced assembly
            foreach (AssemblyNameReference reference in assembly.MainModule.AssemblyReferences)
            {
                AssemblyDefinition reference_assembly;
                try {
                    reference_assembly = resolver.Resolve(reference);
                } catch (FileNotFoundException ex) {
                    var references = new StringBuilder();
                    for (int i = 0; i < resolutionPath.Count; i++)
                    {
                        if (i != 0)
                        {
                            references.Append(" > ");
                        }
                        references.Append('`');
                        references.Append(resolutionPath [i]);
                        references.Append('`');
                    }

                    string missingAssembly = Path.GetFileNameWithoutExtension(ex.FileName);
                    string message         = $"Can not resolve reference: `{missingAssembly}`, referenced by {references}.";
                    if (MonoAndroidHelper.IsFrameworkAssembly(ex.FileName))
                    {
                        LogCodedError("XA2002", $"{message} Perhaps it doesn't exist in the Mono for Android profile?");
                    }
                    else
                    {
                        LogCodedError("XA2002", $"{message} Please add a NuGet package or assembly reference for `{missingAssembly}`, or remove the reference to `{resolutionPath [0]}`.");
                    }
                    return;
                }
                AddAssemblyReferences(resolver, assemblies, reference_assembly, resolutionPath);
            }

            indent -= 2;
            resolutionPath.RemoveAt(resolutionPath.Count - 1);
        }
Example #24
0
        // Extracts library project contents under e.g. obj/Debug/[__library_projects__/*.jar | res/*/*]
        // Extracts library project contents under e.g. obj/Debug/[lp/*.jar | res/*/*]
        void Extract(
            DirectoryAssemblyResolver res,
            ICollection <string> jars,
            ICollection <string> resolvedResourceDirectories,
            ICollection <string> resolvedAssetDirectories,
            ICollection <string> resolvedEnvironments)
        {
            // lets "upgrade" the old directory.
            string oldPath = Path.GetFullPath(Path.Combine(OutputImportDirectory, "..", "__library_projects__"));

            if (!OutputImportDirectory.Contains("__library_projects__") && Directory.Exists(oldPath))
            {
                MonoAndroidHelper.SetDirectoryWriteable(Path.Combine(oldPath, ".."));
                Directory.Delete(oldPath, recursive: true);
            }
            var outdir = new DirectoryInfo(OutputImportDirectory);

            if (!outdir.Exists)
            {
                outdir.Create();
            }

            foreach (var assembly in Assemblies)
            {
                res.Load(assembly.ItemSpec);
            }

            bool updated = false;

            // FIXME: reorder references by import priority (not sure how to do that yet)
            foreach (var assemblyPath in Assemblies
                     .Select(a => GetTargetAssembly(a))
                     .Where(a => a != null)
                     .Distinct())
            {
                string assemblyIdentName = Path.GetFileNameWithoutExtension(assemblyPath);
                if (UseShortFileNames)
                {
                    assemblyIdentName = assemblyMap.GetLibraryImportDirectoryNameForAssembly(assemblyIdentName);
                }
                string outDirForDll = Path.Combine(OutputImportDirectory, assemblyIdentName);
                string importsDir   = Path.Combine(outDirForDll, ImportsDirectory);
#if SEPARATE_CRUNCH
                // FIXME: review these binResDir thing and enable this. Eclipse does this.
                // Enabling these blindly causes build failure on ActionBarSherlock.
                //string binResDir = Path.Combine (importsDir, "bin", "res");
                //string binAssemblyDir = Path.Combine (importsDir, "bin", "assets");
#endif
                string resDir      = Path.Combine(importsDir, "res");
                string assemblyDir = Path.Combine(importsDir, "assets");

                // Skip already-extracted resources.
                var stamp = new FileInfo(Path.Combine(outdir.FullName, assemblyIdentName + ".stamp"));
                if (stamp.Exists && stamp.LastWriteTimeUtc > new FileInfo(assemblyPath).LastWriteTimeUtc)
                {
                    Log.LogDebugMessage("Skipped resource lookup for {0}: extracted files are up to date", assemblyPath);
#if SEPARATE_CRUNCH
                    // FIXME: review these binResDir/binAssemblyDir thing and enable this. Eclipse does this.
                    // Enabling these blindly causes build failure on ActionBarSherlock.
                    if (Directory.Exists(binResDir))
                    {
                        resolvedResourceDirectories.Add(binResDir);
                    }
                    if (Directory.Exists(binAssemblyDir))
                    {
                        resolvedAssetDirectories.Add(binAssemblyDir);
                    }
#endif
                    if (Directory.Exists(resDir))
                    {
                        resolvedResourceDirectories.Add(resDir);
                    }
                    if (Directory.Exists(assemblyDir))
                    {
                        resolvedAssetDirectories.Add(assemblyDir);
                    }
                    foreach (var env in Directory.EnumerateFiles(outDirForDll, "__AndroidEnvironment__*", SearchOption.TopDirectoryOnly))
                    {
                        resolvedEnvironments.Add(env);
                    }
                    continue;
                }

                if (!File.Exists(assemblyPath) && DesignTimeBuild)
                {
                    Log.LogDebugMessage("Skipping non existant dependancy '{0}' due to design time build.", assemblyPath);
                    continue;
                }

                Log.LogDebugMessage("Refreshing {0}", assemblyPath);

                Directory.CreateDirectory(importsDir);

                var assembly          = res.GetAssembly(assemblyPath);
                var assemblyLastWrite = new FileInfo(assemblyPath).LastWriteTimeUtc;

                foreach (var mod in assembly.Modules)
                {
                    // android environment files
                    foreach (var envtxt in mod.Resources
                             .Where(r => r.Name.StartsWith("__AndroidEnvironment__", StringComparison.OrdinalIgnoreCase))
                             .Where(r => r is EmbeddedResource)
                             .Cast <EmbeddedResource> ())
                    {
                        if (!Directory.Exists(outDirForDll))
                        {
                            Directory.CreateDirectory(outDirForDll);
                        }
                        var finfo = new FileInfo(Path.Combine(outDirForDll, envtxt.Name));
                        if (!finfo.Exists || finfo.LastWriteTimeUtc > assemblyLastWrite)
                        {
                            using (var fs = finfo.Create()) {
                                var data = envtxt.GetResourceData();
                                fs.Write(data, 0, data.Length);
                            }
                            updated = true;
                        }
                        resolvedEnvironments.Add(finfo.FullName);
                    }

                    // embedded jars (EmbeddedJar, EmbeddedReferenceJar)
                    var resjars = mod.Resources
                                  .Where(r => r.Name.EndsWith(".jar", StringComparison.InvariantCultureIgnoreCase))
                                  .Select(r => (EmbeddedResource)r);
                    foreach (var resjar in resjars)
                    {
                        var outjarFile = Path.Combine(importsDir, resjar.Name);
                        var fi         = new FileInfo(outjarFile);
                        if (!fi.Exists || fi.LastWriteTimeUtc > assemblyLastWrite)
                        {
                            var data = resjar.GetResourceData();
                            using (var outfs = File.Create(outjarFile))
                                outfs.Write(data, 0, data.Length);
                            updated = true;
                        }
                    }

                    // embedded AndroidResourceLibrary archive
                    var reszip = mod.Resources.FirstOrDefault(r => r.Name == "__AndroidLibraryProjects__.zip") as EmbeddedResource;
                    if (reszip != null)
                    {
                        if (!Directory.Exists(outDirForDll))
                        {
                            Directory.CreateDirectory(outDirForDll);
                        }
                        var finfo = new FileInfo(Path.Combine(outDirForDll, reszip.Name));
                        using (var fs = finfo.Create()) {
                            var data = reszip.GetResourceData();
                            fs.Write(data, 0, data.Length);
                        }

                        // temporarily extracted directory will look like:
                        //    __library_projects__/[dllname]/[library_project_imports | jlibs]/bin
                        using (var zip = MonoAndroidHelper.ReadZipFile(finfo.FullName)) {
                            try {
                                updated |= Files.ExtractAll(zip, importsDir, modifyCallback: (entryFullName) => {
                                    return(entryFullName
                                           .Replace("library_project_imports\\", "")
                                           .Replace("library_project_imports/", ""));
                                }, deleteCallback: (fileToDelete) => {
                                    return(!jars.Contains(fileToDelete));
                                }, forceUpdate: false);
                            } catch (PathTooLongException ex) {
                                Log.LogCodedError("XA4303", $"Error extracting resources from \"{assemblyPath}\": {ex}");
                                return;
                            } catch (NotSupportedException ex) {
                                Log.LogCodedError("XA4303", $"Error extracting resources from \"{assemblyPath}\": {ex}");
                                return;
                            }
                        }

                        // We used to *copy* the resources to overwrite other resources,
                        // which resulted in missing resource issue.
                        // Here we replaced copy with use of '-S' option and made it to work.
#if SEPARATE_CRUNCH
                        // FIXME: review these binResDir/binAssemblyDir thing and enable this. Eclipse does this.
                        // Enabling these blindly causes build failure on ActionBarSherlock.
                        if (Directory.Exists(binResDir))
                        {
                            resolvedResourceDirectories.Add(binResDir);
                        }
                        if (Directory.Exists(binAssemblyDir))
                        {
                            resolvedAssetDirectories.Add(binAssemblyDir);
                        }
#endif
                        if (Directory.Exists(resDir))
                        {
                            resolvedResourceDirectories.Add(resDir);
                        }
                        if (Directory.Exists(assemblyDir))
                        {
                            resolvedAssetDirectories.Add(assemblyDir);
                        }

                        finfo.Delete();
                    }
                }

                if (Directory.Exists(importsDir) && (updated || !stamp.Exists))
                {
                    Log.LogDebugMessage("Touch {0}", stamp.FullName);
                    stamp.Create().Close();
                }
            }
            foreach (var aarFile in AarLibraries ?? new ITaskItem[0])
            {
                if (!File.Exists(aarFile.ItemSpec))
                {
                    continue;
                }
                string aarIdentityName = Path.GetFileNameWithoutExtension(aarFile.ItemSpec);
                if (UseShortFileNames)
                {
                    aarIdentityName = assemblyMap.GetLibraryImportDirectoryNameForAssembly(aarIdentityName);
                }
                string outDirForDll = Path.Combine(OutputImportDirectory, aarIdentityName);
                string importsDir   = Path.Combine(outDirForDll, ImportsDirectory);
                string resDir       = Path.Combine(importsDir, "res");
                string assetsDir    = Path.Combine(importsDir, "assets");

                var stamp = new FileInfo(Path.Combine(outdir.FullName, Path.GetFileNameWithoutExtension(aarFile.ItemSpec) + ".stamp"));
                if (stamp.Exists && stamp.LastWriteTimeUtc > new FileInfo(aarFile.ItemSpec).LastWriteTimeUtc)
                {
                    continue;
                }
                // temporarily extracted directory will look like:
                // _lp_/[aarFile]
                using (var zip = MonoAndroidHelper.ReadZipFile(aarFile.ItemSpec)) {
                    try {
                        updated |= Files.ExtractAll(zip, importsDir, modifyCallback: (entryFullName) => {
                            var entryFileName = Path.GetFileName(entryFullName);
                            var entryPath     = Path.GetDirectoryName(entryFullName);
                            if (entryFileName.StartsWith("internal_impl", StringComparison.InvariantCulture))
                            {
                                var hash = Files.HashString(entryFileName);
                                return(Path.Combine(entryPath, $"internal_impl-{hash}.jar"));
                            }
                            return(entryFullName);
                        }, deleteCallback: (fileToDelete) => {
                            return(!jars.Contains(fileToDelete));
                        }, forceUpdate: false);

                        if (Directory.Exists(importsDir) && (updated || !stamp.Exists))
                        {
                            Log.LogDebugMessage("Touch {0}", stamp.FullName);
                            stamp.Create().Close();
                        }
                    } catch (PathTooLongException ex) {
                        Log.LogErrorFromException(new PathTooLongException($"Error extracting resources from \"{aarFile.ItemSpec}\"", ex));
                    }
                }
                if (Directory.Exists(resDir))
                {
                    resolvedResourceDirectories.Add(resDir);
                }
                if (Directory.Exists(assetsDir))
                {
                    resolvedAssetDirectories.Add(assetsDir);
                }
            }
            foreach (var f in outdir.EnumerateFiles("*.jar", SearchOption.AllDirectories)
                     .Select(fi => fi.FullName))
            {
                if (jars.Contains(f))
                {
                    continue;
                }
                jars.Add(f);
            }
        }
Example #25
0
        void Run(DirectoryAssemblyResolver res)
        {
            PackageNamingPolicy pnp;

            JavaNativeTypeManager.PackageNamingPolicy = Enum.TryParse(PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseHash;

            foreach (var dir in FrameworkDirectories)
            {
                if (Directory.Exists(dir.ItemSpec))
                {
                    res.SearchDirectories.Add(dir.ItemSpec);
                }
            }

            var selectedWhitelistAssemblies = new List <string> ();

            // Put every assembly we'll need in the resolver
            foreach (var assembly in ResolvedAssemblies)
            {
                var assemblyFullPath = Path.GetFullPath(assembly.ItemSpec);
                res.Load(assemblyFullPath);
                if (MonoAndroidHelper.FrameworkAttributeLookupTargets.Any(a => Path.GetFileName(assembly.ItemSpec) == a))
                {
                    selectedWhitelistAssemblies.Add(assemblyFullPath);
                }
            }

            // However we only want to look for JLO types in user code
            var assemblies  = ResolvedUserAssemblies.Select(p => p.ItemSpec).ToList();
            var fxAdditions = MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies(ResolvedAssemblies)
                              .Where(a => assemblies.All(x => Path.GetFileName(x) != Path.GetFileName(a)));

            assemblies = assemblies.Concat(fxAdditions).ToList();

            // Step 1 - Find all the JLO types
            var scanner = new JavaTypeScanner(this.CreateTaskLogger())
            {
                ErrorOnCustomJavaObject = ErrorOnCustomJavaObject,
            };
            var all_java_types = scanner.GetJavaTypes(assemblies, res);

            WriteTypeMappings(all_java_types);

            var java_types = all_java_types
                             .Where(t => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(t))
                             .ToArray();

            // Step 2 - Generate Java stub code
            var success = Generator.CreateJavaSources(
                Log,
                java_types,
                Path.Combine(OutputDirectory, "src"),
                ApplicationJavaClass,
                UseSharedRuntime,
                int.Parse(AndroidSdkPlatform) <= 10,
                ResolvedAssemblies.Any(assembly => Path.GetFileName(assembly.ItemSpec) == "Mono.Android.Export.dll"));

            if (!success)
            {
                return;
            }

            // We need to save a map of .NET type -> ACW type for resource file fixups
            var managed = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal);
            var java    = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal);

            // Allocate a MemoryStream with a reasonable guess at its capacity
            using (var stream = new MemoryStream(java_types.Length * 32))
                using (var acw_map = new StreamWriter(stream)) {
                    foreach (var type in java_types)
                    {
                        string managedKey = type.FullName.Replace('/', '.');
                        string javaKey    = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');

                        acw_map.Write(type.GetPartialAssemblyQualifiedName());
                        acw_map.Write(';');
                        acw_map.Write(javaKey);
                        acw_map.WriteLine();

                        TypeDefinition conflict;
                        if (managed.TryGetValue(managedKey, out conflict))
                        {
                            Log.LogWarning(
                                "Duplicate managed type found! Mappings between managed types and Java types must be unique. " +
                                "First Type: '{0}'; Second Type: '{1}'.",
                                conflict.GetAssemblyQualifiedName(),
                                type.GetAssemblyQualifiedName());
                            Log.LogWarning(
                                "References to the type '{0}' will refer to '{1}'.",
                                managedKey, conflict.GetAssemblyQualifiedName());
                            continue;
                        }
                        if (java.TryGetValue(javaKey, out conflict))
                        {
                            Log.LogError(
                                "Duplicate Java type found! Mappings between managed types and Java types must be unique. " +
                                "First Type: '{0}'; Second Type: '{1}'",
                                conflict.GetAssemblyQualifiedName(),
                                type.GetAssemblyQualifiedName());
                            success = false;
                            continue;
                        }

                        managed.Add(managedKey, type);
                        java.Add(javaKey, type);

                        acw_map.Write(managedKey);
                        acw_map.Write(';');
                        acw_map.Write(javaKey);
                        acw_map.WriteLine();

                        acw_map.Write(JavaNativeTypeManager.ToCompatJniName(type).Replace('/', '.'));
                        acw_map.Write(';');
                        acw_map.Write(javaKey);
                        acw_map.WriteLine();
                    }

                    acw_map.Flush();
                    MonoAndroidHelper.CopyIfStreamChanged(stream, AcwMapFile);
                }

            // Step 3 - Merge [Activity] and friends into AndroidManifest.xml
            var manifest = new ManifestDocument(ManifestTemplate, this.Log);

            manifest.PackageName     = PackageName;
            manifest.ApplicationName = ApplicationName ?? PackageName;
            manifest.Placeholders    = ManifestPlaceholders;
            manifest.Assemblies.AddRange(assemblies);
            manifest.Resolver          = res;
            manifest.SdkDir            = AndroidSdkDir;
            manifest.SdkVersion        = AndroidSdkPlatform;
            manifest.Debug             = Debug;
            manifest.MultiDex          = MultiDex;
            manifest.NeedsInternet     = NeedsInternet;
            manifest.InstantRunEnabled = InstantRunEnabled;

            var additionalProviders = manifest.Merge(all_java_types, selectedWhitelistAssemblies, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments);

            using (var stream = new MemoryStream()) {
                manifest.Save(stream);

                // Only write the new manifest if it actually changed
                MonoAndroidHelper.CopyIfStreamChanged(stream, MergedAndroidManifestOutput);
            }

            // Create additional runtime provider java sources.
            string providerTemplateFile = UseSharedRuntime ? "MonoRuntimeProvider.Shared.java" : "MonoRuntimeProvider.Bundled.java";
            string providerTemplate     = GetResource <JavaCallableWrapperGenerator> (providerTemplateFile);

            foreach (var provider in additionalProviders)
            {
                var contents      = providerTemplate.Replace("MonoRuntimeProvider", provider);
                var real_provider = Path.Combine(OutputDirectory, "src", "mono", provider + ".java");
                MonoAndroidHelper.CopyIfStringChanged(contents, real_provider);
            }

            // Create additional application java sources.
            StringWriter regCallsWriter = new StringWriter();

            regCallsWriter.WriteLine("\t\t// Application and Instrumentation ACWs must be registered first.");
            foreach (var type in java_types)
            {
                if (JavaNativeTypeManager.IsApplication(type) || JavaNativeTypeManager.IsInstrumentation(type))
                {
                    string javaKey = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');
                    regCallsWriter.WriteLine("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);",
                                             type.GetAssemblyQualifiedName(), javaKey);
                }
            }
            regCallsWriter.Close();

            var    real_app_dir            = Path.Combine(OutputDirectory, "src", "mono", "android", "app");
            string applicationTemplateFile = "ApplicationRegistration.java";

            SaveResource(applicationTemplateFile, applicationTemplateFile, real_app_dir,
                         template => template.Replace("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString()));

            // Create NotifyTimeZoneChanges java sources.
            string notifyTimeZoneChangesFile = "NotifyTimeZoneChanges.java";

            SaveResource(notifyTimeZoneChangesFile, notifyTimeZoneChangesFile, real_app_dir, template => template);
        }
Example #26
0
        // Extracts library project contents under e.g. obj/Debug/[__library_projects__/*.jar | res/*/*]
        // Extracts library project contents under e.g. obj/Debug/[lp/*.jar | res/*/*]
        public override bool Execute()
        {
            Log.LogDebugMessage("ResolveLibraryProjectImports Task");
            Log.LogDebugMessage("  ImportsDirectory: {0}", ImportsDirectory);
            Log.LogDebugMessage("  OutputDirectory: {0}", OutputDirectory);
            Log.LogDebugMessage("  OutputImportDirectory: {0}", OutputImportDirectory);
            Log.LogDebugMessage("  UseShortFileNames: {0}", UseShortFileNames);
            Log.LogDebugTaskItems("  Assemblies: ", Assemblies);
            Log.LogDebugTaskItems("  AarLibraries: ", AarLibraries);

            var jars = new List <string> ();
            var resolvedResourceDirectories = new List <string> ();
            var resolvedAssetDirectories    = new List <string> ();
            var resolvedEnvironmentFiles    = new List <string> ();

            assemblyMap.Load(AssemblyIdentityMapFile);

            using (var resolver = new DirectoryAssemblyResolver(this.CreateTaskLogger(), loadDebugSymbols: false)) {
                try {
                    Extract(resolver, jars, resolvedResourceDirectories, resolvedAssetDirectories, resolvedEnvironmentFiles);
                } catch (ZipIOException ex) {
                    Log.LogCodedError("XA1004", ex.Message);
                    Log.LogDebugMessage(ex.ToString());
                }
            }

            Jars = jars.ToArray();
            ResolvedResourceDirectories = resolvedResourceDirectories
                                          .Select(s => new TaskItem(Path.GetFullPath(s)))
                                          .ToArray();
            ResolvedAssetDirectories = resolvedAssetDirectories.ToArray();
            ResolvedEnvironmentFiles = resolvedEnvironmentFiles.ToArray();

            ResolvedResourceDirectoryStamps = ResolvedResourceDirectories
                                              .Select(s => new TaskItem(Path.GetFullPath(Path.Combine(s.ItemSpec, "../..")) + ".stamp"))
                                              .ToArray();

            foreach (var directory in ResolvedResourceDirectories)
            {
                MonoAndroidHelper.SetDirectoryWriteable(directory.ItemSpec);
            }

            foreach (var directory in ResolvedAssetDirectories)
            {
                MonoAndroidHelper.SetDirectoryWriteable(directory);
            }

            if (!string.IsNullOrEmpty(CacheFile))
            {
                var document = new XDocument(
                    new XDeclaration("1.0", "UTF-8", null),
                    new XElement("Paths",
                                 new XElement("Jars",
                                              Jars.Select(e => new XElement("Jar", e))),
                                 new XElement("ResolvedResourceDirectories",
                                              ResolvedResourceDirectories.Select(e => new XElement("ResolvedResourceDirectory", e))),
                                 new XElement("ResolvedAssetDirectories",
                                              ResolvedAssetDirectories.Select(e => new XElement("ResolvedAssetDirectory", e))),
                                 new XElement("ResolvedEnvironmentFiles",
                                              ResolvedEnvironmentFiles.Select(e => new XElement("ResolvedEnvironmentFile", e))),
                                 new XElement("ResolvedResourceDirectoryStamps",
                                              ResolvedResourceDirectoryStamps.Select(e => new XElement("ResolvedResourceDirectoryStamp", e)))
                                 ));
                document.SaveIfChanged(CacheFile);
            }

            assemblyMap.Save(AssemblyIdentityMapFile);

            Log.LogDebugTaskItems("  Jars: ", Jars.Select(s => new TaskItem(s)).ToArray());
            Log.LogDebugTaskItems("  ResolvedResourceDirectories: ", ResolvedResourceDirectories.Select(s => new TaskItem(s)).ToArray());
            Log.LogDebugTaskItems("  ResolvedAssetDirectories: ", ResolvedAssetDirectories.Select(s => new TaskItem(s)).ToArray());
            Log.LogDebugTaskItems("  ResolvedEnvironmentFiles: ", ResolvedEnvironmentFiles.Select(s => new TaskItem(s)).ToArray());
            Log.LogDebugTaskItems("  ResolvedResourceDirectoryStamps: ", ResolvedResourceDirectoryStamps);

            return(!Log.HasLoggedErrors);
        }
        void Run(DirectoryAssemblyResolver res)
        {
            PackageNamingPolicy pnp;

            JavaNativeTypeManager.PackageNamingPolicy = Enum.TryParse(PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseCrc64;

            foreach (var dir in FrameworkDirectories)
            {
                if (Directory.Exists(dir.ItemSpec))
                {
                    res.SearchDirectories.Add(dir.ItemSpec);
                }
            }

            // Put every assembly we'll need in the resolver
            bool hasExportReference   = false;
            bool haveMonoAndroid      = false;
            var  allTypemapAssemblies = new HashSet <string> (StringComparer.OrdinalIgnoreCase);
            var  userAssemblies       = new Dictionary <string, string> (StringComparer.OrdinalIgnoreCase);

            foreach (var assembly in ResolvedAssemblies)
            {
                bool value;
                if (bool.TryParse(assembly.GetMetadata(AndroidSkipJavaStubGeneration), out value) && value)
                {
                    Log.LogDebugMessage($"Skipping Java Stub Generation for {assembly.ItemSpec}");
                    continue;
                }

                bool   addAssembly = false;
                string fileName    = Path.GetFileName(assembly.ItemSpec);
                if (!hasExportReference && String.Compare("Mono.Android.Export.dll", fileName, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    hasExportReference = true;
                    addAssembly        = true;
                }
                else if (!haveMonoAndroid && String.Compare("Mono.Android.dll", fileName, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    haveMonoAndroid = true;
                    addAssembly     = true;
                }
                else if (MonoAndroidHelper.FrameworkAssembliesToTreatAsUserAssemblies.Contains(fileName))
                {
                    if (!bool.TryParse(assembly.GetMetadata(AndroidSkipJavaStubGeneration), out value) || !value)
                    {
                        string name = Path.GetFileNameWithoutExtension(fileName);
                        if (!userAssemblies.ContainsKey(name))
                        {
                            userAssemblies.Add(name, assembly.ItemSpec);
                        }
                        addAssembly = true;
                    }
                }

                if (addAssembly)
                {
                    allTypemapAssemblies.Add(assembly.ItemSpec);
                }

                res.Load(assembly.ItemSpec);
            }

            // However we only want to look for JLO types in user code for Java stub code generation
            foreach (var asm in ResolvedUserAssemblies)
            {
                if (bool.TryParse(asm.GetMetadata(AndroidSkipJavaStubGeneration), out bool value) && value)
                {
                    Log.LogDebugMessage($"Skipping Java Stub Generation for {asm.ItemSpec}");
                    continue;
                }
                allTypemapAssemblies.Add(asm.ItemSpec);
                userAssemblies.Add(Path.GetFileNameWithoutExtension(asm.ItemSpec), asm.ItemSpec);
            }

            // Step 1 - Find all the JLO types
            var cache   = new TypeDefinitionCache();
            var scanner = new JavaTypeScanner(this.CreateTaskLogger(), cache)
            {
                ErrorOnCustomJavaObject = ErrorOnCustomJavaObject,
            };

            List <TypeDefinition> allJavaTypes = scanner.GetJavaTypes(allTypemapAssemblies, res);

            // Step 2 - Generate type maps
            //   Type mappings need to use all the assemblies, always.
            WriteTypeMappings(allJavaTypes, cache);

            var javaTypes = new List <TypeDefinition> ();

            foreach (TypeDefinition td in allJavaTypes)
            {
                if (!userAssemblies.ContainsKey(td.Module.Assembly.Name.Name) || JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(td, cache))
                {
                    continue;
                }

                javaTypes.Add(td);
            }

            // Step 3 - Generate Java stub code
            var success = CreateJavaSources(javaTypes, cache);

            if (!success)
            {
                return;
            }

            // We need to save a map of .NET type -> ACW type for resource file fixups
            var managed = new Dictionary <string, TypeDefinition> (javaTypes.Count, StringComparer.Ordinal);
            var java    = new Dictionary <string, TypeDefinition> (javaTypes.Count, StringComparer.Ordinal);

            var managedConflicts = new Dictionary <string, List <string> > (0, StringComparer.Ordinal);
            var javaConflicts    = new Dictionary <string, List <string> > (0, StringComparer.Ordinal);

            using (var acw_map = MemoryStreamPool.Shared.CreateStreamWriter()) {
                foreach (TypeDefinition type in javaTypes)
                {
                    string managedKey = type.FullName.Replace('/', '.');
                    string javaKey    = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');

                    acw_map.Write(type.GetPartialAssemblyQualifiedName(cache));
                    acw_map.Write(';');
                    acw_map.Write(javaKey);
                    acw_map.WriteLine();

                    TypeDefinition conflict;
                    bool           hasConflict = false;
                    if (managed.TryGetValue(managedKey, out conflict))
                    {
                        if (!managedConflicts.TryGetValue(managedKey, out var list))
                        {
                            managedConflicts.Add(managedKey, list = new List <string> {
                                conflict.GetPartialAssemblyName(cache)
                            });
                        }
                        list.Add(type.GetPartialAssemblyName(cache));
                        hasConflict = true;
                    }
                    if (java.TryGetValue(javaKey, out conflict))
                    {
                        if (!javaConflicts.TryGetValue(javaKey, out var list))
                        {
                            javaConflicts.Add(javaKey, list = new List <string> {
                                conflict.GetAssemblyQualifiedName(cache)
                            });
                        }
                        list.Add(type.GetAssemblyQualifiedName(cache));
                        success     = false;
                        hasConflict = true;
                    }
                    if (!hasConflict)
                    {
                        managed.Add(managedKey, type);
                        java.Add(javaKey, type);

                        acw_map.Write(managedKey);
                        acw_map.Write(';');
                        acw_map.Write(javaKey);
                        acw_map.WriteLine();

                        acw_map.Write(JavaNativeTypeManager.ToCompatJniName(type, cache).Replace('/', '.'));
                        acw_map.Write(';');
                        acw_map.Write(javaKey);
                        acw_map.WriteLine();
                    }
                }

                acw_map.Flush();
                MonoAndroidHelper.CopyIfStreamChanged(acw_map.BaseStream, AcwMapFile);
            }

            foreach (var kvp in managedConflicts)
            {
                Log.LogCodedWarning("XA4214", Properties.Resources.XA4214, kvp.Key, string.Join(", ", kvp.Value));
                Log.LogCodedWarning("XA4214", Properties.Resources.XA4214_Result, kvp.Key, kvp.Value [0]);
            }

            foreach (var kvp in javaConflicts)
            {
                Log.LogCodedError("XA4215", Properties.Resources.XA4215, kvp.Key);
                foreach (var typeName in kvp.Value)
                {
                    Log.LogCodedError("XA4215", Properties.Resources.XA4215_Details, kvp.Key, typeName);
                }
            }

            // Step 3 - Merge [Activity] and friends into AndroidManifest.xml
            var manifest = new ManifestDocument(ManifestTemplate);

            manifest.PackageName     = PackageName;
            manifest.ApplicationName = ApplicationName ?? PackageName;
            manifest.Placeholders    = ManifestPlaceholders;
            manifest.Assemblies.AddRange(userAssemblies.Values);
            manifest.Resolver          = res;
            manifest.SdkDir            = AndroidSdkDir;
            manifest.SdkVersion        = AndroidSdkPlatform;
            manifest.Debug             = Debug;
            manifest.MultiDex          = MultiDex;
            manifest.NeedsInternet     = NeedsInternet;
            manifest.InstantRunEnabled = InstantRunEnabled;

            if (!String.IsNullOrWhiteSpace(CheckedBuild))
            {
                // We don't validate CheckedBuild value here, this will be done in BuildApk. We just know that if it's
                // on then we need android:debuggable=true and android:extractNativeLibs=true
                manifest.ForceDebuggable        = true;
                manifest.ForceExtractNativeLibs = true;
            }

            var additionalProviders = manifest.Merge(Log, cache, allJavaTypes, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments);

            // Only write the new manifest if it actually changed
            if (manifest.SaveIfChanged(Log, MergedAndroidManifestOutput))
            {
                Log.LogDebugMessage($"Saving: {MergedAndroidManifestOutput}");
            }

            // Create additional runtime provider java sources.
            string providerTemplateFile = "MonoRuntimeProvider.Bundled.java";
            string providerTemplate     = GetResource(providerTemplateFile);

            foreach (var provider in additionalProviders)
            {
                var contents      = providerTemplate.Replace("MonoRuntimeProvider", provider);
                var real_provider = Path.Combine(OutputDirectory, "src", "mono", provider + ".java");
                MonoAndroidHelper.CopyIfStringChanged(contents, real_provider);
            }

            // Create additional application java sources.
            StringWriter regCallsWriter = new StringWriter();

            regCallsWriter.WriteLine("\t\t// Application and Instrumentation ACWs must be registered first.");
            foreach (var type in javaTypes)
            {
                if (JavaNativeTypeManager.IsApplication(type, cache) || JavaNativeTypeManager.IsInstrumentation(type, cache))
                {
                    string javaKey = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');
                    regCallsWriter.WriteLine("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);",
                                             type.GetAssemblyQualifiedName(cache), javaKey);
                }
            }
            regCallsWriter.Close();

            var    real_app_dir            = Path.Combine(OutputDirectory, "src", "mono", "android", "app");
            string applicationTemplateFile = "ApplicationRegistration.java";

            SaveResource(applicationTemplateFile, applicationTemplateFile, real_app_dir,
                         template => template.Replace("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString()));
        }
Example #28
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;
            string api_versions_xml        = options.ApiVersionsXmlFile;
            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
            };

            // Load reference libraries

            foreach (var lib in options.LibraryPaths)
            {
                resolver.SearchDirectories.Add(lib);
            }
            foreach (var reference in references)
            {
                resolver.SearchDirectories.Add(Path.GetDirectoryName(reference));
            }
            foreach (var reference in references)
            {
                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).
                            if (td.HasGenericParameters &&
                                md.GetType(td.FullName.Substring(0, td.FullName.IndexOf('`'))) != null)
                            {
                                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.
            string apiXmlFile = filename;

            string apiSourceAttr = null;

            using (var xr = XmlReader.Create(filename)) {
                xr.MoveToContent();
                apiSourceAttr = xr.GetAttribute("api-source");
            }
            if (apiSourceAttr == "class-parse")
            {
                apiXmlFile = api_xml_adjuster_output ?? Path.Combine(Path.GetDirectoryName(filename), Path.GetFileName(filename) + ".adjusted");
                new Adjuster().Process(filename, SymbolTable.AllRegisteredSymbols().OfType <GenBase> ().ToArray(), apiXmlFile);
            }
            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();
            List <GenBase> gens = p.Parse(apiXmlFile, fixups, api_level, product_version);

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

            // disable interface default methods here, especially before validation.
            foreach (var gen in gens)
            {
                gen.StripNonBindables();
            }

            Validate(gens, opt);

            if (api_versions_xml != null)
            {
                ApiVersionsSupport.AssignApiLevels(gens, api_versions_xml, api_level);
            }

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

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

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

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

            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);
        }
        void Run(DirectoryAssemblyResolver res)
        {
            PackageNamingPolicy pnp;

            JavaNativeTypeManager.PackageNamingPolicy = Enum.TryParse(PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseCrc64;

            foreach (var dir in FrameworkDirectories)
            {
                if (Directory.Exists(dir.ItemSpec))
                {
                    res.SearchDirectories.Add(dir.ItemSpec);
                }
            }

            // Put every assembly we'll need in the resolver
            foreach (var assembly in ResolvedAssemblies)
            {
                if (bool.TryParse(assembly.GetMetadata(AndroidSkipJavaStubGeneration), out bool value) && value)
                {
                    Log.LogDebugMessage($"Skipping Java Stub Generation for {assembly.ItemSpec}");
                    continue;
                }
                res.Load(assembly.ItemSpec);
            }

            // However we only want to look for JLO types in user code
            List <string> assemblies = new List <string> ();

            foreach (var asm in ResolvedUserAssemblies)
            {
                if (bool.TryParse(asm.GetMetadata(AndroidSkipJavaStubGeneration), out bool value) && value)
                {
                    Log.LogDebugMessage($"Skipping Java Stub Generation for {asm.ItemSpec}");
                    continue;
                }
                if (!assemblies.All(x => Path.GetFileName(x) != Path.GetFileName(asm.ItemSpec)))
                {
                    continue;
                }
                Log.LogDebugMessage($"Adding {asm.ItemSpec} to assemblies.");
                assemblies.Add(asm.ItemSpec);
            }
            foreach (var asm in MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies(ResolvedAssemblies))
            {
                if (bool.TryParse(asm.GetMetadata(AndroidSkipJavaStubGeneration), out bool value) && value)
                {
                    Log.LogDebugMessage($"Skipping Java Stub Generation for {asm.ItemSpec}");
                    continue;
                }
                if (!assemblies.All(x => Path.GetFileName(x) != Path.GetFileName(asm.ItemSpec)))
                {
                    continue;
                }
                Log.LogDebugMessage($"Adding {asm.ItemSpec} to assemblies.");
                assemblies.Add(asm.ItemSpec);
            }

            // Step 1 - Find all the JLO types
            var scanner = new JavaTypeScanner(this.CreateTaskLogger())
            {
                ErrorOnCustomJavaObject = ErrorOnCustomJavaObject,
            };
            var all_java_types = scanner.GetJavaTypes(assemblies, res);

            WriteTypeMappings(all_java_types);

            var java_types = all_java_types
                             .Where(t => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(t))
                             .ToArray();

            // Step 2 - Generate Java stub code
            var success = Generator.CreateJavaSources(
                Log,
                java_types,
                Path.Combine(OutputDirectory, "src"),
                ApplicationJavaClass,
                AndroidSdkPlatform,
                UseSharedRuntime,
                int.Parse(AndroidSdkPlatform) <= 10,
                ResolvedAssemblies.Any(assembly => Path.GetFileName(assembly.ItemSpec) == "Mono.Android.Export.dll"));

            if (!success)
            {
                return;
            }

            // We need to save a map of .NET type -> ACW type for resource file fixups
            var managed = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal);
            var java    = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal);

            var managedConflicts = new Dictionary <string, List <string> > (0, StringComparer.Ordinal);
            var javaConflicts    = new Dictionary <string, List <string> > (0, StringComparer.Ordinal);

            // Allocate a MemoryStream with a reasonable guess at its capacity
            using (var stream = new MemoryStream(java_types.Length * 32))
                using (var acw_map = new StreamWriter(stream)) {
                    foreach (var type in java_types)
                    {
                        string managedKey = type.FullName.Replace('/', '.');
                        string javaKey    = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');

                        acw_map.Write(type.GetPartialAssemblyQualifiedName());
                        acw_map.Write(';');
                        acw_map.Write(javaKey);
                        acw_map.WriteLine();

                        TypeDefinition conflict;
                        bool           hasConflict = false;
                        if (managed.TryGetValue(managedKey, out conflict))
                        {
                            if (!managedConflicts.TryGetValue(managedKey, out var list))
                            {
                                managedConflicts.Add(managedKey, list = new List <string> {
                                    conflict.GetPartialAssemblyName()
                                });
                            }
                            list.Add(type.GetPartialAssemblyName());
                            hasConflict = true;
                        }
                        if (java.TryGetValue(javaKey, out conflict))
                        {
                            if (!javaConflicts.TryGetValue(javaKey, out var list))
                            {
                                javaConflicts.Add(javaKey, list = new List <string> {
                                    conflict.GetAssemblyQualifiedName()
                                });
                            }
                            list.Add(type.GetAssemblyQualifiedName());
                            success     = false;
                            hasConflict = true;
                        }
                        if (!hasConflict)
                        {
                            managed.Add(managedKey, type);
                            java.Add(javaKey, type);

                            acw_map.Write(managedKey);
                            acw_map.Write(';');
                            acw_map.Write(javaKey);
                            acw_map.WriteLine();

                            acw_map.Write(JavaNativeTypeManager.ToCompatJniName(type).Replace('/', '.'));
                            acw_map.Write(';');
                            acw_map.Write(javaKey);
                            acw_map.WriteLine();
                        }
                    }

                    acw_map.Flush();
                    MonoAndroidHelper.CopyIfStreamChanged(stream, AcwMapFile);
                }

            foreach (var kvp in managedConflicts)
            {
                Log.LogCodedWarning("XA4214", Properties.Resources.XA4214, kvp.Key, string.Join(", ", kvp.Value));
                Log.LogCodedWarning("XA4214", Properties.Resources.XA4214_Result, kvp.Key, kvp.Value [0]);
            }

            foreach (var kvp in javaConflicts)
            {
                Log.LogCodedError(
                    "XA4215",
                    "The Java type `{0}` is generated by more than one managed type. " +
                    "Please change the [Register] attribute so that the same Java type is not emitted.",
                    kvp.Key);
                foreach (var typeName in kvp.Value)
                {
                    Log.LogCodedError("XA4215", "  `{0}` generated by: {1}", kvp.Key, typeName);
                }
            }

            // Step 3 - Merge [Activity] and friends into AndroidManifest.xml
            var manifest = new ManifestDocument(ManifestTemplate, this.Log);

            manifest.PackageName     = PackageName;
            manifest.ApplicationName = ApplicationName ?? PackageName;
            manifest.Placeholders    = ManifestPlaceholders;
            manifest.Assemblies.AddRange(assemblies);
            manifest.Resolver          = res;
            manifest.SdkDir            = AndroidSdkDir;
            manifest.SdkVersion        = AndroidSdkPlatform;
            manifest.Debug             = Debug;
            manifest.MultiDex          = MultiDex;
            manifest.NeedsInternet     = NeedsInternet;
            manifest.InstantRunEnabled = InstantRunEnabled;

            var additionalProviders = manifest.Merge(all_java_types, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName);

            using (var stream = new MemoryStream()) {
                manifest.Save(stream);

                // Only write the new manifest if it actually changed
                MonoAndroidHelper.CopyIfStreamChanged(stream, MergedAndroidManifestOutput);
            }

            // Create additional runtime provider java sources.
            string providerTemplateFile = UseSharedRuntime ? "MonoRuntimeProvider.Shared.java" : "MonoRuntimeProvider.Bundled.java";
            string providerTemplate     = GetResource(providerTemplateFile);

            foreach (var provider in additionalProviders)
            {
                var contents      = providerTemplate.Replace("MonoRuntimeProvider", provider);
                var real_provider = Path.Combine(OutputDirectory, "src", "mono", provider + ".java");
                MonoAndroidHelper.CopyIfStringChanged(contents, real_provider);
            }

            // Create additional application java sources.
            StringWriter regCallsWriter = new StringWriter();

            regCallsWriter.WriteLine("\t\t// Application and Instrumentation ACWs must be registered first.");
            foreach (var type in java_types)
            {
                if (JavaNativeTypeManager.IsApplication(type) || JavaNativeTypeManager.IsInstrumentation(type))
                {
                    string javaKey = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');
                    regCallsWriter.WriteLine("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);",
                                             type.GetAssemblyQualifiedName(), javaKey);
                }
            }
            regCallsWriter.Close();

            var    real_app_dir            = Path.Combine(OutputDirectory, "src", "mono", "android", "app");
            string applicationTemplateFile = "ApplicationRegistration.java";

            SaveResource(applicationTemplateFile, applicationTemplateFile, real_app_dir,
                         template => template.Replace("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString()));
        }
Example #30
0
        void Run(DirectoryAssemblyResolver res)
        {
            PackageNamingPolicy pnp;

            JavaNativeTypeManager.PackageNamingPolicy = Enum.TryParse(PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseHash;

            foreach (var dir in FrameworkDirectories)
            {
                if (Directory.Exists(dir.ItemSpec))
                {
                    res.SearchDirectories.Add(dir.ItemSpec);
                }
            }

            var selectedWhitelistAssemblies = new List <string> ();

            // Put every assembly we'll need in the resolver
            foreach (var assembly in ResolvedAssemblies)
            {
                var assemblyFullPath = Path.GetFullPath(assembly.ItemSpec);
                res.Load(assemblyFullPath);
                if (MonoAndroidHelper.FrameworkAttributeLookupTargets.Any(a => Path.GetFileName(assembly.ItemSpec) == a))
                {
                    selectedWhitelistAssemblies.Add(assemblyFullPath);
                }
            }

            // However we only want to look for JLO types in user code
            var assemblies  = ResolvedUserAssemblies.Select(p => p.ItemSpec).ToList();
            var fxAdditions = MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies(ResolvedAssemblies)
                              .Where(a => assemblies.All(x => Path.GetFileName(x) != Path.GetFileName(a)));

            assemblies = assemblies.Concat(fxAdditions).ToList();

            // Step 1 - Find all the JLO types
            var scanner = new JavaTypeScanner(this.CreateTaskLogger())
            {
                ErrorOnCustomJavaObject = ErrorOnCustomJavaObject,
            };
            var all_java_types = scanner.GetJavaTypes(assemblies, res);

            WriteTypeMappings(all_java_types);

            var java_types = all_java_types
                             .Where(t => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(t))
                             .ToArray();

            // Step 2 - Generate Java stub code
            var success = Generator.CreateJavaSources(
                Log,
                java_types,
                Path.Combine(OutputDirectory, "src"),
                ApplicationJavaClass,
                UseSharedRuntime,
                int.Parse(AndroidSdkPlatform) <= 10,
                ResolvedAssemblies.Any(assembly => Path.GetFileName(assembly.ItemSpec) == "Mono.Android.Export.dll"));

            if (!success)
            {
                return;
            }

            // We need to save a map of .NET type -> ACW type for resource file fixups
            var managed = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal);
            var java    = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal);

            var managedConflicts = new Dictionary <string, List <string> > (0, StringComparer.Ordinal);
            var javaConflicts    = new Dictionary <string, List <string> > (0, StringComparer.Ordinal);

            // Allocate a MemoryStream with a reasonable guess at its capacity
            using (var stream = new MemoryStream(java_types.Length * 32))
                using (var acw_map = new StreamWriter(stream)) {
                    foreach (var type in java_types)
                    {
                        string managedKey = type.FullName.Replace('/', '.');
                        string javaKey    = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');

                        acw_map.Write(type.GetPartialAssemblyQualifiedName());
                        acw_map.Write(';');
                        acw_map.Write(javaKey);
                        acw_map.WriteLine();

                        TypeDefinition conflict;
                        bool           hasConflict = false;
                        if (managed.TryGetValue(managedKey, out conflict))
                        {
                            if (!managedConflicts.TryGetValue(managedKey, out var list))
                            {
                                managedConflicts.Add(managedKey, list = new List <string> {
                                    conflict.GetPartialAssemblyName()
                                });
                            }
                            list.Add(type.GetPartialAssemblyName());
                            hasConflict = true;
                        }
                        if (java.TryGetValue(javaKey, out conflict))
                        {
                            if (!javaConflicts.TryGetValue(javaKey, out var list))
                            {
                                javaConflicts.Add(javaKey, list = new List <string> {
                                    conflict.GetAssemblyQualifiedName()
                                });
                            }
                            list.Add(type.GetAssemblyQualifiedName());
                            success     = false;
                            hasConflict = true;
                        }
                        if (!hasConflict)
                        {
                            managed.Add(managedKey, type);
                            java.Add(javaKey, type);

                            acw_map.Write(managedKey);
                            acw_map.Write(';');
                            acw_map.Write(javaKey);
                            acw_map.WriteLine();

                            acw_map.Write(JavaNativeTypeManager.ToCompatJniName(type).Replace('/', '.'));
                            acw_map.Write(';');
                            acw_map.Write(javaKey);
                            acw_map.WriteLine();
                        }
                    }

                    acw_map.Flush();
                    MonoAndroidHelper.CopyIfStreamChanged(stream, AcwMapFile);
                }

            foreach (var kvp in managedConflicts)
            {
                Log.LogCodedWarning(
                    "XA4214",
                    "The managed type `{0}` exists in multiple assemblies: {1}. " +
                    "Please refactor the managed type names in these assemblies so that they are not identical.",
                    kvp.Key,
                    string.Join(", ", kvp.Value));
                Log.LogCodedWarning("XA4214", "References to the type `{0}` will refer to `{0}, {1}`.", kvp.Key, kvp.Value [0]);
            }

            foreach (var kvp in javaConflicts)
            {
                Log.LogCodedError(
                    "XA4215",
                    "The Java type `{0}` is generated by more than one managed type. " +
                    "Please change the [Register] attribute so that the same Java type is not emitted.",
                    kvp.Key);
                foreach (var typeName in kvp.Value)
                {
                    Log.LogCodedError("XA4215", "  `{0}` generated by: {1}", kvp.Key, typeName);
                }
            }

            // Step 3 - Merge [Activity] and friends into AndroidManifest.xml
            var manifest = new ManifestDocument(ManifestTemplate, this.Log);

            manifest.PackageName     = PackageName;
            manifest.ApplicationName = ApplicationName ?? PackageName;
            manifest.Placeholders    = ManifestPlaceholders;
            manifest.Assemblies.AddRange(assemblies);
            manifest.Resolver          = res;
            manifest.SdkDir            = AndroidSdkDir;
            manifest.SdkVersion        = AndroidSdkPlatform;
            manifest.Debug             = Debug;
            manifest.MultiDex          = MultiDex;
            manifest.NeedsInternet     = NeedsInternet;
            manifest.InstantRunEnabled = InstantRunEnabled;

            var additionalProviders = manifest.Merge(all_java_types, selectedWhitelistAssemblies, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments);

            using (var stream = new MemoryStream()) {
                manifest.Save(stream);

                // Only write the new manifest if it actually changed
                MonoAndroidHelper.CopyIfStreamChanged(stream, MergedAndroidManifestOutput);
            }

            // Create the CacheFile if needed
            if (!string.IsNullOrEmpty(CacheFile))
            {
                bool extractNativeLibraries = manifest.ExtractNativeLibraries();
                if (!extractNativeLibraries)
                {
                    //We need to write the value to a file, if _GenerateJavaStubs is skipped on incremental builds
                    var document = new XDocument(
                        new XDeclaration("1.0", "UTF-8", null),
                        new XElement("Properties", new XElement(nameof(ReadJavaStubsCache.EmbeddedDSOsEnabled), "True"))
                        );
                    document.SaveIfChanged(CacheFile);
                }
                else
                {
                    //Delete the file otherwise, since we only need to specify when EmbeddedDSOsEnabled=True
                    File.Delete(CacheFile);
                }
            }

            // Create additional runtime provider java sources.
            string providerTemplateFile = UseSharedRuntime ? "MonoRuntimeProvider.Shared.java" : "MonoRuntimeProvider.Bundled.java";
            string providerTemplate     = GetResource <JavaCallableWrapperGenerator> (providerTemplateFile);

            foreach (var provider in additionalProviders)
            {
                var contents      = providerTemplate.Replace("MonoRuntimeProvider", provider);
                var real_provider = Path.Combine(OutputDirectory, "src", "mono", provider + ".java");
                MonoAndroidHelper.CopyIfStringChanged(contents, real_provider);
            }

            // Create additional application java sources.
            StringWriter regCallsWriter = new StringWriter();

            regCallsWriter.WriteLine("\t\t// Application and Instrumentation ACWs must be registered first.");
            foreach (var type in java_types)
            {
                if (JavaNativeTypeManager.IsApplication(type) || JavaNativeTypeManager.IsInstrumentation(type))
                {
                    string javaKey = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');
                    regCallsWriter.WriteLine("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);",
                                             type.GetAssemblyQualifiedName(), javaKey);
                }
            }
            regCallsWriter.Close();

            var    real_app_dir            = Path.Combine(OutputDirectory, "src", "mono", "android", "app");
            string applicationTemplateFile = "ApplicationRegistration.java";

            SaveResource(applicationTemplateFile, applicationTemplateFile, real_app_dir,
                         template => template.Replace("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString()));

            // Create NotifyTimeZoneChanges java sources.
            string notifyTimeZoneChangesFile = "NotifyTimeZoneChanges.java";

            SaveResource(notifyTimeZoneChangesFile, notifyTimeZoneChangesFile, real_app_dir, template => template);
        }
        bool Execute(DirectoryAssemblyResolver res)
        {
            foreach (var assembly in Assemblies)
            {
                res.Load(Path.GetFullPath(assembly.ItemSpec));
            }

            foreach (var assemblyName in Assemblies)
            {
                var    suffix   = assemblyName.ItemSpec.EndsWith(".dll") ? String.Empty : ".dll";
                string hintPath = assemblyName.GetMetadata("HintPath").Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
                string fileName = assemblyName.ItemSpec + suffix;
                if (!String.IsNullOrEmpty(hintPath) && !File.Exists(hintPath))                   // ignore invalid HintPath
                {
                    hintPath = null;
                }
                string assemblyPath = String.IsNullOrEmpty(hintPath) ? fileName : hintPath;
                if (MonoAndroidHelper.IsFrameworkAssembly(fileName) && !MonoAndroidHelper.FrameworkEmbeddedJarLookupTargets.Contains(Path.GetFileName(fileName)))
                {
                    continue;
                }

                var  assembly          = res.GetAssembly(assemblyPath);
                bool assembly_modified = false;
                foreach (var mod in assembly.Modules)
                {
                    // embedded jars
                    var resjars = mod.Resources.Where(r => r.Name.EndsWith(".jar", StringComparison.InvariantCultureIgnoreCase)).Select(r => (EmbeddedResource)r);
                    foreach (var resjar in resjars.ToArray())
                    {
                        Log.LogDebugMessage("    Stripped {0}", resjar.Name);
                        mod.Resources.Remove(resjar);
                        assembly_modified = true;
                    }
                    // embedded AndroidNativeLibrary archive
                    var nativezip = mod.Resources.FirstOrDefault(r => r.Name == "__AndroidNativeLibraries__.zip") as EmbeddedResource;
                    if (nativezip != null)
                    {
                        Log.LogDebugMessage("    Stripped {0}", nativezip.Name);
                        mod.Resources.Remove(nativezip);
                        assembly_modified = true;
                    }
                    // embedded AndroidResourceLibrary archive
                    var reszip = mod.Resources.FirstOrDefault(r => r.Name == "__AndroidLibraryProjects__.zip") as EmbeddedResource;
                    if (reszip != null)
                    {
                        Log.LogDebugMessage("    Stripped {0}", reszip.Name);
                        mod.Resources.Remove(reszip);
                        assembly_modified = true;
                    }
                }
                if (assembly_modified)
                {
                    Log.LogDebugMessage("    The stripped library is saved as {0}", assemblyPath);

                    // Output assembly needs to regenerate symbol file even if no IL/metadata was touched
                    // because Cecil still rewrites all assembly types in Cecil order (type A, nested types of A, type B, etc)
                    // and not in the original order causing symbols if original order doesn't match Cecil order
                    var wp = new WriterParameters()
                    {
                        WriteSymbols = assembly.MainModule.HasSymbols
                    };

                    assembly.Write(wp);
                }
            }
            return(true);
        }
        public override bool Execute()
        {
            Log.LogDebugMessage ("LinkAssemblies Task");
            Log.LogDebugMessage ("  UseSharedRuntime: {0}", UseSharedRuntime);
            Log.LogDebugMessage ("  MainAssembly: {0}", MainAssembly);
            Log.LogDebugMessage ("  OutputDirectory: {0}", OutputDirectory);
            Log.LogDebugMessage ("  OptionalDestinationDirectory: {0}", OptionalDestinationDirectory);
            Log.LogDebugMessage ("  I18nAssemblies: {0}", I18nAssemblies);
            Log.LogDebugMessage ("  LinkMode: {0}", LinkMode);
            Log.LogDebugMessage ("  LinkSkip: {0}", LinkSkip);
            Log.LogDebugTaskItems ("  LinkDescriptions:", LinkDescriptions);
            Log.LogDebugTaskItems ("  ResolvedAssemblies:", ResolvedAssemblies);
            Log.LogDebugMessage ("  EnableProguard: {0}", EnableProguard);
            Log.LogDebugMessage ("  ProguardConfiguration: {0}", ProguardConfiguration);
            Log.LogDebugMessage ("  DumpDependencies: {0}", DumpDependencies);
            Log.LogDebugMessage ("  LinkOnlyNewerThan: {0}", LinkOnlyNewerThan);

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

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

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

            // Set up for linking
            var options = new LinkerOptions ();
            options.MainAssembly = res.GetAssembly (MainAssembly);
            options.OutputDirectory = Path.GetFullPath (OutputDirectory);
            options.LinkSdkOnly = string.Compare (LinkMode, "SdkOnly", true) == 0;
            options.LinkNone = string.Compare (LinkMode, "None", true) == 0;
            options.Resolver = resolver;
            options.LinkDescriptions = LinkDescriptions.Select (item => Path.GetFullPath (item.ItemSpec)).ToArray ();
            options.I18nAssemblies = Linker.ParseI18nAssemblies (I18nAssemblies);
            if (!options.LinkSdkOnly)
                options.RetainAssemblies = GetRetainAssemblies (res);
            options.DumpDependencies = DumpDependencies;

            var skiplist = new List<string> ();

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

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

            options.SkippedAssemblies = skiplist;

            if (EnableProguard)
                options.ProguardConfiguration = ProguardConfiguration;

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

                var copydst = OptionalDestinationDirectory ?? OutputDirectory;

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

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

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

            return true;
        }
        public override bool Execute()
        {
            LogDebugMessage ("GetAdditionalResourcesFromAssemblies Task");
            LogDebugMessage ("  AndroidSdkDirectory: {0}", AndroidSdkDirectory);
            LogDebugMessage ("  AndroidNdkDirectory: {0}", AndroidNdkDirectory);
            LogDebugTaskItems ("  Assemblies: ", Assemblies);

            if (Environment.GetEnvironmentVariable ("XA_DL_IGNORE_CERT_ERRROS") == "yesyesyes") {
                ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
                LogDebugMessage ("    Disabling download certificate validation callback.");
            }
            var androidResources   = new HashSet<string> ();
            var javaLibraries      = new HashSet<string> ();
            var nativeLibraries    = new HashSet<string> ();
            var assemblies         = new HashSet<string> ();

            if (Assemblies == null)
                return true;

            System.Threading.Tasks.Task.Run (() => {
                // The cache location can be overriden by the (to be documented) XAMARIN_CACHEPATH
                CachePath = Environment.ExpandEnvironmentVariables (CachePathEnvironmentVar);
                CachePath = CachePath != CachePathEnvironmentVar
                ? CachePath
                : Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData), CacheBaseDir);

                var resolver = new DirectoryAssemblyResolver (Log.LogWarning, loadDebugSymbols: false);
                foreach (var assemblyItem in Assemblies) {
                    string fullPath = Path.GetFullPath (assemblyItem.ItemSpec);
                    if (assemblies.Contains (fullPath)) {
                        LogDebugMessage ("  Skip assembly: {0}, it was already processed", fullPath);
                        continue;
                    }
                    assemblies.Add (fullPath);
                    resolver.Load (fullPath);
                    // Append source file name (without the Xamarin. prefix or extension) to the base folder
                    // This would help avoid potential collisions.
                    foreach (var ca in resolver.GetAssembly (assemblyItem.ItemSpec).CustomAttributes) {
                        switch (ca.AttributeType.FullName) {
                        case "Android.IncludeAndroidResourcesFromAttribute":
                            AddAttributeValue (androidResources, ca, "XA5206", "{0}. Android resource directory {1} doesn't exist.", true, fullPath);
                            break;
                        case "Java.Interop.JavaLibraryReferenceAttribute":
                            AddAttributeValue (javaLibraries, ca, "XA5207", "{0}. Java library file {1} doesn't exist.", false, fullPath);
                            break;
                        case "Android.NativeLibraryReferenceAttribute":
                            AddAttributeValue (nativeLibraries, ca, "XA5210", "{0}. Native library file {1} doesn't exist.", false, fullPath);
                            break;
                        }
                    }
                }
            }).ContinueWith ((t) => {
                if (t.Exception != null)
                    Log.LogErrorFromException (t.Exception.GetBaseException ());
                Complete ();
            });

            var result = base.Execute ();

            var AdditionalAndroidResourcePaths = androidResources.ToArray ();
            var AdditionalJavaLibraryReferences = javaLibraries.ToArray ();
            var AdditionalNativeLibraryReferences = nativeLibraries
                .Where (x => MonoAndroidHelper.GetNativeLibraryAbi (x) != null)
                .ToArray ();

            var document = new XDocument (
                new XDeclaration ("1.0", "UTF-8", null),
                new XElement ("Paths",
                    new XElement ("AdditionalAndroidResourcePaths",
                            AdditionalAndroidResourcePaths.Select(e => new XElement ("AdditionalAndroidResourcePath", e))),
                    new XElement ("AdditionalJavaLibraryReferences",
                            AdditionalJavaLibraryReferences.Select(e => new XElement ("AdditionalJavaLibraryReference", e))),
                    new XElement ("AdditionalNativeLibraryReferences",
                            AdditionalNativeLibraryReferences.Select(e => new XElement ("AdditionalNativeLibraryReference", e)))
                    ));
            document.Save (CacheFile);

            LogDebugTaskItems ("  AdditionalAndroidResourcePaths: ", AdditionalAndroidResourcePaths);
            LogDebugTaskItems ("  AdditionalJavaLibraryReferences: ", AdditionalJavaLibraryReferences);
            LogDebugTaskItems ("  AdditionalNativeLibraryReferences: ", AdditionalNativeLibraryReferences);

            return result && !Log.HasLoggedErrors;
        }
Example #34
0
 void AddNativeLibrariesFromAssemblies(ZipFile apk, string supportedAbis)
 {
     var abis = supportedAbis.Split (new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
     var res = new DirectoryAssemblyResolver (Console.WriteLine, loadDebugSymbols: false);
     foreach (var assembly in EmbeddedNativeLibraryAssemblies)
         res.Load (assembly.ItemSpec);
     foreach (var assemblyPath in EmbeddedNativeLibraryAssemblies) {
         var assembly = res.GetAssembly (assemblyPath.ItemSpec);
         foreach (var mod in assembly.Modules) {
             var ressozip = mod.Resources.FirstOrDefault (r => r.Name == "__AndroidNativeLibraries__.zip") as EmbeddedResource;
             if (ressozip == null)
                 continue;
             var data = ressozip.GetResourceData ();
             using (var ms = new MemoryStream (data)) {
                 using (var zip = ZipFile.Read (ms)) {
                     foreach (var e in zip.Entries.Where (x => abis.Any (a => x.FileName.Contains (a)))) {
                         if (e.IsDirectory)
                             continue;
                         var key = e.FileName.Replace ("native_library_imports", "lib");
                         if (apk.ContainsEntry (key)) {
                             Log.LogCodedWarning ("4301", "Apk already contains the item {0}; ignoring.", key);
                             continue;
                         }
                         using (var s = new MemoryStream ()) {
                             e.Extract (s);
                             apk.AddEntry (key, s.ToArray ());
                         }
                     }
                 }
             }
         }
     }
 }
Example #35
0
        public static int Main(string [] args)
        {
            var resolver = new DirectoryAssemblyResolver(logWarnings: Console.WriteLine, loadDebugSymbols: false);

            bool   help       = false;
            string outputPath = null;
            int    verbosity  = 0;

            var options = new OptionSet {
                "Usage: jcw-gen.exe OPTIONS* ASSEMBLY+",
                "",
                "Generates Java Callable Wrappers from specified assemblies.",
                "",
                "Copyright 2016 Xamarin Inc.",
                "",
                "Options:",
                { "L=",
                  "{DIRECTORY} to resolve assemblies from.",
                  v => resolver.SearchDirectories.Add(v) },
                { "o=",
                  "{DIRECTORY} to write Java source code to.",
                  v => outputPath = v },
                { "v:",
                  "Logging verbosity.",
                  (int?v) => verbosity = v.HasValue ? v.Value : verbosity + 1 },
                { "h|help|?",
                  "Show this message and exit",
                  v => help = v != null },
            };

            try {
                var assemblies = options.Parse(args);
                if (assemblies.Count == 0 || outputPath == null || help)
                {
                    int r = 0;
                    if (assemblies.Count == 0)
                    {
                        Console.Error.WriteLine("jcw-gen: No assemblies specified.");
                        r = 1;
                    }
                    else if (outputPath == null)
                    {
                        Console.Error.WriteLine("jcw-gen: No output directory specified. Use `jcw-gen -o PATH`.");
                        r = 1;
                    }
                    options.WriteOptionDescriptions(Console.Out);
                    return(r);
                }
                foreach (var assembly in assemblies)
                {
                    resolver.SearchDirectories.Add(Path.GetDirectoryName(assembly));
                    resolver.Load(assembly);
                }
                var types = JavaTypeScanner.GetJavaTypes(assemblies, resolver, log: Console.WriteLine)
                            .Where(td => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(td));
                foreach (var type in types)
                {
                    GenerateJavaCallableWrapper(type, outputPath);
                }
                return(0);
            }
            catch (Exception e) {
                Console.Error.Write("jcw-gen: {0}", verbosity > 0 ? e.ToString() : e.Message);
                return(1);
            }
        }
        public override bool RunTask()
        {
            if (SourceFiles.Length != DestinationFiles.Length)
            {
                throw new ArgumentException("source and destination count mismatch");
            }

            var readerParameters = new ReaderParameters {
                ReadSymbols = true,
            };
            var writerParameters = new WriterParameters {
                DeterministicMvid = Deterministic,
            };

            var hasSystemPrivateCorelib = false;

            using (var resolver = new DirectoryAssemblyResolver(this.CreateTaskLogger(), loadDebugSymbols: true, loadReaderParameters: readerParameters)) {
                // Add SearchDirectories with ResolvedAssemblies
                foreach (var assembly in ResolvedAssemblies)
                {
                    var path = Path.GetFullPath(Path.GetDirectoryName(assembly.ItemSpec));
                    if (Path.GetFileName(assembly.ItemSpec).Equals("System.Private.CoreLib.dll", StringComparison.OrdinalIgnoreCase))
                    {
                        hasSystemPrivateCorelib = true;
                    }

                    if (!resolver.SearchDirectories.Contains(path))
                    {
                        resolver.SearchDirectories.Add(path);
                    }
                }

                // Set up the FixAbstractMethodsStep
                var step1 = new FixAbstractMethodsStep(resolver, new TypeDefinitionCache(), Log);
                // Set up the AddKeepAlivesStep
                var step2 = new AddKeepAlivesStep(resolver, new TypeDefinitionCache(), Log, hasSystemPrivateCorelib);
                for (int i = 0; i < SourceFiles.Length; i++)
                {
                    var source      = SourceFiles [i];
                    var destination = DestinationFiles [i];
                    AssemblyDefinition assemblyDefinition = null;

                    var assemblyName = Path.GetFileNameWithoutExtension(source.ItemSpec);
                    if (!MTProfile.IsSdkAssembly(assemblyName) && !MTProfile.IsProductAssembly(assemblyName))
                    {
                        assemblyDefinition = resolver.GetAssembly(source.ItemSpec);
                        step1.CheckAppDomainUsage(assemblyDefinition, (string msg) => Log.LogMessageFromText(msg, MessageImportance.High));
                    }

                    // Only run the step on "MonoAndroid" assemblies
                    if (MonoAndroidHelper.IsMonoAndroidAssembly(source) && !MonoAndroidHelper.IsSharedRuntimeAssembly(source.ItemSpec))
                    {
                        if (assemblyDefinition == null)
                        {
                            assemblyDefinition = resolver.GetAssembly(source.ItemSpec);
                        }

                        if (step1.FixAbstractMethods(assemblyDefinition) ||
                            (AddKeepAlives && step2.AddKeepAlives(assemblyDefinition)))
                        {
                            Log.LogDebugMessage($"Saving modified assembly: {destination.ItemSpec}");
                            writerParameters.WriteSymbols = assemblyDefinition.MainModule.HasSymbols;
                            assemblyDefinition.Write(destination.ItemSpec, writerParameters);
                            continue;
                        }
                    }

                    if (MonoAndroidHelper.CopyAssemblyAndSymbols(source.ItemSpec, destination.ItemSpec))
                    {
                        Log.LogDebugMessage($"Copied: {destination.ItemSpec}");
                    }
                    else
                    {
                        Log.LogDebugMessage($"Skipped unchanged file: {destination.ItemSpec}");

                        // NOTE: We still need to update the timestamp on this file, or this target would run again
                        File.SetLastWriteTimeUtc(destination.ItemSpec, DateTime.UtcNow);
                    }
                }
            }

            return(!Log.HasLoggedErrors);
        }
 IEnumerable<AssemblyDefinition> GetRetainAssemblies(DirectoryAssemblyResolver res)
 {
     List<AssemblyDefinition> retainList = null;
     foreach (var assembly in ResolvedAssemblies) {
         var filename = Path.GetFileName (assembly.ItemSpec);
         if (!MonoAndroidHelper.IsForceRetainedAssembly (filename))
             continue;
         if (retainList == null)
             retainList = new List<AssemblyDefinition> ();
         retainList.Add (res.GetAssembly (assembly.ItemSpec));
     }
     return retainList;
 }
Example #38
0
        public override bool Execute()
        {
            // In Xamarin Studio, if the project name isn't a valid C# identifier
            // then $(RootNamespace) is not set, and the generated Activity is
            // placed into the "Application" namespace. VS just munges the project
            // name to be a valid C# identifier.
            // Use "Application" as the default namespace name to work with XS.
            Namespace = Namespace ?? "Application";

            Log.LogDebugMessage("GenerateResourceDesigner Task");
            Log.LogDebugMessage("  NetResgenOutputFile: {0}", NetResgenOutputFile);
            Log.LogDebugMessage("  JavaResgenInputFile: {0}", JavaResgenInputFile);
            Log.LogDebugMessage("  Namespace: {0}", Namespace);
            Log.LogDebugMessage("  ResourceDirectory: {0}", ResourceDirectory);
            Log.LogDebugTaskItemsAndLogical("  AdditionalResourceDirectories:", AdditionalResourceDirectories);
            Log.LogDebugMessage("  IsApplication: {0}", IsApplication);
            Log.LogDebugMessage("  UseManagedResourceGenerator: {0}", UseManagedResourceGenerator);
            Log.LogDebugTaskItemsAndLogical("  Resources:", Resources);
            Log.LogDebugTaskItemsAndLogical("  References:", References);

            if (!File.Exists(JavaResgenInputFile) && !UseManagedResourceGenerator)
            {
                return(true);
            }

            // ResourceDirectory may be a relative path, and
            // we need to compare it to absolute paths
            ResourceDirectory = Path.GetFullPath(ResourceDirectory);

            // Create our capitalization maps so we can support mixed case resources
            foreach (var item in Resources)
            {
                if (!item.ItemSpec.StartsWith(ResourceDirectory))
                {
                    continue;
                }

                var name         = item.ItemSpec.Substring(ResourceDirectory.Length);
                var logical_name = item.GetMetadata("LogicalName").Replace('\\', '/');

                AddRename(name.Replace('/', Path.DirectorySeparatorChar), logical_name.Replace('/', Path.DirectorySeparatorChar));
            }
            if (AdditionalResourceDirectories != null)
            {
                foreach (var additionalDir in AdditionalResourceDirectories)
                {
                    var file = Path.Combine(ProjectDir, Path.GetDirectoryName(additionalDir.ItemSpec), "__res_name_case_map.txt");
                    if (File.Exists(file))
                    {
                        foreach (var line in File.ReadAllLines(file).Where(l => !string.IsNullOrEmpty(l)))
                        {
                            string [] tok = line.Split(';');
                            AddRename(tok [1].Replace('/', Path.DirectorySeparatorChar), tok [0].Replace('/', Path.DirectorySeparatorChar));
                        }
                    }
                }
            }

            // Parse out the resources from the R.java file
            CodeTypeDeclaration resources;

            if (UseManagedResourceGenerator)
            {
                var parser = new ManagedResourceParser()
                {
                    Log = Log
                };
                resources = parser.Parse(ResourceDirectory, AdditionalResourceDirectories?.Select(x => x.ItemSpec), IsApplication, resource_fixup);
            }
            else
            {
                var parser = new JavaResourceParser()
                {
                    Log = Log
                };
                resources = parser.Parse(JavaResgenInputFile, IsApplication, resource_fixup);
            }

            var  extension = Path.GetExtension(NetResgenOutputFile);
            var  language  = string.Compare(extension, ".fs", StringComparison.OrdinalIgnoreCase) == 0 ? "F#" : CodeDomProvider.GetLanguageFromExtension(extension);
            bool isVB      = string.Equals(extension, ".vb", StringComparison.OrdinalIgnoreCase);
            bool isFSharp  = string.Equals(language, "F#", StringComparison.OrdinalIgnoreCase);
            bool isCSharp  = string.Equals(language, "C#", StringComparison.OrdinalIgnoreCase);

            // Let VB put this in the default namespace
            if (isVB)
            {
                Namespace = string.Empty;
            }

            // Create static resource overwrite methods for each Resource class in libraries.
            var assemblyNames = new List <string> ();

            if (IsApplication && References != null && References.Any())
            {
                // FIXME: should this be unified to some better code with ResolveLibraryProjectImports?
                using (var resolver = new DirectoryAssemblyResolver(this.CreateTaskLogger(), loadDebugSymbols: false)) {
                    foreach (var assemblyName in References)
                    {
                        var    suffix   = assemblyName.ItemSpec.EndsWith(".dll") ? String.Empty : ".dll";
                        string hintPath = assemblyName.GetMetadata("HintPath").Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
                        string fileName = assemblyName.ItemSpec + suffix;
                        resolver.Load(Path.GetFullPath(assemblyName.ItemSpec));
                        if (!String.IsNullOrEmpty(hintPath) && !File.Exists(hintPath))                           // ignore invalid HintPath
                        {
                            hintPath = null;
                        }
                        string assemblyPath = String.IsNullOrEmpty(hintPath) ? fileName : hintPath;
                        if (MonoAndroidHelper.IsFrameworkAssembly(fileName) && !MonoAndroidHelper.FrameworkEmbeddedJarLookupTargets.Contains(Path.GetFileName(fileName)))
                        {
                            continue;
                        }
                        Log.LogDebugMessage("Scan assembly {0} for resource generator", fileName);
                        assemblyNames.Add(assemblyPath);
                    }
                    var assemblies = assemblyNames.Select(assembly => resolver.GetAssembly(assembly));
                    new ResourceDesignerImportGenerator(Namespace, resources, Log)
                    .CreateImportMethods(assemblies);
                }
            }

            AdjustConstructor(isFSharp, resources);
            foreach (var member in resources.Members)
            {
                if (member is CodeTypeDeclaration)
                {
                    AdjustConstructor(isFSharp, (CodeTypeDeclaration)member);
                }
            }

            // Write out our Resources.Designer.cs file

            WriteFile(NetResgenOutputFile, resources, language, isFSharp, isCSharp);

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

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

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

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

            var skiplist = new List <string> ();

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

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

            options.SkippedAssemblies = skiplist;

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

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

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

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

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

            return(true);
        }
        public override bool Execute()
        {
            Log.LogDebugMessage ("ResolveAssemblies Task");
            Log.LogDebugMessage ("  ReferenceAssembliesDirectory: {0}", ReferenceAssembliesDirectory);
            Log.LogDebugMessage ("  I18nAssemblies: {0}", I18nAssemblies);
            Log.LogDebugMessage ("  LinkMode: {0}", LinkMode);
            Log.LogDebugTaskItems ("  Assemblies:", Assemblies);

            resolver  = new DirectoryAssemblyResolver (Log.LogWarning, loadDebugSymbols: false);
            foreach (var dir in ReferenceAssembliesDirectory.Split (new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
                resolver.SearchDirectories.Add (dir);

            var assemblies = new HashSet<string> ();

            var topAssemblyReferences = new List<AssemblyDefinition> ();

            try {
                foreach (var assembly in Assemblies) {
                    var assembly_path = Path.GetDirectoryName (assembly.ItemSpec);

                    if (!resolver.SearchDirectories.Contains (assembly_path))
                        resolver.SearchDirectories.Add (assembly_path);

                    // Add each user assembly and all referenced assemblies (recursive)
                    var assemblyDef = resolver.Load (assembly.ItemSpec);
                    if (assemblyDef == null)
                        throw new InvalidOperationException ("Failed to load assembly " + assembly.ItemSpec);
                    topAssemblyReferences.Add (assemblyDef);
                    assemblies.Add (assemblyDef.MainModule.FullyQualifiedName);
                }
            } catch (Exception ex) {
                Log.LogError ("Exception while loading assemblies: {0}", ex);
                return false;
            }
            try {
                foreach (var assembly in topAssemblyReferences)
                    AddAssemblyReferences (assemblies, assembly, true);
            } catch (Exception ex) {
                Log.LogError ("Exception while loading assemblies: {0}", ex);
                return false;
            }

            // Add I18N assemblies if needed
            AddI18nAssemblies (assemblies);

            ResolvedAssemblies = assemblies.Select (a => new TaskItem (a)).ToArray ();
            ResolvedSymbols = assemblies.Select (a => a + ".mdb").Where (a => File.Exists (a)).Select (a => new TaskItem (a)).ToArray ();
            ResolvedFrameworkAssemblies = ResolvedAssemblies.Where (p => MonoAndroidHelper.IsFrameworkAssembly (p.ItemSpec, true)).ToArray ();
            ResolvedUserAssemblies = ResolvedAssemblies.Where (p => !MonoAndroidHelper.IsFrameworkAssembly (p.ItemSpec, true)).ToArray ();
            ResolvedDoNotPackageAttributes = do_not_package_atts.ToArray ();

            Log.LogDebugTaskItems ("  [Output] ResolvedAssemblies:", ResolvedAssemblies);
            Log.LogDebugTaskItems ("  [Output] ResolvedUserAssemblies:", ResolvedUserAssemblies);
            Log.LogDebugTaskItems ("  [Output] ResolvedFrameworkAssemblies:", ResolvedFrameworkAssemblies);
            Log.LogDebugTaskItems ("  [Output] ResolvedDoNotPackageAttributes:", ResolvedDoNotPackageAttributes);

            return true;
        }