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);
        }
예제 #3
0
        void Run(DirectoryAssemblyResolver res)
        {
            PackageNamingPolicy pnp;

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

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

            var selectedWhitelistAssemblies = new List <string> ();

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

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

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

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

            WriteTypeMappings(all_java_types);

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

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

            if (!success)
            {
                return;
            }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            SaveResource(notifyTimeZoneChangesFile, notifyTimeZoneChangesFile, real_app_dir, template => template);
        }
        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);
        }
예제 #6
0
파일: Aot.cs 프로젝트: wjk/xamarin-windows
        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);
        }