public override bool Execute() { Log.LogDebugMessage("BuildApk Task"); Log.LogDebugMessage(" ApkInputPath: {0}", ApkInputPath); Log.LogDebugMessage(" ApkOutputPath: {0}", ApkOutputPath); Log.LogDebugMessage(" BundleAssemblies: {0}", BundleAssemblies); Log.LogDebugTaskItems(" DalvikClasses:", DalvikClasses); Log.LogDebugMessage(" SupportedAbis: {0}", SupportedAbis); Log.LogDebugMessage(" UseSharedRuntime: {0}", UseSharedRuntime); Log.LogDebugMessage(" Debug: {0}", Debug ?? "no"); Log.LogDebugMessage(" PreferNativeLibrariesWithDebugSymbols: {0}", PreferNativeLibrariesWithDebugSymbols); Log.LogDebugMessage(" EmbedAssemblies: {0}", EmbedAssemblies); Log.LogDebugMessage(" AndroidSequencePointsMode: {0}", AndroidSequencePointsMode); Log.LogDebugMessage(" CreatePackagePerAbi: {0}", CreatePackagePerAbi); Log.LogDebugMessage(" UncompressedFileExtensions: {0}", UncompressedFileExtensions); Log.LogDebugTaskItems(" ResolvedUserAssemblies:", ResolvedUserAssemblies); Log.LogDebugTaskItems(" ResolvedFrameworkAssemblies:", ResolvedFrameworkAssemblies); Log.LogDebugTaskItems(" NativeLibraries:", NativeLibraries); Log.LogDebugTaskItems(" AdditionalNativeLibraryReferences:", AdditionalNativeLibraryReferences); Log.LogDebugTaskItems(" BundleNativeLibraries:", BundleNativeLibraries); Log.LogDebugTaskItems(" JavaSourceFiles:", JavaSourceFiles); Log.LogDebugTaskItems(" JavaLibraries:", JavaLibraries); Log.LogDebugTaskItems(" LibraryProjectJars:", LibraryProjectJars); Log.LogDebugTaskItems(" AdditionalNativeLibraryReferences:", AdditionalNativeLibraryReferences); Aot.TryGetSequencePointsMode(AndroidSequencePointsMode, out sequencePointsMode); if (string.IsNullOrEmpty(AndroidEmbedProfilers) && _Debug) { AndroidEmbedProfilers = "log"; } var outputFiles = new List <string> (); uncompressedFileExtensions = UncompressedFileExtensions?.Split(new char [] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries) ?? new string [0]; ExecuteWithAbi(SupportedAbis, ApkInputPath, ApkOutputPath); outputFiles.Add(ApkOutputPath); if (CreatePackagePerAbi) { var abis = SupportedAbis.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); if (abis.Length > 1) { foreach (var abi in abis) { var path = Path.GetDirectoryName(ApkOutputPath); var apk = Path.GetFileNameWithoutExtension(ApkOutputPath); ExecuteWithAbi(abi, String.Format("{0}-{1}", ApkInputPath, abi), Path.Combine(path, String.Format("{0}-{1}.apk", apk, abi))); outputFiles.Add(Path.Combine(path, String.Format("{0}-{1}.apk", apk, abi))); } } } OutputFiles = outputFiles.Select(a => new TaskItem(a)).ToArray(); Log.LogDebugTaskItems(" [Output] OutputFiles :", OutputFiles); return(!Log.HasLoggedErrors); }
void UpdateWhenChanged(string path, string type, MemoryStream ms, Action <Stream> generator) { if (InstantRunEnabled) { ms.SetLength(0); generator(ms); MonoAndroidHelper.CopyIfStreamChanged(ms, path); } string dataFilePath = $"{path}.inc"; using (var stream = new NativeAssemblyDataStream()) { generator(stream); stream.EndOfFile(); MonoAndroidHelper.CopyIfStreamChanged(stream, dataFilePath); var generatedFiles = new List <ITaskItem> (); string mappingFieldName = $"{type}_typemap"; string dataFileName = Path.GetFileName(dataFilePath); NativeAssemblerTargetProvider asmTargetProvider; var utf8Encoding = new UTF8Encoding(false); foreach (string abi in SupportedAbis.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)) { ms.SetLength(0); switch (abi.Trim()) { case "armeabi-v7a": asmTargetProvider = new ARMNativeAssemblerTargetProvider(is64Bit: false); break; case "arm64-v8a": asmTargetProvider = new ARMNativeAssemblerTargetProvider(is64Bit: true); break; case "x86": asmTargetProvider = new X86NativeAssemblerTargetProvider(is64Bit: false); break; case "x86_64": asmTargetProvider = new X86NativeAssemblerTargetProvider(is64Bit: true); break; default: throw new InvalidOperationException($"Unknown ABI {abi}"); } var asmgen = new TypeMappingNativeAssemblyGenerator(asmTargetProvider, stream, dataFileName, stream.MapByteCount, mappingFieldName); string asmFileName = $"{path}.{abi.Trim ()}.s"; using (var sw = new StreamWriter(ms, utf8Encoding, bufferSize: 8192, leaveOpen: true)) { asmgen.Write(sw, dataFileName); MonoAndroidHelper.CopyIfStreamChanged(ms, asmFileName); } } } }
void ProcessManifest(ITaskItem manifestFile) { var manifest = Path.IsPathRooted(manifestFile.ItemSpec) ? manifestFile.ItemSpec : Path.Combine(WorkingDirectory, manifestFile.ItemSpec); if (!File.Exists(manifest)) { LogDebugMessage("{0} does not exists. Skipping", manifest); return; } bool upToDate = ManifestIsUpToDate(manifest); if (AdditionalAndroidResourcePaths != null) { foreach (var dir in AdditionalAndroidResourcePaths) { if (!string.IsNullOrEmpty(dir.ItemSpec)) { upToDate = upToDate && ManifestIsUpToDate(string.Format("{0}{1}{2}{3}{4}", dir, Path.DirectorySeparatorChar, "manifest", Path.DirectorySeparatorChar, "AndroidManifest.xml")); } } } if (upToDate) { LogMessage(" Additional Android Resources manifsets files are unchanged. Skipping."); return; } var defaultAbi = new string [] { null }; var abis = SupportedAbis?.Split(new char [] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); var outputFile = string.IsNullOrEmpty(OutputFile) ? Path.GetTempFileName() : OutputFile; foreach (var abi in (CreatePackagePerAbi && abis?.Length > 1) ? defaultAbi.Concat(abis) : defaultAbi) { var currentResourceOutputFile = abi != null?string.Format("{0}-{1}", outputFile, abi) : outputFile; if (!string.IsNullOrEmpty(currentResourceOutputFile) && !Path.IsPathRooted(currentResourceOutputFile)) { currentResourceOutputFile = Path.Combine(WorkingDirectory, currentResourceOutputFile); } if (!ExecuteForAbi(GenerateCommandLineCommands(manifest, abi, currentResourceOutputFile), currentResourceOutputFile)) { Cancel(); } } return; }
int DoExecute(ITaskItem manifestFile, ThreadingTasks.ParallelLoopState state, int loop) { if (!File.Exists(manifestFile.ItemSpec)) { LogDebugMessage("{0} does not exists. Skipping", manifestFile.ItemSpec); return(0); } bool upToDate = ManifestIsUpToDate(manifestFile.ItemSpec); if (AdditionalAndroidResourcePaths != null) { foreach (var dir in AdditionalAndroidResourcePaths) { if (!string.IsNullOrEmpty(dir.ItemSpec)) { upToDate = upToDate && ManifestIsUpToDate(string.Format("{0}{1}{2}{3}{4}", dir, Path.DirectorySeparatorChar, "manifest", Path.DirectorySeparatorChar, "AndroidManifest.xml")); } } } if (upToDate) { LogMessage(" Additional Android Resources manifsets files are unchanged. Skipping."); return(0); } var defaultAbi = new string [] { null }; var abis = SupportedAbis?.Split(new char [] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (var abi in (CreatePackagePerAbi && abis?.Length > 1) ? defaultAbi.Concat(abis) : defaultAbi) { var currentResourceOutputFile = abi != null?string.Format("{0}-{1}", ResourceOutputFile, abi) : ResourceOutputFile; if (!ExecuteForAbi(GenerateCommandLineCommands(manifestFile.ItemSpec, abi, currentResourceOutputFile), currentResourceOutputFile)) { Cancel(); } } return(0); }
public override bool Execute() { Aot.TryGetSequencePointsMode(AndroidSequencePointsMode, out sequencePointsMode); if (string.IsNullOrEmpty(AndroidEmbedProfilers) && _Debug) { AndroidEmbedProfilers = "log"; } var outputFiles = new List <string> (); uncompressedFileExtensions = UncompressedFileExtensions?.Split(new char [] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries) ?? new string [0]; ExecuteWithAbi(SupportedAbis, ApkInputPath, ApkOutputPath); outputFiles.Add(ApkOutputPath); if (CreatePackagePerAbi) { var abis = SupportedAbis.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); if (abis.Length > 1) { foreach (var abi in abis) { var path = Path.GetDirectoryName(ApkOutputPath); var apk = Path.GetFileNameWithoutExtension(ApkOutputPath); ExecuteWithAbi(abi, String.Format("{0}-{1}", ApkInputPath, abi), Path.Combine(path, String.Format("{0}-{1}.apk", apk, abi))); outputFiles.Add(Path.Combine(path, String.Format("{0}-{1}.apk", apk, abi))); } } } OutputFiles = outputFiles.Select(a => new TaskItem(a)).ToArray(); Log.LogDebugTaskItems(" [Output] OutputFiles :", OutputFiles); return(!Log.HasLoggedErrors); }
IEnumerable <Config> GetAotConfigs() { if (!Directory.Exists(AotOutputDirectory)) { Directory.CreateDirectory(AotOutputDirectory); } // Check that we have a compatible NDK version for the targeted ABIs. NdkUtil.NdkVersion ndkVersion; bool hasNdkVersion = NdkUtil.GetNdkToolchainRelease(AndroidNdkDirectory, out ndkVersion); var sdkBinDirectory = MonoAndroidHelper.GetOSBinPath(); var abis = SupportedAbis.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (var abi in abis) { string aotCompiler = ""; string outdir = ""; string mtriple = ""; AndroidTargetArch arch; switch (abi) { case "armeabi": aotCompiler = Path.Combine(sdkBinDirectory, "cross-arm"); outdir = Path.Combine(AotOutputDirectory, "armeabi"); mtriple = "armv5-linux-gnueabi"; arch = AndroidTargetArch.Arm; break; case "armeabi-v7a": aotCompiler = Path.Combine(sdkBinDirectory, "cross-arm"); outdir = Path.Combine(AotOutputDirectory, "armeabi-v7a"); mtriple = "armv7-linux-gnueabi"; arch = AndroidTargetArch.Arm; break; case "arm64": case "arm64-v8a": case "aarch64": aotCompiler = Path.Combine(sdkBinDirectory, "cross-arm64"); outdir = Path.Combine(AotOutputDirectory, "arm64-v8a"); mtriple = "aarch64-linux-android"; arch = AndroidTargetArch.Arm64; break; case "x86": aotCompiler = Path.Combine(sdkBinDirectory, "cross-x86"); outdir = Path.Combine(AotOutputDirectory, "x86"); mtriple = "i686-linux-android"; arch = AndroidTargetArch.X86; break; case "x86_64": aotCompiler = Path.Combine(sdkBinDirectory, "cross-x86_64"); outdir = Path.Combine(AotOutputDirectory, "x86_64"); mtriple = "x86_64-linux-android"; arch = AndroidTargetArch.X86_64; break; // case "mips": default: throw new Exception("Unsupported Android target architecture ABI: " + abi); } if (!NdkUtil.ValidateNdkPlatform(Log, AndroidNdkDirectory, arch, enableLLVM:EnableLLVM)) { yield return(Config.Invalid); yield break; } if (!ValidateAotConfiguration(Log, arch, EnableLLVM)) { yield return(Config.Invalid); yield break; } outdir = Path.GetFullPath(outdir); if (!Directory.Exists(outdir)) { Directory.CreateDirectory(outdir); } var toolPrefix = NdkUtil.GetNdkToolPrefix(AndroidNdkDirectory, arch); var toolchainPath = toolPrefix.Substring(0, toolPrefix.LastIndexOf(Path.DirectorySeparatorChar)); var ldFlags = string.Empty; if (EnableLLVM) { int level = GetNdkApiLevel(AndroidNdkDirectory, AndroidApiLevel, arch); string androidLibPath = string.Empty; try { androidLibPath = NdkUtil.GetNdkPlatformLibPath(AndroidNdkDirectory, arch, level); } catch (InvalidOperationException ex) { Diagnostic.Error(5101, ex.Message); } var libs = new List <string>() { GetShortPath(Path.Combine(GetNdkToolchainLibraryDir(toolchainPath), "libgcc.a")), GetShortPath(Path.Combine(androidLibPath, "libc.so")), GetShortPath(Path.Combine(androidLibPath, "libm.so")) }; ldFlags = string.Join(";", libs); } foreach (var assembly in ResolvedAssemblies) { string outputFile = Path.Combine(outdir, string.Format("libaot-{0}.so", Path.GetFileName(assembly.ItemSpec))); string seqpointsFile = Path.Combine(outdir, string.Format("{0}.msym", Path.GetFileName(assembly.ItemSpec))); string tempDir = Path.Combine(outdir, Path.GetFileName(assembly.ItemSpec)); if (!Directory.Exists(tempDir)) { Directory.CreateDirectory(tempDir); } List <string> aotOptions = new List <string> (); if (!string.IsNullOrEmpty(AotAdditionalArguments)) { aotOptions.Add(AotAdditionalArguments); } if (sequencePointsMode == SequencePointsMode.Offline) { aotOptions.Add("msym-dir=" + GetShortPath(outdir)); } if (AotMode != AotMode.Normal) { aotOptions.Add(AotMode.ToString().ToLowerInvariant()); } aotOptions.Add("outfile=" + GetShortPath(outputFile)); aotOptions.Add("asmwriter"); aotOptions.Add("mtriple=" + mtriple); aotOptions.Add("tool-prefix=" + GetShortPath(toolPrefix)); aotOptions.Add("ld-flags=" + ldFlags); aotOptions.Add("llvm-path=" + GetShortPath(sdkBinDirectory)); aotOptions.Add("temp-path=" + GetShortPath(tempDir)); string aotOptionsStr = (EnableLLVM ? "--llvm " : "") + "--aot=" + string.Join(",", aotOptions); if (!string.IsNullOrEmpty(ExtraAotOptions)) { aotOptionsStr += (aotOptions.Count > 0 ? "," : "") + ExtraAotOptions; } // Due to a Monodroid MSBuild bug we can end up with paths to assemblies that are not in the intermediate // assembly directory (typically obj/assemblies). This can lead to problems with the Mono loader not being // able to find their dependency laters, since framework assemblies are stored in different directories. // This can happen when linking is disabled (AndroidLinkMode=None). Workaround this problem by resolving // the paths to the right assemblies manually. var resolvedPath = Path.GetFullPath(assembly.ItemSpec); var intermediateAssemblyPath = Path.Combine(IntermediateAssemblyDir, Path.GetFileName(assembly.ItemSpec)); if (LinkMode.ToLowerInvariant() == "none") { if (!resolvedPath.Contains(IntermediateAssemblyDir) && File.Exists(intermediateAssemblyPath)) { resolvedPath = intermediateAssemblyPath; } } var assembliesPath = Path.GetFullPath(Path.GetDirectoryName(resolvedPath)); var assemblyPath = QuoteFileName(Path.GetFullPath(resolvedPath)); yield return(new Config(assembliesPath, QuoteFileName(aotCompiler), aotOptionsStr, assemblyPath, outputFile)); } } }
public override bool Execute() { Log.LogDebugMessage("BuildApk Task"); Log.LogDebugMessage(" ApkInputPath: {0}", ApkInputPath); Log.LogDebugMessage(" ApkOutputPath: {0}", ApkOutputPath); Log.LogDebugMessage(" BundleAssemblies: {0}", BundleAssemblies); Log.LogDebugTaskItems(" DalvikClasses:", DalvikClasses); Log.LogDebugMessage(" SupportedAbis: {0}", SupportedAbis); Log.LogDebugMessage(" UseSharedRuntime: {0}", UseSharedRuntime); Log.LogDebugMessage(" Debug: {0}", Debug ?? "no"); Log.LogDebugMessage(" EmbedAssemblies: {0}", EmbedAssemblies); Log.LogDebugMessage(" AndroidAotMode: {0}", AndroidAotMode); Log.LogDebugMessage(" AndroidSequencePointsMode: {0}", AndroidSequencePointsMode); Log.LogDebugMessage(" CreatePackagePerAbi: {0}", CreatePackagePerAbi); Log.LogDebugTaskItems(" Environments:", Environments); Log.LogDebugTaskItems(" ResolvedUserAssemblies:", ResolvedUserAssemblies); Log.LogDebugTaskItems(" ResolvedFrameworkAssemblies:", ResolvedFrameworkAssemblies); Log.LogDebugTaskItems(" NativeLibraries:", NativeLibraries); Log.LogDebugTaskItems(" AdditionalNativeLibraryReferences:", AdditionalNativeLibraryReferences); Log.LogDebugTaskItems(" BundleNativeLibraries:", BundleNativeLibraries); Log.LogDebugTaskItems(" JavaSourceFiles:", JavaSourceFiles); Log.LogDebugTaskItems(" JavaLibraries:", JavaLibraries); Log.LogDebugTaskItems(" LibraryProjectJars:", LibraryProjectJars); Log.LogDebugTaskItems(" AdditionalNativeLibraryReferences:", AdditionalNativeLibraryReferences); Log.LogDebugTaskItems(" HttpClientHandlerType:", HttpClientHandlerType); Aot.TryGetSequencePointsMode(AndroidSequencePointsMode, out sequencePointsMode); var androidDebugServer = GdbPaths.GetAndroidDebugServer(AndroidGdbDebugServer); if (!androidDebugServer.HasValue) { Log.LogError("Unable to determine debug server variant: {0}", AndroidGdbDebugServer); return(false); } debugServer = androidDebugServer.Value; if (string.IsNullOrEmpty(AndroidEmbedProfilers) && _Debug) { AndroidEmbedProfilers = "log"; } var outputFiles = new List <string> (); ExecuteWithAbi(SupportedAbis, ApkInputPath, ApkOutputPath); outputFiles.Add(ApkOutputPath); if (CreatePackagePerAbi) { var abis = SupportedAbis.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); if (abis.Length > 1) { foreach (var abi in abis) { var path = Path.GetDirectoryName(ApkOutputPath); var apk = Path.GetFileNameWithoutExtension(ApkOutputPath); ExecuteWithAbi(abi, String.Format("{0}-{1}", ApkInputPath, abi), Path.Combine(path, String.Format("{0}-{1}.apk", apk, abi))); outputFiles.Add(Path.Combine(path, String.Format("{0}-{1}.apk", apk, abi))); } } } BuildId = buildId.ToString(); Log.LogDebugMessage(" [Output] BuildId: {0}", BuildId); OutputFiles = outputFiles.Select(a => new TaskItem(a)).ToArray(); Log.LogDebugTaskItems(" [Output] OutputFiles :", OutputFiles); return(!Log.HasLoggedErrors); }
bool DoExecute() { var abis = SupportedAbis.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); var results = new List <ITaskItem> (); string bundlepath = Path.Combine(TempOutputPath, "bundles"); if (!Directory.Exists(bundlepath)) { Directory.CreateDirectory(bundlepath); } else { Directory.Delete(bundlepath, true); } foreach (var abi in abis) { AndroidTargetArch arch = AndroidTargetArch.Other; switch (abi) { case "arm64": case "arm64-v8a": case "aarch64": arch = AndroidTargetArch.Arm64; break; case "armeabi": case "armeabi-v7a": arch = AndroidTargetArch.Arm; break; case "x86": arch = AndroidTargetArch.X86; break; case "x86_64": arch = AndroidTargetArch.X86_64; break; case "mips": arch = AndroidTargetArch.Mips; break; } if (!NdkUtil.ValidateNdkPlatform(Log, AndroidNdkDirectory, arch, requireLibm:true)) { return(false); } // FIXME: it is kind of hacky, we should have something like NdkUtil.GetMinimumApiLevelFor(arch). int level = NdkUtil.IsNdk64BitArch(arch) ? 21 : arch == AndroidTargetArch.Arm ? 4 : 9; var outpath = Path.Combine(bundlepath, abi); if (!Directory.Exists(outpath)) { Directory.CreateDirectory(outpath); } var clb = new CommandLineBuilder(); clb.AppendSwitch("--dos2unix=false"); clb.AppendSwitch("--nomain"); clb.AppendSwitch("--style"); clb.AppendSwitch("linux"); clb.AppendSwitch("-c"); clb.AppendSwitch("-o"); clb.AppendFileNameIfNotNull(Path.Combine(outpath, "temp.c")); clb.AppendSwitch("-oo"); clb.AppendFileNameIfNotNull(Path.Combine(outpath, "assemblies.o")); if (AutoDeps) { clb.AppendSwitch("--autodeps"); } if (KeepTemp) { clb.AppendSwitch("--keeptemp"); } clb.AppendSwitch("-z"); // Compress clb.AppendFileNamesIfNotNull(Assemblies, " "); var psi = new ProcessStartInfo() { FileName = MkbundlePath, Arguments = clb.ToString(), UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, }; var gccNoQuotes = NdkUtil.GetNdkTool(AndroidNdkDirectory, arch, "gcc"); var gcc = '"' + gccNoQuotes + '"'; var gas = '"' + NdkUtil.GetNdkTool(AndroidNdkDirectory, arch, "as") + '"'; psi.EnvironmentVariables ["CC"] = gcc; psi.EnvironmentVariables ["AS"] = gas; Log.LogDebugMessage("CC=" + gcc); Log.LogDebugMessage("AS=" + gas); //psi.EnvironmentVariables ["PKG_CONFIG_PATH"] = Path.Combine (Path.GetDirectoryName (MonoDroidSdk.MandroidTool), "lib", abi); Log.LogDebugMessage("[mkbundle] " + psi.FileName + " " + clb); var proc = new Process(); proc.OutputDataReceived += OnMkbundleOutputData; proc.ErrorDataReceived += OnMkbundleErrorData; proc.StartInfo = psi; proc.Start(); proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); proc.WaitForExit(); if (proc.ExitCode != 0) { Log.LogCodedError("XA5102", "Conversion from assembly to native code failed. Exit code {0}", proc.ExitCode); return(false); } // make some changes in the mkbundle output so that it does not require libmonodroid.so var mkbundleOutput = File.ReadAllText(Path.Combine(outpath, "temp.c")); mkbundleOutput = mkbundleOutput.Replace("void mono_mkbundle_init ()", "void mono_mkbundle_init (void (register_bundled_assemblies_func)(const MonoBundledAssembly **), void (register_config_for_assembly_func)(const char *, const char *))") .Replace("mono_register_config_for_assembly (\"", "register_config_for_assembly_func (\"") .Replace("install_dll_config_files (void)", "install_dll_config_files (void (register_config_for_assembly_func)(const char *, const char *))") .Replace("install_dll_config_files ()", "install_dll_config_files (register_config_for_assembly_func)") .Replace("mono_register_bundled_assemblies(", "register_bundled_assemblies_func("); File.WriteAllText(Path.Combine(outpath, "temp.c"), mkbundleOutput); // then compile temp.c into temp.o and ... clb = new CommandLineBuilder(); clb.AppendSwitch("-c"); clb.AppendSwitch("-o"); clb.AppendFileNameIfNotNull(Path.Combine(outpath, "temp.o")); if (!string.IsNullOrWhiteSpace(IncludePath)) { clb.AppendSwitch("-I"); clb.AppendFileNameIfNotNull(IncludePath); } clb.AppendSwitch("-I"); clb.AppendFileNameIfNotNull(NdkUtil.GetNdkPlatformIncludePath(AndroidNdkDirectory, arch, level)); clb.AppendFileNameIfNotNull(Path.Combine(outpath, "temp.c")); Log.LogDebugMessage("[CC] " + gcc + " " + clb); if (MonoAndroidHelper.RunProcess(gccNoQuotes, clb.ToString(), OnCcOutputData, OnCcErrorData) != 0) { Log.LogCodedError("XA5103", "NDK C compiler resulted in an error. Exit code {0}", proc.ExitCode); return(false); } // ... link temp.o and assemblies.o into app.so clb = new CommandLineBuilder(); clb.AppendSwitch("--shared"); clb.AppendFileNameIfNotNull(Path.Combine(outpath, "temp.o")); clb.AppendFileNameIfNotNull(Path.Combine(outpath, "assemblies.o")); clb.AppendSwitch("-o"); clb.AppendFileNameIfNotNull(Path.Combine(outpath, "libmonodroid_bundle_app.so")); clb.AppendSwitch("-L"); clb.AppendFileNameIfNotNull(NdkUtil.GetNdkPlatformLibPath(AndroidNdkDirectory, arch, level)); clb.AppendSwitch("-lc"); clb.AppendSwitch("-lm"); clb.AppendSwitch("-ldl"); clb.AppendSwitch("-llog"); clb.AppendSwitch("-lz"); // Compress string ld = NdkUtil.GetNdkTool(AndroidNdkDirectory, arch, "ld"); Log.LogMessage(MessageImportance.Normal, "[LD] " + ld + " " + clb); if (MonoAndroidHelper.RunProcess(ld, clb.ToString(), OnLdOutputData, OnLdErrorData) != 0) { Log.LogCodedError("XA5201", "NDK Linker resulted in an error. Exit code {0}", proc.ExitCode); return(false); } results.Add(new TaskItem(Path.Combine(outpath, "libmonodroid_bundle_app.so"))); } OutputNativeLibraries = results.ToArray(); return(true); }
bool DoExecute() { var abis = SupportedAbis.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); var results = new List <ITaskItem> (); string bundlepath = Path.Combine(TempOutputPath, "bundles"); if (!Directory.Exists(bundlepath)) { Directory.CreateDirectory(bundlepath); } else { Directory.Delete(bundlepath, true); } foreach (var abi in abis) { AndroidTargetArch arch = AndroidTargetArch.Other; switch (abi) { case "arm64": case "arm64-v8a": case "aarch64": arch = AndroidTargetArch.Arm64; break; case "armeabi-v7a": arch = AndroidTargetArch.Arm; break; case "x86": arch = AndroidTargetArch.X86; break; case "x86_64": arch = AndroidTargetArch.X86_64; break; case "mips": arch = AndroidTargetArch.Mips; break; } if (!NdkUtil.ValidateNdkPlatform(Log, AndroidNdkDirectory, arch, enableLLVM: false)) { return(false); } int level = NdkUtil.GetMinimumApiLevelFor(arch, AndroidNdkDirectory); var outpath = Path.Combine(bundlepath, abi); if (!Directory.Exists(outpath)) { Directory.CreateDirectory(outpath); } var clb = new CommandLineBuilder(); clb.AppendSwitch("--dos2unix=false"); clb.AppendSwitch("--nomain"); clb.AppendSwitch("--i18n none"); clb.AppendSwitch("--bundled-header"); clb.AppendSwitch("--mono-api-struct-path"); clb.AppendFileNameIfNotNull(BundleApiPath); clb.AppendSwitch("--style"); clb.AppendSwitch("linux"); clb.AppendSwitch("-c"); clb.AppendSwitch("-o"); clb.AppendFileNameIfNotNull(Path.Combine(outpath, "temp.c")); clb.AppendSwitch("-oo"); clb.AppendFileNameIfNotNull(Path.Combine(outpath, "assemblies.o")); if (AutoDeps) { clb.AppendSwitch("--autodeps"); } if (KeepTemp) { clb.AppendSwitch("--keeptemp"); } clb.AppendSwitch("-z"); // Compress clb.AppendFileNamesIfNotNull(Assemblies, " "); var psi = new ProcessStartInfo() { FileName = MkbundlePath, Arguments = clb.ToString(), UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, }; var gccNoQuotes = NdkUtil.GetNdkTool(AndroidNdkDirectory, arch, "gcc"); var gcc = '"' + gccNoQuotes + '"'; var gas = '"' + NdkUtil.GetNdkTool(AndroidNdkDirectory, arch, "as") + '"'; psi.EnvironmentVariables ["CC"] = gcc; psi.EnvironmentVariables ["AS"] = gas; Log.LogDebugMessage("CC=" + gcc); Log.LogDebugMessage("AS=" + gas); //psi.EnvironmentVariables ["PKG_CONFIG_PATH"] = Path.Combine (Path.GetDirectoryName (MonoDroidSdk.MandroidTool), "lib", abi); Log.LogDebugMessage("[mkbundle] " + psi.FileName + " " + clb); var proc = new Process(); proc.OutputDataReceived += OnMkbundleOutputData; proc.ErrorDataReceived += OnMkbundleErrorData; proc.StartInfo = psi; proc.Start(); proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); proc.WaitForExit(); if (proc.ExitCode != 0) { Log.LogCodedError("XA5102", "Conversion from assembly to native code failed. Exit code {0}", proc.ExitCode); return(false); } // then compile temp.c into temp.o and ... clb = new CommandLineBuilder(); clb.AppendSwitch("-c"); // This is necessary only when unified headers are in use but it won't hurt to have it // defined even if we don't use them clb.AppendSwitch($"-D__ANDROID_API__={level}"); // This is necessary because of the injected code, which is reused between libmonodroid // and the bundle clb.AppendSwitch("-DANDROID"); clb.AppendSwitch("-o"); clb.AppendFileNameIfNotNull(Path.Combine(outpath, "temp.o")); if (!string.IsNullOrWhiteSpace(IncludePath)) { clb.AppendSwitch("-I"); clb.AppendFileNameIfNotNull(IncludePath); } string asmIncludePath = NdkUtil.GetNdkAsmIncludePath(AndroidNdkDirectory, arch, level); if (!String.IsNullOrEmpty(asmIncludePath)) { clb.AppendSwitch("-I"); clb.AppendFileNameIfNotNull(asmIncludePath); } clb.AppendSwitch("-I"); clb.AppendFileNameIfNotNull(NdkUtil.GetNdkPlatformIncludePath(AndroidNdkDirectory, arch, level)); clb.AppendFileNameIfNotNull(Path.Combine(outpath, "temp.c")); Log.LogDebugMessage("[CC] " + gcc + " " + clb); if (MonoAndroidHelper.RunProcess(gccNoQuotes, clb.ToString(), OnCcOutputData, OnCcErrorData) != 0) { Log.LogCodedError("XA5103", "NDK C compiler resulted in an error. Exit code {0}", proc.ExitCode); return(false); } // ... link temp.o and assemblies.o into app.so clb = new CommandLineBuilder(); clb.AppendSwitch("--shared"); clb.AppendFileNameIfNotNull(Path.Combine(outpath, "temp.o")); clb.AppendFileNameIfNotNull(Path.Combine(outpath, "assemblies.o")); // API23+ requires that the shared library has its soname set or it won't load clb.AppendSwitch("-soname"); clb.AppendSwitch(BundleSharedLibraryName); clb.AppendSwitch("-o"); clb.AppendFileNameIfNotNull(Path.Combine(outpath, BundleSharedLibraryName)); clb.AppendSwitch("-L"); clb.AppendFileNameIfNotNull(NdkUtil.GetNdkPlatformLibPath(AndroidNdkDirectory, arch, level)); clb.AppendSwitch("-lc"); clb.AppendSwitch("-lm"); clb.AppendSwitch("-ldl"); clb.AppendSwitch("-llog"); clb.AppendSwitch("-lz"); // Compress string ld = NdkUtil.GetNdkTool(AndroidNdkDirectory, arch, "ld"); Log.LogMessage(MessageImportance.Normal, "[LD] " + ld + " " + clb); if (MonoAndroidHelper.RunProcess(ld, clb.ToString(), OnLdOutputData, OnLdErrorData) != 0) { Log.LogCodedError("XA5201", "NDK Linker resulted in an error. Exit code {0}", proc.ExitCode); return(false); } results.Add(new TaskItem(Path.Combine(outpath, "libmonodroid_bundle_app.so"))); } OutputNativeLibraries = results.ToArray(); return(true); }
bool DoExecute() { Log.LogDebugMessage("Aot:", AndroidAotMode); Log.LogDebugMessage(" AndroidApiLevel: {0}", AndroidApiLevel); Log.LogDebugMessage(" AndroidAotMode: {0}", AndroidAotMode); Log.LogDebugMessage(" AndroidSequencePointsMode: {0}", AndroidSequencePointsMode); Log.LogDebugMessage(" AndroidNdkDirectory: {0}", AndroidNdkDirectory); Log.LogDebugMessage(" AotOutputDirectory: {0}", AotOutputDirectory); Log.LogDebugMessage(" EnableLLVM: {0}", EnableLLVM); Log.LogDebugMessage(" IntermediateAssemblyDir: {0}", IntermediateAssemblyDir); Log.LogDebugMessage(" LinkMode: {0}", LinkMode); Log.LogDebugMessage(" SdkBinDirectory: {0}", SdkBinDirectory); Log.LogDebugMessage(" SupportedAbis: {0}", SupportedAbis); Log.LogDebugTaskItems(" ResolvedAssemblies:", ResolvedAssemblies); Log.LogDebugTaskItems(" AdditionalNativeLibraryReferences:", AdditionalNativeLibraryReferences); bool hasValidAotMode = GetAndroidAotMode(AndroidAotMode, out AotMode); if (!hasValidAotMode) { Log.LogCodedError("XA3001", "Invalid AOT mode: {0}", AndroidAotMode); return(false); } TryGetSequencePointsMode(AndroidSequencePointsMode, out sequencePointsMode); var nativeLibs = new List <string> (); if (!Directory.Exists(AotOutputDirectory)) { Directory.CreateDirectory(AotOutputDirectory); } // Check that we have a compatible NDK version for the targeted ABIs. NdkUtil.NdkVersion ndkVersion; bool hasNdkVersion = NdkUtil.GetNdkToolchainRelease(AndroidNdkDirectory, out ndkVersion); var abis = SupportedAbis.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (var abi in abis) { string aotCompiler = ""; string outdir = ""; string mtriple = ""; AndroidTargetArch arch; switch (abi) { case "armeabi": aotCompiler = Path.Combine(SdkBinDirectory, "cross-arm"); outdir = Path.Combine(AotOutputDirectory, "armeabi"); mtriple = "armv5-linux-gnueabi"; arch = AndroidTargetArch.Arm; break; case "armeabi-v7a": aotCompiler = Path.Combine(SdkBinDirectory, "cross-arm"); outdir = Path.Combine(AotOutputDirectory, "armeabi-v7a"); mtriple = "armv7-linux-gnueabi"; arch = AndroidTargetArch.Arm; break; case "arm64": case "arm64-v8a": case "aarch64": aotCompiler = Path.Combine(SdkBinDirectory, "cross-arm64"); outdir = Path.Combine(AotOutputDirectory, "arm64-v8a"); mtriple = "aarch64-linux-android"; arch = AndroidTargetArch.Arm64; break; case "x86": aotCompiler = Path.Combine(SdkBinDirectory, "cross-x86"); outdir = Path.Combine(AotOutputDirectory, "x86"); mtriple = "i686-linux-android"; arch = AndroidTargetArch.X86; break; case "x86_64": aotCompiler = Path.Combine(SdkBinDirectory, "cross-x86_64"); outdir = Path.Combine(AotOutputDirectory, "x86_64"); mtriple = "x86_64-linux-android"; arch = AndroidTargetArch.X86_64; break; // case "mips": default: throw new Exception("Unsupported Android target architecture ABI: " + abi); } if (!NdkUtil.ValidateNdkPlatform(Log, AndroidNdkDirectory, arch, enableLLVM:EnableLLVM)) { return(false); } if (!ValidateAotConfiguration(Log, arch, EnableLLVM)) { return(false); } outdir = Path.GetFullPath(outdir); if (!Directory.Exists(outdir)) { Directory.CreateDirectory(outdir); } var toolPrefix = NdkUtil.GetNdkToolPrefix(AndroidNdkDirectory, arch); var toolchainPath = toolPrefix.Substring(0, toolPrefix.LastIndexOf(Path.DirectorySeparatorChar)); var ldFlags = string.Empty; if (EnableLLVM) { int level = GetNdkApiLevel(AndroidNdkDirectory, AndroidApiLevel, arch); string androidLibPath = string.Empty; try { androidLibPath = NdkUtil.GetNdkPlatformLibPath(AndroidNdkDirectory, arch, level); } catch (InvalidOperationException ex) { Diagnostic.Error(5101, ex.Message); } var libs = new List <string>() { QuoteFileName(Path.Combine(GetNdkToolchainLibraryDir(toolchainPath), "libgcc.a")), QuoteFileName(Path.Combine(androidLibPath, "libc.so")), QuoteFileName(Path.Combine(androidLibPath, "libm.so")) }; ldFlags = string.Join(";", libs); } foreach (var assembly in ResolvedAssemblies) { string outputFile = Path.Combine(outdir, string.Format("libaot-{0}.so", Path.GetFileName(assembly.ItemSpec))); string seqpointsFile = Path.Combine(outdir, string.Format("{0}.msym", Path.GetFileName(assembly.ItemSpec))); string aotOptions = string.Format( "{0}--aot={8}{1}outfile={2},asmwriter,mtriple={3},tool-prefix={4},ld-flags={5},llvm-path={6},temp-path={7}", EnableLLVM ? "--llvm " : string.Empty, AotMode != AotMode.Normal ? string.Format("{0},", AotMode.ToString().ToLowerInvariant()) : string.Empty, QuoteFileName(outputFile), mtriple, QuoteFileName(toolPrefix), ldFlags, QuoteFileName(SdkBinDirectory), QuoteFileName(outdir), sequencePointsMode == SequencePointsMode.Offline ? string.Format("gen-seq-points-file={0},", seqpointsFile) : string.Empty ); // Due to a Monodroid MSBuild bug we can end up with paths to assemblies that are not in the intermediate // assembly directory (typically obj/assemblies). This can lead to problems with the Mono loader not being // able to find their dependency laters, since framework assemblies are stored in different directories. // This can happen when linking is disabled (AndroidLinkMode=None). Workaround this problem by resolving // the paths to the right assemblies manually. var resolvedPath = Path.GetFullPath(assembly.ItemSpec); var intermediateAssemblyPath = Path.Combine(IntermediateAssemblyDir, Path.GetFileName(assembly.ItemSpec)); if (LinkMode.ToLowerInvariant() == "none") { if (!resolvedPath.Contains(IntermediateAssemblyDir) && File.Exists(intermediateAssemblyPath)) { resolvedPath = intermediateAssemblyPath; } } var assembliesPath = Path.GetFullPath(Path.GetDirectoryName(resolvedPath)); var assemblyPath = QuoteFileName(Path.GetFullPath(resolvedPath)); if (!RunAotCompiler(assembliesPath, aotCompiler, aotOptions, assemblyPath)) { Log.LogCodedError("XA3001", "Could not AOT the assembly: {0}", assembly.ItemSpec); return(false); } nativeLibs.Add(outputFile); } } NativeLibrariesReferences = nativeLibs.ToArray(); Log.LogDebugTaskItems("Aot Outputs:"); Log.LogDebugTaskItems(" NativeLibrariesReferences: ", NativeLibrariesReferences); return(true); }
public override bool Execute() { Log.LogDebugMessage("Aapt Task"); Log.LogDebugMessage(" AssetDirectory: {0}", AssetDirectory); Log.LogDebugMessage(" ManifestFile: {0}", ManifestFile); Log.LogDebugMessage(" ResourceDirectory: {0}", ResourceDirectory); Log.LogDebugMessage(" JavaDesignerOutputDirectory: {0}", JavaDesignerOutputDirectory); Log.LogDebugMessage(" PackageName: {0}", PackageName); Log.LogDebugMessage(" UncompressedFileExtensions: {0}", UncompressedFileExtensions); Log.LogDebugMessage(" ExtraPackages: {0}", ExtraPackages); Log.LogDebugTaskItems(" AdditionalResourceDirectories: ", AdditionalResourceDirectories); Log.LogDebugTaskItems(" AdditionalAndroidResourcePaths: ", AdditionalAndroidResourcePaths); Log.LogDebugTaskItems(" LibraryProjectJars: ", LibraryProjectJars); Log.LogDebugMessage(" ExtraArgs: {0}", ExtraArgs); Log.LogDebugMessage(" CreatePackagePerAbi: {0}", CreatePackagePerAbi); Log.LogDebugMessage(" ResourceNameCaseMap: {0}", ResourceNameCaseMap); if (CreatePackagePerAbi) { Log.LogDebugMessage(" SupportedAbis: {0}", SupportedAbis); } bool upToDate = ManifestIsUpToDate(ManifestFile); if (ResourceNameCaseMap != null) { foreach (var arr in ResourceNameCaseMap.Split(';').Select(l => l.Split('|')).Where(a => a.Length == 2)) { resource_name_case_map [arr [1]] = arr [0]; // lowercase -> original } } if (AdditionalAndroidResourcePaths != null) { foreach (var dir in AdditionalAndroidResourcePaths) { if (!string.IsNullOrEmpty(dir.ItemSpec)) { upToDate = upToDate && ManifestIsUpToDate(string.Format("{0}{1}{2}", dir, Path.DirectorySeparatorChar, "manifest", Path.DirectorySeparatorChar, "AndroidManifest.xml")); } } } if (upToDate) { Log.LogMessage(MessageImportance.Normal, " Additional Android Resources manifsets files are unchanged. Skipping."); return(true); } ExecuteForAbi(null); if (CreatePackagePerAbi) { var abis = SupportedAbis.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); if (abis.Length > 1) { foreach (var abi in abis) { ExecuteForAbi(abi); } } } return(!Log.HasLoggedErrors); }
void AddEnvironment() { bool usesEmbeddedDSOs = false; bool usesMonoAOT = false; bool usesAssemblyPreload = EnablePreloadAssembliesDefault; uint monoAOTMode = 0; string androidPackageName = null; var environmentVariables = new Dictionary <string, string> (StringComparer.Ordinal); var systemProperties = new Dictionary <string, string> (StringComparer.Ordinal); AotMode aotMode; if (AndroidAotMode != null && Aot.GetAndroidAotMode(AndroidAotMode, out aotMode)) { usesMonoAOT = true; monoAOTMode = (uint)aotMode; } bool haveLogLevel = false; bool haveMonoDebug = false; bool havebuildId = false; bool haveHttpMessageHandler = false; bool haveTlsProvider = false; bool haveMonoGCParams = false; SequencePointsMode sequencePointsMode; if (!Aot.TryGetSequencePointsMode(AndroidSequencePointsMode, out sequencePointsMode)) { sequencePointsMode = SequencePointsMode.None; } foreach (ITaskItem env in Environments ?? new TaskItem[0]) { foreach (string line in File.ReadLines(env.ItemSpec)) { var lineToWrite = line; if (lineToWrite.StartsWith("MONO_LOG_LEVEL=", StringComparison.Ordinal)) { haveLogLevel = true; } if (lineToWrite.StartsWith("MONO_GC_PARAMS=", StringComparison.Ordinal)) { haveMonoGCParams = true; } if (lineToWrite.StartsWith("XAMARIN_BUILD_ID=", StringComparison.Ordinal)) { havebuildId = true; } if (lineToWrite.StartsWith("MONO_DEBUG=", StringComparison.Ordinal)) { haveMonoDebug = true; if (sequencePointsMode != SequencePointsMode.None && !lineToWrite.Contains("gen-compact-seq-points")) { lineToWrite = line + ",gen-compact-seq-points"; } } if (lineToWrite.StartsWith("XA_HTTP_CLIENT_HANDLER_TYPE=", StringComparison.Ordinal)) { haveHttpMessageHandler = true; } if (lineToWrite.StartsWith("XA_TLS_PROVIDER=", StringComparison.Ordinal)) { haveTlsProvider = true; } if (lineToWrite.StartsWith("__XA_DSO_IN_APK", StringComparison.Ordinal)) { usesEmbeddedDSOs = true; continue; } if (lineToWrite.StartsWith("mono.enable_assembly_preload=", StringComparison.Ordinal)) { int idx = lineToWrite.IndexOf('='); uint val; if (idx < lineToWrite.Length - 1 && UInt32.TryParse(lineToWrite.Substring(idx + 1), out val)) { usesAssemblyPreload = idx == 1; } continue; } AddEnvironmentVariableLine(lineToWrite); } } if (_Debug && !haveLogLevel) { AddEnvironmentVariable(defaultLogLevel[0], defaultLogLevel[1]); } if (sequencePointsMode != SequencePointsMode.None && !haveMonoDebug) { AddEnvironmentVariable(defaultMonoDebug[0], defaultMonoDebug[1]); } if (!havebuildId) { AddEnvironmentVariable("XAMARIN_BUILD_ID", BuildId); } if (!haveHttpMessageHandler) { if (HttpClientHandlerType == null) { AddEnvironmentVariable(defaultHttpMessageHandler[0], defaultHttpMessageHandler[1]); } else { AddEnvironmentVariable("XA_HTTP_CLIENT_HANDLER_TYPE", HttpClientHandlerType.Trim()); } } if (!haveTlsProvider) { if (TlsProvider == null) { AddEnvironmentVariable(defaultTlsProvider[0], defaultTlsProvider[1]); } else { AddEnvironmentVariable("XA_TLS_PROVIDER", TlsProvider.Trim()); } } if (!haveMonoGCParams) { if (EnableSGenConcurrent) { AddEnvironmentVariable("MONO_GC_PARAMS", "major=marksweep-conc"); } else { AddEnvironmentVariable("MONO_GC_PARAMS", "major=marksweep"); } } using (var ms = new MemoryStream()) { var utf8Encoding = new UTF8Encoding(false); foreach (string abi in SupportedAbis.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)) { ms.SetLength(0); NativeAssemblerTargetProvider asmTargetProvider; string asmFileName = Path.Combine(EnvironmentOutputDirectory, $"environment.{abi.ToLowerInvariant ()}.s"); switch (abi.Trim()) { case "armeabi-v7a": asmTargetProvider = new ARMNativeAssemblerTargetProvider(false); break; case "arm64-v8a": asmTargetProvider = new ARMNativeAssemblerTargetProvider(true); break; case "x86": asmTargetProvider = new X86NativeAssemblerTargetProvider(false); break; case "x86_64": asmTargetProvider = new X86NativeAssemblerTargetProvider(true); break; default: throw new InvalidOperationException($"Unknown ABI {abi}"); } var asmgen = new ApplicationConfigNativeAssemblyGenerator(asmTargetProvider, environmentVariables, systemProperties) { IsBundledApp = IsBundledApplication, UsesEmbeddedDSOs = usesEmbeddedDSOs, UsesMonoAOT = usesMonoAOT, UsesMonoLLVM = EnableLLVM, UsesAssemblyPreload = usesAssemblyPreload, MonoAOTMode = monoAOTMode.ToString().ToLowerInvariant(), AndroidPackageName = AndroidPackageName, }; using (var sw = new StreamWriter(ms, utf8Encoding, bufferSize: 8192, leaveOpen: true)) { asmgen.Write(sw, asmFileName); MonoAndroidHelper.CopyIfStreamChanged(ms, asmFileName); } } } void AddEnvironmentVariable(string name, string value) { if (Char.IsUpper(name [0]) || !Char.IsLetter(name [0])) { environmentVariables [ValidAssemblerString(name)] = ValidAssemblerString(value); } else { systemProperties [ValidAssemblerString(name)] = ValidAssemblerString(value); } } void AddEnvironmentVariableLine(string l) { string line = l?.Trim(); if (String.IsNullOrEmpty(line) || line [0] == '#') { return; } string[] nv = line.Split(new char[] { '=' }, 2); AddEnvironmentVariable(nv[0].Trim(), nv.Length < 2 ? String.Empty : nv[1].Trim()); } string ValidAssemblerString(string s) { return(s.Replace("\"", "\\\"")); } }