Пример #1
0
        public override bool Execute()
        {
            Log.LogDebugMessage("CheckTargetFrameworks Task");
            Log.LogDebugMessage("  TargetFrameworkVersion: {0}", TargetFrameworkVersion);
            Log.LogDebugMessage("  ProjectFile: {0}", ProjectFile);
            Log.LogDebugTaskItems("  ResolvedUserAssemblies: {0}", ResolvedAssemblies);

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

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

            foreach (var item in apiLevels.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.ItemSpec), itemOSVersion, TargetFrameworkVersion);
            }

            return(!Log.HasLoggedErrors);
        }
Пример #2
0
        public TypeNameMapGenerator(IEnumerable <string> assemblies, Action <string, object []> logMessage)
        {
            if (assemblies == null)
            {
                throw new ArgumentNullException("assemblies");
            }
            if (logMessage == null)
            {
                throw new ArgumentNullException(nameof(logMessage));
            }

            Log = logMessage;
            var Assemblies = assemblies.ToList();
            var rp         = new ReaderParameters();

            Resolver = new DirectoryAssemblyResolver(Log, loadDebugSymbols: true, loadReaderParameters: rp);
            foreach (var assembly in Assemblies)
            {
                var directory = Path.GetDirectoryName(assembly);
                if (string.IsNullOrEmpty(directory))
                {
                    continue;
                }
                if (!Resolver.SearchDirectories.Contains(directory))
                {
                    Resolver.SearchDirectories.Add(directory);
                }
            }
            foreach (var assembly in Assemblies)
            {
                Resolver.Load(Path.GetFullPath(assembly));
            }

            Types = JavaTypeScanner.GetJavaTypes(Assemblies, Resolver, logMessage);
        }
        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;
        }
Пример #4
0
        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;
        }
Пример #6
0
        void AddNativeLibrariesFromAssemblies(ZipArchiveEx apk, string supportedAbis)
        {
            int count = 0;
            var abis  = supportedAbis.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);

            using (var res = new DirectoryAssemblyResolver(this.CreateTaskLogger(), 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 = ZipArchive.Open(ms)) {
                                foreach (var e in zip.Where(x => abis.Any(a => x.FullName.Contains($"/{a}/"))))
                                {
                                    if (e.IsDirectory)
                                    {
                                        continue;
                                    }
                                    var key = e.FullName.Replace("native_library_imports", "lib");
                                    if (apk.Archive.Any(k => k.FullName == key))
                                    {
                                        Log.LogCodedWarning("4301", "Apk already contains the item {0}; ignoring.", key);
                                        continue;
                                    }
                                    using (var s = new MemoryStream()) {
                                        e.Extract(s);
                                        s.Position = 0;
                                        apk.Archive.AddEntry(s.ToArray(), key);
                                    }
                                }
                            }
                        }
                    }
                    count++;
                    if (count == ZipArchiveEx.ZipFlushLimit)
                    {
                        apk.Flush();
                        count = 0;
                    }
                }
            }
        }
        AssemblyDefinition ResolveRuntimeAssemblyForReferenceAssembly(LockFile lockFile, DirectoryAssemblyResolver resolver, string assemblyPath)
        {
            if (string.IsNullOrEmpty(TargetMoniker))
            {
                return(null);
            }

            var framework = NuGetFramework.Parse(TargetMoniker);

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

            if (target == null)
            {
                LogCodedWarning("XA0118", $"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);
        }
Пример #8
0
        AssemblyDefinition ResolveRuntimeAssemblyForReferenceAssembly(LockFile lockFile, DirectoryAssemblyResolver resolver, AssemblyNameDefinition assemblyNameDefinition)
        {
            if (string.IsNullOrEmpty(TargetMoniker) || string.IsNullOrEmpty(NuGetPackageRoot) || !Directory.Exists(NuGetPackageRoot))
            {
                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);
            }
            var libraryPath = lockFile.Libraries.FirstOrDefault(x => x.Name == assemblyNameDefinition.Name);

            if (libraryPath == null)
            {
                return(null);
            }
            var library = target.Libraries.FirstOrDefault(x => x.Name == assemblyNameDefinition.Name);

            if (library == null)
            {
                return(null);
            }
            var runtime = library.RuntimeAssemblies.FirstOrDefault();

            if (runtime == null)
            {
                return(null);
            }
            var path = Path.Combine(NuGetPackageRoot, libraryPath.Path, runtime.Path);

            LogDebugMessage($"Attempting to load {path}");
            return(resolver.Load(path, forceLoad: true));
        }
Пример #9
0
        void AddNativeLibrariesFromAssemblies(ZipArchive 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 = new ZipArchive(ms, ZipArchiveMode.Read)) {
                            foreach (var e in zip.Entries.Where(x => abis.Any(a => x.FullName.Contains(a))))
                            {
                                if (e.IsDirectory())
                                {
                                    continue;
                                }
                                var key = e.FullName.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());
                                }
                            }
                        }
                    }
                }
            }
        }
        public TypeNameMapGenerator(IEnumerable <string> assemblies, Action <TraceLevel, string> logger, IMetadataResolver resolver)
        {
            if (assemblies == null)
            {
                throw new ArgumentNullException("assemblies");
            }
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }

            Cache = resolver ?? new TypeDefinitionCache();
            Log   = logger;
            var Assemblies = assemblies.ToList();
            var rp         = new ReaderParameters();

            Resolver = new DirectoryAssemblyResolver(Log, loadDebugSymbols: true, loadReaderParameters: rp);
            foreach (var assembly in Assemblies)
            {
                var directory = Path.GetDirectoryName(assembly);
                if (string.IsNullOrEmpty(directory))
                {
                    continue;
                }
                if (!Resolver.SearchDirectories.Contains(directory))
                {
                    Resolver.SearchDirectories.Add(directory);
                }
            }
            foreach (var assembly in Assemblies)
            {
                Resolver.Load(Path.GetFullPath(assembly));
            }

            Scanner = new JavaTypeScanner(Log, Cache)
            {
                ErrorOnCustomJavaObject = false,
            };
            Types = Scanner.GetJavaTypes(Assemblies, Resolver);
        }
Пример #11
0
        public TypeNameMapGenerator(IEnumerable <string> assemblies, Action <string, object []> logMessage)
        {
            if (assemblies == null)
            {
                throw new ArgumentNullException("assemblies");
            }
            if (logMessage == null)
            {
                throw new ArgumentNullException(nameof(logMessage));
            }

            Log = logMessage;
            var Assemblies = assemblies.ToList();
            var resolver   = new DirectoryAssemblyResolver(Log, loadDebugSymbols: true);

            foreach (var assembly in Assemblies)
            {
                resolver.Load(Path.GetFullPath(assembly));
            }

            Types = JavaTypeScanner.GetJavaTypes(Assemblies, resolver, logMessage);
        }
        // This fixup ensures all referenced Java types can be resolved, and
        // removes types and members that rely on unresolvable Java types.
        public static void Fixup(string xmlFile, string outputXmlFile, DirectoryAssemblyResolver resolver, string [] references)
        {
            // Parse api.xml
            var type_collection = JavaXmlApiImporter.Parse(xmlFile);

            // Add in reference types from assemblies
            foreach (var reference in references.Distinct())
            {
                Report.Verbose(0, "Resolving assembly for Java type resolution: '{0}'.", reference);
                var assembly = resolver.Load(reference);

                ManagedApiImporter.Parse(assembly, type_collection);
            }

            // Run the type resolution pass
            var results = type_collection.ResolveCollection();

            OutputResults(results, xmlFile, outputXmlFile);

            // Output the adjusted xml
            JavaXmlApiExporter.Save(type_collection, outputXmlFile);
        }
        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;
        }
        void DoExecute()
        {
            LogDebugMessage("GetAdditionalResourcesFromAssemblies Task");
            LogDebugMessage("  AndroidSdkDirectory: {0}", AndroidSdkDirectory);
            LogDebugMessage("  AndroidNdkDirectory: {0}", AndroidNdkDirectory);
            LogDebugMessage("  CacheFile: {0}", CacheFile);
            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;
            }

            var cacheFileFullPath = CacheFile;

            if (!Path.IsPathRooted(cacheFileFullPath))
            {
                cacheFileFullPath = Path.Combine(WorkingDirectory, cacheFileFullPath);
            }

            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 (DesignTimeBuild && !File.Exists(fullPath))
                        {
                            LogWarning("Failed to load '{0}'. Check the file exists or the project has been built.", fullPath);
                            continue;
                        }
                        if (assemblies.Contains(fullPath))
                        {
                            LogDebugMessage("  Skip assembly: {0}, it was already processed", fullPath);
                            continue;
                        }
                        // don't try to even load mscorlib it will fail.
                        if (string.Compare(Path.GetFileNameWithoutExtension(fullPath), "mscorlib", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            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;
                            }
                        }
                    }
                }
            }, Token).ContinueWith(Complete);

            var result = base.Execute();

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

            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.SaveIfChanged(cacheFileFullPath);

            LogDebugTaskItems("  AdditionalAndroidResourcePaths: ", AdditionalAndroidResourcePaths);
            LogDebugTaskItems("  AdditionalJavaLibraryReferences: ", AdditionalJavaLibraryReferences);
            LogDebugTaskItems("  AdditionalNativeLibraryReferences: ", AdditionalNativeLibraryReferences);
        }
Пример #15
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).
                            var nonGenericOverload = td.HasGenericParameters
                                                                ? md.GetType(td.FullName.Substring(0, td.FullName.IndexOf('`')))
                                                                : null;
                            if (BindSameType(td, nonGenericOverload))
                            {
                                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, 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();
            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.
            gens = gens.Where(g => !g.IsObfuscated && g.Visibility != "private").ToList();
            foreach (var gen in gens)
            {
                gen.StripNonBindables();
                if (gen.IsGeneratable)
                {
                    AddTypeToTable(gen);
                }
            }

            Validate(gens, opt);

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

            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);
        }
        // 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);
        }
Пример #17
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))
                            {
                                MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(assemblyDestination, DateTime.UtcNow, Log);
                                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;
                    }

                    if (MonoAndroidHelper.CopyIfChanged(copysrc, assemblyDestination))
                    {
                        MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(assemblyDestination, DateTime.UtcNow, Log);
                    }
                    try {
                        var mdbDestination = assemblyDestination + ".mdb";
                        if (MonoAndroidHelper.CopyIfChanged(assembly.ItemSpec + ".mdb", mdbDestination))
                        {
                            MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(mdbDestination, DateTime.UtcNow, Log);
                        }
                    } 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");
                        if (MonoAndroidHelper.CopyIfChanged(pdb, pdbDestination))
                        {
                            MonoAndroidHelper.SetLastAccessAndWriteTimeUtc(pdbDestination, DateTime.UtcNow, Log);
                        }
                    }
                }
            } 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);
        }
Пример #18
0
        bool Execute(DirectoryAssemblyResolver resolver)
        {
            LogDebugMessage("ResolveAssemblies Task");
            LogDebugMessage("  ReferenceAssembliesDirectory: {0}", ReferenceAssembliesDirectory);
            LogDebugMessage("  I18nAssemblies: {0}", I18nAssemblies);
            LogDebugMessage("  LinkMode: {0}", LinkMode);
            LogDebugTaskItems("  Assemblies:", Assemblies);
            LogDebugMessage("  ProjectAssetFile: {0}", ProjectAssetFile);
            LogDebugMessage("  NuGetPackageRoot: {0}", NuGetPackageRoot);
            LogDebugMessage("  TargetMoniker: {0}", TargetMoniker);

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

            var assemblies = new HashSet <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
                        if (lockFile != null)
                        {
                            assemblyDef = ResolveRuntimeAssemblyForReferenceAssembly(lockFile, resolver, assemblyDef.Name);
                        }
                        if (lockFile == null || assemblyDef == null)
                        {
                            LogWarning($"Ignoring {assembly_path} as it is a Reference Assembly");
                            continue;
                        }
                    }
                    topAssemblyReferences.Add(assemblyDef);
                    assemblies.Add(Path.GetFullPath(assemblyDef.MainModule.FullyQualifiedName));
                }
            } catch (Exception ex) {
                LogError("Exception while loading assemblies: {0}", ex);
                return(false);
            }
            try {
                foreach (var assembly in topAssemblyReferences)
                {
                    AddAssemblyReferences(resolver, assemblies, assembly, true);
                }
            } catch (Exception ex) {
                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();

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

            return(!Log.HasLoggedErrors);
        }
Пример #19
0
        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(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();
            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);
        }
Пример #20
0
        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;
        }
Пример #21
0
        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);
        }
Пример #22
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");
            }

            var is_classparse = apiSourceAttr == "class-parse";

            // Resolve types using Java.Interop.Tools.JavaTypeSystem
            if (is_classparse && !options.UseLegacyJavaResolver)
            {
                var output_xml = api_xml_adjuster_output ?? Path.Combine(Path.GetDirectoryName(filename), Path.GetFileName(filename) + ".adjusted");
                JavaTypeResolutionFixups.Fixup(filename, output_xml, resolver, references.Distinct().ToArray());

                if (only_xml_adjuster)
                {
                    return;
                }

                // Use this output for future steps
                filename      = output_xml;
                apiXmlFile    = filename;
                is_classparse = false;
            }

            // 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 = !is_classparse;

            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.
            // Resolve types using ApiXmlAdjuster
            if (is_classparse && options.UseLegacyJavaResolver)
            {
                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);
            }

            // Load the API XML document
            var api = ApiXmlDocument.Load(apiXmlFile, api_level, product_version);

            if (api is null)
            {
                return;
            }

            // Apply metadata fixups
            foreach (var fixup in fixups)
            {
                api.ApplyFixupFile(fixup);
            }

            api.ApiDocument.Save(apiXmlFile + ".fixed");

            // Parse API XML
            var gens = XmlApiImporter.Parse(api.ApiDocument, opt);

            if (gens is null)
            {
                return;
            }

            apiSource = api.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);

            gen_info.GenerateLibraryProjectFile(options, enumFiles);
        }
Пример #23
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();
        }
        void Run(DirectoryAssemblyResolver res)
        {
            PackageNamingPolicy pnp;

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

            Directory.CreateDirectory(temp);

            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)
            {
                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 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));

            // 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    = JavaNativeTypeManager.ToJniName(type).Replace('/', '.');

                acw_map.WriteLine("{0};{1}", type.GetPartialAssemblyQualifiedName(), 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}", JavaNativeTypeManager.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.Placeholders    = ManifestPlaceholders;
            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 (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.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) { }
        }
        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);
        }
Пример #26
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);
            }
            finally {
                resolver.Dispose();
            }
        }
Пример #27
0
        // Extracts library project contents under e.g. obj/Debug/[__library_projects__/*.jar | res/*/*]
        void Extract(
            DirectoryAssemblyResolver res,
            ICollection <string> jars,
            ICollection <string> resolvedResourceDirectories,
            ICollection <string> resolvedAssetDirectories,
            ICollection <string> resolvedEnvironments)
        {
            var outdir = new DirectoryInfo(OutputImportDirectory);

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

            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 = MonoAndroidHelper.ReadZipFile(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);
            }
        }
Пример #28
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 ());
                         }
                     }
                 }
             }
         }
     }
 }
        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;
        }
Пример #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);

            // 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 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);
        }
Пример #31
0
        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()));
        }
        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);
        }
Пример #33
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);
                }
            }

            // 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",
                    "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, 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(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()));
        }
        // 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,
            IDictionary <string, ITaskItem> jars,
            ICollection <ITaskItem> resolvedResourceDirectories,
            ICollection <ITaskItem> resolvedAssetDirectories,
            ICollection <ITaskItem> 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 => a.ItemSpec)
                     .Distinct())
            {
                var fileName = Path.GetFileName(assemblyPath);
                if (MonoAndroidHelper.IsFrameworkAssembly(fileName) &&
                    !MonoAndroidHelper.FrameworkEmbeddedJarLookupTargets.Contains(fileName) &&
                    !MonoAndroidHelper.FrameworkEmbeddedNativeLibraryAssemblies.Contains(fileName))
                {
                    Log.LogDebugMessage($"Skipping framework assembly '{fileName}'.");
                    continue;
                }
                if (DesignTimeBuild && !File.Exists(assemblyPath))
                {
                    Log.LogDebugMessage($"Skipping non-existent dependency '{assemblyPath}' during a design-time build.");
                    continue;
                }
                if (assembliestoSkipExtraction.Contains(assemblyPath))
                {
                    Log.LogDebugMessage("Skipping resource extraction for '{0}' .", 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);
                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 (Directory.Exists(importsDir))
                    {
                        foreach (var file in Directory.EnumerateFiles(importsDir, "*.jar", SearchOption.AllDirectories))
                        {
                            AddJar(jars, Path.GetFullPath(file));
                        }
                    }
                    if (Directory.Exists(resDir))
                    {
                        var taskItem = new TaskItem(Path.GetFullPath(resDir), new Dictionary <string, string> {
                            { OriginalFile, assemblyPath },
                        });
                        if (assembliesToSkipCaseFixup.Contains(assemblyPath))
                        {
                            taskItem.SetMetadata(AndroidSkipResourceProcessing, "True");
                        }
                        resolvedResourceDirectories.Add(taskItem);
                    }
                    if (Directory.Exists(assetsDir))
                    {
                        resolvedAssetDirectories.Add(new TaskItem(Path.GetFullPath(assetsDir), new Dictionary <string, string> {
                            { OriginalFile, assemblyPath }
                        }));
                    }
                    foreach (var env in Directory.EnumerateFiles(outDirForDll, "__AndroidEnvironment__*", SearchOption.TopDirectoryOnly))
                    {
                        resolvedEnvironments.Add(new TaskItem(env, new Dictionary <string, string> {
                            { OriginalFile, assemblyPath }
                        }));
                    }
                    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(new TaskItem(Path.GetFullPath(outFile), new Dictionary <string, string> {
                            { OriginalFile, assemblyPath }
                        }));
                    }

                    // 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, assemblyPath);
                            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, assemblyPath);
                                        }
                                        return(path);
                                    }, deleteCallback: (fileToDelete) => {
                                        return(!jars.ContainsKey(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 (Directory.Exists(resDir))
                        {
                            var taskItem = new TaskItem(Path.GetFullPath(resDir), new Dictionary <string, string> {
                                { OriginalFile, assemblyPath }
                            });
                            if (assembliesToSkipCaseFixup.Contains(assemblyPath))
                            {
                                taskItem.SetMetadata(AndroidSkipResourceProcessing, "True");
                            }
                            resolvedResourceDirectories.Add(taskItem);
                        }
                        if (Directory.Exists(assetsDir))
                        {
                            resolvedAssetDirectories.Add(new TaskItem(Path.GetFullPath(assetsDir), new Dictionary <string, string> {
                                { OriginalFile, assemblyPath }
                            }));
                        }
                    }
                }

                if (Directory.Exists(importsDir))
                {
                    // Delete unknown files in the top directory of importsDir
                    foreach (var file in Directory.EnumerateFiles(importsDir, "*"))
                    {
                        var fullPath = Path.GetFullPath(file);
                        if (file.StartsWith("__AndroidEnvironment__", StringComparison.OrdinalIgnoreCase) && !resolvedEnvironments.Any(x => x.ItemSpec == fullPath))
                        {
                            Log.LogDebugMessage($"Deleting unknown AndroidEnvironment file: {Path.GetFileName (file)}");
                            File.Delete(fullPath);
                            updated = true;
                        }
                        else if (file.EndsWith(".jar", StringComparison.OrdinalIgnoreCase) && !jars.ContainsKey(fullPath))
                        {
                            Log.LogDebugMessage($"Deleting unknown jar: {Path.GetFileName (file)}");
                            File.Delete(fullPath);
                            updated = true;
                        }
                    }
                    if (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, aarIdentityName + ".stamp");
                string stampHash   = File.Exists(stamp) ? File.ReadAllText(stamp) : null;
                var    aarFullPath = Path.GetFullPath(aarFile.ItemSpec);
                if (aarHash == stampHash)
                {
                    Log.LogDebugMessage("Skipped {0}: extracted files are up to date", aarFile.ItemSpec);
                    if (Directory.Exists(importsDir))
                    {
                        foreach (var file in Directory.EnumerateFiles(importsDir, "*.jar", SearchOption.AllDirectories))
                        {
                            AddJar(jars, Path.GetFullPath(file));
                        }
                    }
                    if (Directory.Exists(resDir))
                    {
                        resolvedResourceDirectories.Add(new TaskItem(Path.GetFullPath(resDir), new Dictionary <string, string> {
                            { OriginalFile, Path.GetFullPath(aarFile.ItemSpec) },
                            { AndroidSkipResourceProcessing, "True" },
                        }));
                    }
                    if (Directory.Exists(assetsDir))
                    {
                        resolvedAssetDirectories.Add(new TaskItem(Path.GetFullPath(assetsDir), new Dictionary <string, string> {
                            { OriginalFile, aarFullPath },
                        }));
                    }
                    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, aarFullPath);
                                return(jar);
                            }
                            if (entryFullName.EndsWith(".jar", StringComparison.OrdinalIgnoreCase))
                            {
                                AddJar(jars, importsDir, entryFullName, aarFullPath);
                            }
                            return(entryFullName);
                        }, deleteCallback: (fileToDelete) => {
                            return(!jars.ContainsKey(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, aarFullPath },
                        { AndroidSkipResourceProcessing, "True" },
                    }));
                }
                if (Directory.Exists(assetsDir))
                {
                    resolvedAssetDirectories.Add(new TaskItem(Path.GetFullPath(assetsDir), new Dictionary <string, string> {
                        { OriginalFile, aarFullPath },
                    }));
                }
            }
        }
Пример #35
0
        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) { }
        }
Пример #36
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.AddKeepAlives             = AddKeepAlives;
            options.PreserveJniMarshalMethods = PreserveJniMarshalMethods;
            options.DeterministicOutput       = Deterministic;
            options.LinkResources             = LinkResources;

            var skiplist = new List <string> ();

            // 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, Properties.Resources.XA2006, ex.Member, ex.Member.Module.Assembly, ex.Scope);
            }

            return(true);
        }
Пример #37
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);
            }

            // 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;
                }

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

                Directory.CreateDirectory(importsDir);

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

                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;
                        }
                        jars.Add(outjarFile);
                    }

                    // 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.LogErrorFromException(new PathTooLongException($"Error extracting resources from \"{assemblyPath}\"", ex));
                            }
                        }

                        // 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 f in outdir.GetFiles("*.jar", SearchOption.AllDirectories)
                     .Select(fi => fi.FullName))
            {
                if (jars.Contains(f))
                {
                    continue;
                }
                jars.Add(f);
            }
        }
        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;
                        string fullPath = Path.GetFullPath(assemblyName.ItemSpec);
                        // Skip non existing files in DesignTimeBuild
                        if (!File.Exists(fullPath) && DesignTimeBuild)
                        {
                            Log.LogDebugMessage("Skipping non existant dependancy '{0}' due to design time build.", fullPath);
                            continue;
                        }
                        resolver.Load(fullPath);
                        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);
        }
Пример #39
0
        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;
        }