public override bool Execute() { BuildId = buildId.ToString(); Log.LogDebugMessage(" [Output] BuildId: {0}", BuildId); var shared_runtime = string.Compare(UseSharedRuntime, "true", true) == 0; var doc = AndroidAppManifest.Load(Manifest, MonoAndroidHelper.SupportedVersions); int minApiVersion = doc.MinSdkVersion == null ? 4 : (int)doc.MinSdkVersion; // We need to include any special assemblies in the Assemblies list var assemblies = ResolvedUserAssemblies.Select(p => p.ItemSpec) .Concat(MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies(ResolvedAssemblies)) .ToList(); var mainFileName = Path.GetFileName(MainAssembly); Func <string, string, bool> fileNameEq = (a, b) => a.Equals(b, StringComparison.OrdinalIgnoreCase); assemblies = assemblies.Where(a => fileNameEq(a, mainFileName)).Concat(assemblies.Where(a => !fileNameEq(a, mainFileName))).ToList(); using (var stream = new MemoryStream()) using (var pkgmgr = new StreamWriter(stream)) { pkgmgr.WriteLine("package mono;"); // Write all the user assemblies pkgmgr.WriteLine("public class MonoPackageManager_Resources {"); pkgmgr.WriteLine("\tpublic static final String[] Assemblies = new String[]{"); pkgmgr.WriteLine("\t\t/* We need to ensure that \"{0}\" comes first in this list. */", mainFileName); foreach (var assembly in assemblies) { pkgmgr.WriteLine("\t\t\"" + Path.GetFileName(assembly) + "\","); } // Write the assembly dependencies pkgmgr.WriteLine("\t};"); pkgmgr.WriteLine("\tpublic static final String[] Dependencies = new String[]{"); //foreach (var assembly in assemblies.Except (args.Assemblies)) { // if (args.SharedRuntime && !Toolbox.IsInSharedRuntime (assembly)) // pkgmgr.WriteLine ("\t\t\"" + Path.GetFileName (assembly) + "\","); //} pkgmgr.WriteLine("\t};"); // Write the platform api apk we need pkgmgr.WriteLine("\tpublic static final String ApiPackageName = {0};", shared_runtime ? string.Format("\"Mono.Android.Platform.ApiLevel_{0}\"", MonoAndroidHelper.SupportedVersions.GetApiLevelFromFrameworkVersion(TargetFrameworkVersion)) : "null"); pkgmgr.WriteLine("}"); pkgmgr.Flush(); // Only copy to the real location if the contents actually changed var dest = Path.GetFullPath(Path.Combine(OutputDirectory, "MonoPackageManager_Resources.java")); MonoAndroidHelper.CopyIfStreamChanged(stream, dest); } AddEnvironment(); return(!Log.HasLoggedErrors); }
public override bool Execute() { Log.LogDebugMessage("GeneratePackageManagerJava Task"); Log.LogDebugMessage(" OutputDirectory: {0}", OutputDirectory); Log.LogDebugMessage(" TargetFrameworkVersion: {0}", TargetFrameworkVersion); Log.LogDebugMessage(" Manifest: {0}", Manifest); Log.LogDebugMessage(" UseSharedRuntime: {0}", UseSharedRuntime); Log.LogDebugMessage(" MainAssembly: {0}", MainAssembly); Log.LogDebugTaskItems(" ResolvedAssemblies:", ResolvedAssemblies); Log.LogDebugTaskItems(" ResolvedUserAssemblies:", ResolvedUserAssemblies); var shared_runtime = string.Compare(UseSharedRuntime, "true", true) == 0; var doc = AndroidAppManifest.Load(Manifest, MonoAndroidHelper.SupportedVersions); int minApiVersion = doc.MinSdkVersion == null ? 4 : (int)doc.MinSdkVersion; // We need to include any special assemblies in the Assemblies list var assemblies = ResolvedUserAssemblies.Select(p => p.ItemSpec) .Concat(MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies(ResolvedAssemblies)) .ToList(); var mainFileName = Path.GetFileName(MainAssembly); Func <string, string, bool> fileNameEq = (a, b) => a.Equals(b, StringComparison.OrdinalIgnoreCase); assemblies = assemblies.Where(a => fileNameEq(a, mainFileName)).Concat(assemblies.Where(a => !fileNameEq(a, mainFileName))).ToList(); // Write first to a temporary file var temp = Path.GetTempFileName(); using (var pkgmgr = File.CreateText(temp)) { // Write the boilerplate from the MonoPackageManager.java resource var packageManagerResource = minApiVersion < 9 ? "MonoPackageManager.api4.java" : "MonoPackageManager.java"; using (var template = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream(packageManagerResource))) { string line; while ((line = template.ReadLine()) != null) { pkgmgr.WriteLine(line); } } // Write all the user assemblies pkgmgr.WriteLine("class MonoPackageManager_Resources {"); pkgmgr.WriteLine("\tpublic static final String[] Assemblies = new String[]{"); pkgmgr.WriteLine("\t\t/* We need to ensure that \"{0}\" comes first in this list. */", mainFileName); foreach (var assembly in assemblies) { pkgmgr.WriteLine("\t\t\"" + Path.GetFileName(assembly) + "\","); } // Write the assembly dependencies pkgmgr.WriteLine("\t};"); pkgmgr.WriteLine("\tpublic static final String[] Dependencies = new String[]{"); //foreach (var assembly in assemblies.Except (args.Assemblies)) { // if (args.SharedRuntime && !Toolbox.IsInSharedRuntime (assembly)) // pkgmgr.WriteLine ("\t\t\"" + Path.GetFileName (assembly) + "\","); //} pkgmgr.WriteLine("\t};"); // Write the platform api apk we need pkgmgr.WriteLine("\tpublic static final String ApiPackageName = {0};", shared_runtime ? string.Format("\"Mono.Android.Platform.ApiLevel_{0}\"", MonoAndroidHelper.SupportedVersions.GetApiLevelFromFrameworkVersion(TargetFrameworkVersion)) : "null"); pkgmgr.WriteLine("}"); } // Only copy to the real location if the contents actually changed var dest = Path.GetFullPath(Path.Combine(OutputDirectory, "MonoPackageManager.java")); MonoAndroidHelper.CopyIfChanged(temp, dest); try { File.Delete(temp); } catch (Exception) { } try { File.Delete(temp); } catch (Exception) { } 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.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) { } }
void Run(DirectoryAssemblyResolver res) { PackageNamingPolicy pnp; JavaNativeTypeManager.PackageNamingPolicy = Enum.TryParse(PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseHash; foreach (var dir in FrameworkDirectories) { if (Directory.Exists(dir.ItemSpec)) { res.SearchDirectories.Add(dir.ItemSpec); } } var selectedWhitelistAssemblies = new List <string> (); // Put every assembly we'll need in the resolver foreach (var assembly in ResolvedAssemblies) { var assemblyFullPath = Path.GetFullPath(assembly.ItemSpec); res.Load(assemblyFullPath); if (MonoAndroidHelper.FrameworkAttributeLookupTargets.Any(a => Path.GetFileName(assembly.ItemSpec) == a)) { selectedWhitelistAssemblies.Add(assemblyFullPath); } } // However we only want to look for JLO types in user code var assemblies = ResolvedUserAssemblies.Select(p => p.ItemSpec).ToList(); var fxAdditions = MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies(ResolvedAssemblies) .Where(a => assemblies.All(x => Path.GetFileName(x) != Path.GetFileName(a))); assemblies = assemblies.Concat(fxAdditions).ToList(); // Step 1 - Find all the JLO types var scanner = new JavaTypeScanner(this.CreateTaskLogger()) { ErrorOnCustomJavaObject = ErrorOnCustomJavaObject, }; var all_java_types = scanner.GetJavaTypes(assemblies, res); WriteTypeMappings(all_java_types); var java_types = all_java_types .Where(t => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(t)) .ToArray(); // Step 2 - Generate Java stub code var success = Generator.CreateJavaSources( Log, java_types, Path.Combine(OutputDirectory, "src"), ApplicationJavaClass, UseSharedRuntime, int.Parse(AndroidSdkPlatform) <= 10, ResolvedAssemblies.Any(assembly => Path.GetFileName(assembly.ItemSpec) == "Mono.Android.Export.dll")); if (!success) { return; } // We need to save a map of .NET type -> ACW type for resource file fixups var managed = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal); var java = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal); var managedConflicts = new Dictionary <string, List <string> > (0, StringComparer.Ordinal); var javaConflicts = new Dictionary <string, List <string> > (0, StringComparer.Ordinal); // Allocate a MemoryStream with a reasonable guess at its capacity using (var stream = new MemoryStream(java_types.Length * 32)) using (var acw_map = new StreamWriter(stream)) { foreach (var type in java_types) { string managedKey = type.FullName.Replace('/', '.'); string javaKey = JavaNativeTypeManager.ToJniName(type).Replace('/', '.'); acw_map.Write(type.GetPartialAssemblyQualifiedName()); acw_map.Write(';'); acw_map.Write(javaKey); acw_map.WriteLine(); TypeDefinition conflict; bool hasConflict = false; if (managed.TryGetValue(managedKey, out conflict)) { if (!managedConflicts.TryGetValue(managedKey, out var list)) { managedConflicts.Add(managedKey, list = new List <string> { conflict.GetPartialAssemblyName() }); } list.Add(type.GetPartialAssemblyName()); hasConflict = true; } if (java.TryGetValue(javaKey, out conflict)) { if (!javaConflicts.TryGetValue(javaKey, out var list)) { javaConflicts.Add(javaKey, list = new List <string> { conflict.GetAssemblyQualifiedName() }); } list.Add(type.GetAssemblyQualifiedName()); success = false; hasConflict = true; } if (!hasConflict) { managed.Add(managedKey, type); java.Add(javaKey, type); acw_map.Write(managedKey); acw_map.Write(';'); acw_map.Write(javaKey); acw_map.WriteLine(); acw_map.Write(JavaNativeTypeManager.ToCompatJniName(type).Replace('/', '.')); acw_map.Write(';'); acw_map.Write(javaKey); acw_map.WriteLine(); } } acw_map.Flush(); MonoAndroidHelper.CopyIfStreamChanged(stream, AcwMapFile); } foreach (var kvp in managedConflicts) { Log.LogCodedWarning( "XA4214", "The managed type `{0}` exists in multiple assemblies: {1}. " + "Please refactor the managed type names in these assemblies so that they are not identical.", kvp.Key, string.Join(", ", kvp.Value)); Log.LogCodedWarning("XA4214", "References to the type `{0}` will refer to `{0}, {1}`.", kvp.Key, kvp.Value [0]); } foreach (var kvp in javaConflicts) { Log.LogCodedError( "XA4215", "The Java type `{0}` is generated by more than one managed type. " + "Please change the [Register] attribute so that the same Java type is not emitted.", kvp.Key); foreach (var typeName in kvp.Value) { Log.LogCodedError("XA4215", " `{0}` generated by: {1}", kvp.Key, typeName); } } // Step 3 - Merge [Activity] and friends into AndroidManifest.xml var manifest = new ManifestDocument(ManifestTemplate, this.Log); manifest.PackageName = PackageName; manifest.ApplicationName = ApplicationName ?? PackageName; manifest.Placeholders = ManifestPlaceholders; manifest.Assemblies.AddRange(assemblies); manifest.Resolver = res; manifest.SdkDir = AndroidSdkDir; manifest.SdkVersion = AndroidSdkPlatform; manifest.Debug = Debug; manifest.MultiDex = MultiDex; manifest.NeedsInternet = NeedsInternet; manifest.InstantRunEnabled = InstantRunEnabled; var additionalProviders = manifest.Merge(all_java_types, selectedWhitelistAssemblies, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments); using (var stream = new MemoryStream()) { manifest.Save(stream); // Only write the new manifest if it actually changed MonoAndroidHelper.CopyIfStreamChanged(stream, MergedAndroidManifestOutput); } // Create 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); }
private bool DoExecute() { bool failureDetected = false; if (string.IsNullOrEmpty(OutputFileExtension)) { OutputFileExtension = DEFAULT_FILE_EXTENSIONS[(int)outputFileType]; } Log.LogDebugMessage("Aot Task"); Log.LogDebugMessage(" Environment.CurrentDirectory: {0}", Environment.CurrentDirectory); Log.LogDebugMessage(" AotCompilerBclPath: {0}", AotCompilerBclPath); Log.LogDebugMessage(" AotOutputDirectory: {0}", AotOutputDirectory); Log.LogDebugMessage(" IntermediateAssemblyDirectory: {0}", IntermediateAssemblyDirectory); Log.LogDebugMessage(" AotCompilerPath: {0}", AotCompilerPath); Log.LogDebugMessage(" NativeToolchainPaths: {0}", NativeToolchainPaths); Log.LogDebugMessage(" NativeToolsPrefix: {0}", NativeToolsPrefix); Log.LogDebugMessage(" NativeLinkerFlags: {0}", NativeLinkerFlags); Log.LogDebugMessage(" PreAdditionalAotArguments: {0}", PreAdditionalAotArguments); Log.LogDebugMessage(" PostAdditionalAotArguments: {0}", PostAdditionalAotArguments); Log.LogDebugMessage(" IsDebug: {0}", IsDebug); Log.LogDebugMessage(" Runtime: {0}", Runtime); Log.LogDebugMessage(" EnableLLVM: {0}", EnableLLVM); Log.LogDebugMessage(" OptimizationArguments: {0}", OptimizationArguments); Log.LogDebugMessage(" InlineLimit: {0}", InlineLimit); Log.LogDebugMessage(" OnlyRecompileIfChanged: {0}", OnlyRecompileIfChanged); Log.LogDebugMessage(" GenerateNativeDebugInfo: {0}", GenerateNativeDebugInfo); Log.LogDebugMessage(" OutputFileType: {0}", OutputFileType); Log.LogDebugMessage(" OutputFileExtension: {0}", OutputFileExtension); Log.LogDebugTaskItems(" ResolvedFrameworkAssemblies:", ResolvedFrameworkAssemblies); Log.LogDebugTaskItems(" ResolvedUserAssemblies:", ResolvedUserAssemblies); var outputFiles = new List <string>(); // Calculate the MONO_PATH we'll use when invoking the AOT compiler. This is the concatenation // of AotCompilerBclPath and the dir of each assembly we will compile. var assembliesPath = string.Join(";", (AotCompilerBclPath ?? "") .Split(';').Where(p => !string.IsNullOrEmpty(p)).Select(p => Path.GetFullPath(p)) .Union( ResolvedFrameworkAssemblies .Union(ResolvedUserAssemblies) .Select(a => Path.GetDirectoryName(Path.GetFullPath(a.ItemSpec)))) .Select(p => p.TrimEnd('\\', '/')) .Distinct(StringComparer.CurrentCultureIgnoreCase)); int parallelBuildTasks = MaxParallelBuildTasks <= 0 ? Environment.ProcessorCount : MaxParallelBuildTasks; if (parallelBuildTasks > 1) { Log.LogMessage(MessageImportance.High, "Using {0} parallel build tasks.", parallelBuildTasks); } using (SemaphoreSlim parallellCompileTasks = new SemaphoreSlim(parallelBuildTasks)) { var compileTasks = new List <System.Threading.Tasks.Task <bool> >(); var currentCompileTaskId = 0; foreach (var assembly in ResolvedFrameworkAssemblies.Union(ResolvedUserAssemblies)) { if (cancellationToken.IsCancellationRequested) { failureDetected = true; break; } var outputFile = Path.Combine(AotOutputDirectory, Path.GetFileName(assembly.ItemSpec) + "." + OutputFileExtension); var outputFileLLVM = Path.Combine(AotOutputDirectory, Path.GetFileName(assembly.ItemSpec) + "-llvm." + OutputFileExtension); outputFiles.Add(outputFile); if (EnableLLVM) { outputFiles.Add(outputFileLLVM); } var assemblyPath = Path.GetFullPath(assembly.ItemSpec); if (OnlyRecompileIfChanged && File.Exists(outputFile) && File.Exists(assemblyPath) && File.GetLastWriteTime(outputFile) >= File.GetLastWriteTime(assemblyPath)) { if (!EnableLLVM && File.Exists(outputFileLLVM)) { Log.LogMessage(MessageImportance.High, " Found LLVM object file for assembly: {0} during none LLVM build, forcing recompile.", assemblyPath); } else { Log.LogMessage(MessageImportance.High, " Not recompiling unchanged assembly: {0}", assemblyPath); continue; } } if (File.Exists(outputFile)) { File.Delete(outputFile); } if (File.Exists(outputFileLLVM)) { File.Delete(outputFileLLVM); } var tempDir = Path.Combine(AotOutputDirectory, Path.GetFileName(assembly.ItemSpec) + ".tmp"); if (!Directory.Exists(tempDir)) { Directory.CreateDirectory(tempDir); } var aotOptions = new List <string>(); if (!string.IsNullOrEmpty(PreAdditionalAotArguments)) { aotOptions.Add(PreAdditionalAotArguments); } aotOptions.Add("full"); if (EnableLLVM) { aotOptions.Add("llvm"); aotOptions.Add("llvm-outfile=" + QuoteFileName(outputFileLLVM)); } aotOptions.Add("outfile=" + QuoteFileName(outputFile)); if (IsDebug && ResolvedUserAssemblies.Contains(assembly)) { aotOptions.Add("soft-debug"); } if (GenerateNativeDebugInfo) { aotOptions.Add("dwarfdebug"); } if (outputFileType == AotFileType.Asm) { aotOptions.Add("asmonly"); } aotOptions.Add("print-skipped"); if (outputFileType != AotFileType.Dll) { aotOptions.Add("static"); } aotOptions.Add("tool-prefix=" + QuoteFileName(NativeToolsPrefix)); aotOptions.Add("ld-flags=" + NativeLinkerFlags); aotOptions.Add("temp-path=" + QuoteFileName(tempDir)); if (!string.IsNullOrEmpty(PostAdditionalAotArguments)) { aotOptions.Add(PostAdditionalAotArguments); } var args = new List <string>(); if (IsDebug) { args.Add("--debug"); } if (!string.IsNullOrWhiteSpace(Runtime)) { args.Add("--runtime=" + Runtime); } if (!string.IsNullOrWhiteSpace(OptimizationArguments)) { args.Add("--optimize=" + OptimizationArguments); } args.Add("--aot=" + string.Join(",", aotOptions)); args.Add('"' + assemblyPath + '"'); parallellCompileTasks.Wait(); if (updateAndCheckTasksResult(compileTasks)) { failureDetected = true; break; } int capturedCompileTaskId = ++currentCompileTaskId; var compileTask = System.Threading.Tasks.Task <bool> .Factory.StartNew(() => { bool result = false; try { string compileTaskName = String.Format("{0}", "[AOT-" + capturedCompileTaskId + "]"); Log.LogMessage(MessageImportance.High, " {0} compiling assembly: {1}", compileTaskName, assemblyPath); result = RunAotCompiler(AotCompilerPath, args, assembliesPath, compileTaskName); if (!result) { Log.LogCodedError("XW3001", "Could not AOT compile the assembly: {0}", assemblyPath); } else { Log.LogMessage(MessageImportance.High, " {0} compilation of {1} finished", compileTaskName, Path.GetFileName(assemblyPath)); } } finally { parallellCompileTasks.Release(); } return(result); }); compileTasks.Add(compileTask); } System.Threading.Tasks.Task.WaitAll(compileTasks.ToArray()); if (updateAndCheckTasksResult(compileTasks)) { failureDetected = true; } } if (!failureDetected) { GeneratedFiles = outputFiles.Select(f => new TaskItem(f)).ToArray(); Log.LogDebugTaskItems(" [Output] GeneratedFiles:", GeneratedFiles); } return(!failureDetected); }