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); }
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; }
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; }
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); }
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)); }
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); }
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); }
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); }
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); }
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); }
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); }
public override bool Execute() { Log.LogDebugMessage ("LinkAssemblies Task"); Log.LogDebugMessage (" UseSharedRuntime: {0}", UseSharedRuntime); Log.LogDebugMessage (" MainAssembly: {0}", MainAssembly); Log.LogDebugMessage (" OutputDirectory: {0}", OutputDirectory); Log.LogDebugMessage (" OptionalDestinationDirectory: {0}", OptionalDestinationDirectory); Log.LogDebugMessage (" I18nAssemblies: {0}", I18nAssemblies); Log.LogDebugMessage (" LinkMode: {0}", LinkMode); Log.LogDebugMessage (" LinkSkip: {0}", LinkSkip); Log.LogDebugTaskItems (" LinkDescriptions:", LinkDescriptions); Log.LogDebugTaskItems (" ResolvedAssemblies:", ResolvedAssemblies); Log.LogDebugMessage (" EnableProguard: {0}", EnableProguard); Log.LogDebugMessage (" ProguardConfiguration: {0}", ProguardConfiguration); Log.LogDebugMessage (" DumpDependencies: {0}", DumpDependencies); Log.LogDebugMessage (" LinkOnlyNewerThan: {0}", LinkOnlyNewerThan); var res = new DirectoryAssemblyResolver (Log.LogWarning, loadDebugSymbols: false); // Put every assembly we'll need in the resolver foreach (var assembly in ResolvedAssemblies) { res.Load (Path.GetFullPath (assembly.ItemSpec)); } var resolver = new AssemblyResolver (res.ToResolverCache ()); // Set up for linking var options = new LinkerOptions (); options.MainAssembly = res.GetAssembly (MainAssembly); options.OutputDirectory = Path.GetFullPath (OutputDirectory); options.LinkSdkOnly = string.Compare (LinkMode, "SdkOnly", true) == 0; options.LinkNone = string.Compare (LinkMode, "None", true) == 0; options.Resolver = resolver; options.LinkDescriptions = LinkDescriptions.Select (item => Path.GetFullPath (item.ItemSpec)).ToArray (); options.I18nAssemblies = Linker.ParseI18nAssemblies (I18nAssemblies); if (!options.LinkSdkOnly) options.RetainAssemblies = GetRetainAssemblies (res); options.DumpDependencies = DumpDependencies; var skiplist = new List<string> (); if (string.Compare (UseSharedRuntime, "true", true) == 0) skiplist.AddRange (Profile.SharedRuntimeAssemblies.Where (a => a.EndsWith (".dll")).Select (a => Path.GetFileNameWithoutExtension (a))); if (!string.IsNullOrWhiteSpace (LinkOnlyNewerThan) && File.Exists (LinkOnlyNewerThan)) { var newerThan = File.GetLastWriteTime (LinkOnlyNewerThan); var skipOldOnes = ResolvedAssemblies.Where (a => File.GetLastWriteTime (a.ItemSpec) < newerThan); foreach (var old in skipOldOnes) Log.LogMessage (MessageImportance.Low, " Skip linking unchanged file: " + old.ItemSpec); skiplist = skipOldOnes.Select (a => Path.GetFileNameWithoutExtension (a.ItemSpec)).Concat (skiplist).ToList (); } // Add LinkSkip options if (!string.IsNullOrWhiteSpace (LinkSkip)) foreach (var assembly in LinkSkip.Split (',', ';')) skiplist.Add (assembly); options.SkippedAssemblies = skiplist; if (EnableProguard) options.ProguardConfiguration = ProguardConfiguration; // Link! try { LinkContext link_context; Linker.Process (options, out link_context); var copydst = OptionalDestinationDirectory ?? OutputDirectory; foreach (var assembly in ResolvedAssemblies) { var copysrc = assembly.ItemSpec; var filename = Path.GetFileName (assembly.ItemSpec); if (options.LinkNone) { if (skiplist.Any (s => Path.GetFileNameWithoutExtension (filename) == s)) { // For skipped assemblies, skip if there is existing file in the destination. // We cannot just copy the linker output from *current* run output, because // it always renew the assemblies, in *different* binary values, whereas // the dll in the OptionalDestinationDirectory must retain old and unchanged. if (File.Exists (Path.Combine (copydst, filename))) continue; copysrc = assembly.ItemSpec; } else { // Prefer fixup assemblies if exists, otherwise just copy the original. copysrc = Path.Combine (OutputDirectory, filename); copysrc = File.Exists (copysrc) ? copysrc : assembly.ItemSpec; } } else if (!MonoAndroidHelper.IsForceRetainedAssembly (filename)) continue; MonoAndroidHelper.CopyIfChanged (copysrc, Path.Combine (copydst, filename)); try { MonoAndroidHelper.CopyIfChanged (assembly.ItemSpec + ".mdb", Path.Combine (copydst, filename + ".mdb")); } catch (Exception) { // skip it, mdb sometimes fails to read and it's optional } } } catch (ResolutionException ex) { Diagnostic.Error (2006, ex, "Reference to metadata item '{0}' (defined in '{1}') from '{1}' could not be resolved.", ex.Member, ex.Member.Module.Assembly, ex.Scope); } return true; }
public override bool Execute() { 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); }
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); }
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); }
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(); } }
// 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); } }
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; }
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); }
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); }
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 }, })); } } }
void Run() { PackageNamingPolicy pnp; JniType.PackageNamingPolicy = Enum.TryParse (PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseHash; var temp = Path.Combine (Path.GetTempPath (), Path.GetRandomFileName ()); Directory.CreateDirectory (temp); // We're going to do 3 steps here instead of separate tasks so // we can share the list of JLO TypeDefinitions between them var res = new DirectoryAssemblyResolver (Log.LogWarning, loadDebugSymbols:true); var selectedWhitelistAssemblies = new List<string> (); // Put every assembly we'll need in the resolver foreach (var assembly in ResolvedAssemblies) { res.Load (Path.GetFullPath (assembly.ItemSpec)); if (MonoAndroidHelper.FrameworkAttributeLookupTargets.Any (a => Path.GetFileName (assembly.ItemSpec) == a)) selectedWhitelistAssemblies.Add (Path.GetFullPath (assembly.ItemSpec)); } // However we only want to look for JLO types in user code var assemblies = ResolvedUserAssemblies.Select (p => p.ItemSpec).ToList (); var fxAdditions = MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies (ResolvedAssemblies) .Where (a => assemblies.All (x => Path.GetFileName (x) != Path.GetFileName (a))); assemblies = assemblies.Concat (fxAdditions).ToList (); // Step 1 - Find all the JLO types var all_java_types = JavaTypeScanner.GetJavaTypes (assemblies, res, Log.LogWarning); WriteTypeMappings (all_java_types); var java_types = all_java_types.Where (t => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration (t)); // Step 2 - Generate Java stub code var keep_going = Generator.CreateJavaSources ( Log, java_types, temp, UseSharedRuntime, int.Parse (AndroidSdkPlatform) <= 10, ResolvedAssemblies.Any (assembly => Path.GetFileName (assembly.ItemSpec) == "Mono.Android.Export.dll")); var temp_map_file = Path.Combine (temp, "acw-map.temp"); // We need to save a map of .NET type -> ACW type for resource file fixups var managed = new Dictionary<string, TypeDefinition> (); var java = new Dictionary<string, TypeDefinition> (); var acw_map = new StreamWriter (temp_map_file); foreach (var type in java_types) { string managedKey = type.FullName.Replace ('/', '.'); string javaKey = JniType.ToJniName (type).Replace ('/', '.'); acw_map.WriteLine ("{0};{1}", type.GetPartialAssemblyQualifiedName (), javaKey); acw_map.WriteLine ("{0};{1}", type.GetAssemblyQualifiedName (), javaKey); TypeDefinition conflict; if (managed.TryGetValue (managedKey, out conflict)) { Log.LogWarning ( "Duplicate managed type found! Mappings between managed types and Java types must be unique. " + "First Type: '{0}'; Second Type: '{1}'.", conflict.GetAssemblyQualifiedName (), type.GetAssemblyQualifiedName ()); Log.LogWarning ( "References to the type '{0}' will refer to '{1}'.", managedKey, conflict.GetAssemblyQualifiedName ()); continue; } if (java.TryGetValue (javaKey, out conflict)) { Log.LogError ( "Duplicate Java type found! Mappings between managed types and Java types must be unique. " + "First Type: '{0}'; Second Type: '{1}'", conflict.GetAssemblyQualifiedName (), type.GetAssemblyQualifiedName ()); keep_going = false; continue; } managed.Add (managedKey, type); java.Add (javaKey, type); acw_map.WriteLine ("{0};{1}", managedKey, javaKey); acw_map.WriteLine ("{0};{1}", JniType.ToCompatJniName (type).Replace ('/', '.'), javaKey); } acw_map.Close (); //The previous steps found an error, so we must abort and not generate any further output //We must do so subsequent unchanged builds fail too. if (!keep_going) { File.Delete (temp_map_file); return; } MonoAndroidHelper.CopyIfChanged (temp_map_file, AcwMapFile); try { File.Delete (temp_map_file); } catch (Exception) { } // Only overwrite files if the contents actually changed foreach (var file in Directory.GetFiles (temp, "*", SearchOption.AllDirectories)) { var dest = Path.GetFullPath (Path.Combine (OutputDirectory, "src", file.Substring (temp.Length + 1))); MonoAndroidHelper.CopyIfChanged (file, dest); } // Step 3 - Merge [Activity] and friends into AndroidManifest.xml var manifest = new ManifestDocument (ManifestTemplate, this.Log); manifest.PackageName = PackageName; manifest.ApplicationName = ApplicationName ?? PackageName; manifest.Assemblies.AddRange (assemblies); manifest.Resolver = res; manifest.SdkDir = AndroidSdkDir; manifest.SdkVersion = AndroidSdkPlatform; manifest.Debug = Debug; manifest.NeedsInternet = NeedsInternet; var additionalProviders = manifest.Merge (all_java_types, selectedWhitelistAssemblies, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments); var temp_manifest = Path.Combine (temp, "AndroidManifest.xml"); var real_manifest = Path.GetFullPath (MergedAndroidManifestOutput); manifest.Save (temp_manifest); // Only write the new manifest if it actually changed MonoAndroidHelper.CopyIfChanged (temp_manifest, real_manifest); // Create additional runtime provider java sources. string providerTemplateFile = UseSharedRuntime ? "MonoRuntimeProvider.Shared.java" : "MonoRuntimeProvider.Bundled.java"; string providerTemplate = new StreamReader (typeof (JavaCallableWrapperGenerator).Assembly.GetManifestResourceStream (providerTemplateFile)).ReadToEnd (); foreach (var provider in additionalProviders) { var temp_provider = Path.Combine (temp, provider + ".java"); File.WriteAllText (temp_provider, providerTemplate.Replace ("MonoRuntimeProvider", provider)); var real_provider_dir = Path.GetFullPath (Path.Combine (OutputDirectory, "src", "mono")); Directory.CreateDirectory (real_provider_dir); var real_provider = Path.Combine (real_provider_dir, provider + ".java"); MonoAndroidHelper.CopyIfChanged (temp_provider, real_provider); } // Create additional application java sources. Action<string,string,string,Func<string,string>> save = (resource, filename, destDir, applyTemplate) => { string temp_file = Path.Combine (temp, filename); string template = applyTemplate (new StreamReader (typeof (GenerateJavaStubs).Assembly.GetManifestResourceStream (resource)).ReadToEnd ()); File.WriteAllText (temp_file, template); Directory.CreateDirectory (destDir); var real_file = Path.Combine (destDir, filename); MonoAndroidHelper.CopyIfChanged (temp_file, real_file); }; StringWriter regCallsWriter = new StringWriter (); regCallsWriter.WriteLine ("\t\t// Application and Instrumentation ACWs must be registered first."); foreach (var type in java_types) { if (JniType.IsApplication (type) || JniType.IsInstrumentation (type)) { string javaKey = JniType.ToJniName (type).Replace ('/', '.'); regCallsWriter.WriteLine ("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);", type.GetAssemblyQualifiedName (), javaKey); } } regCallsWriter.Close (); var real_app_dir = Path.GetFullPath (Path.Combine (OutputDirectory, "src", "mono", "android", "app")); string applicationTemplateFile = "ApplicationRegistration.java"; save (applicationTemplateFile, applicationTemplateFile, real_app_dir, template => template.Replace ("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString ())); // Create NotifyTimeZoneChanges java sources. string notifyTimeZoneChangesFile = "NotifyTimeZoneChanges.java"; save (notifyTimeZoneChangesFile, notifyTimeZoneChangesFile, real_app_dir, template => template); // Delete our temp directory try { Directory.Delete (temp, true); } catch (Exception) { } }
bool Execute(DirectoryAssemblyResolver 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); }
// 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); }
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; }