public static int GetMinimumApiLevelFor(AndroidTargetArch arch, string androidNdkPath) { var minValue = NdkUtil.IsNdk64BitArch(arch) ? 21 : arch == AndroidTargetArch.Arm ? 4 : 9; var platforms = GetSupportedPlatforms(androidNdkPath).OrderBy(x => x).Where(x => x >= minValue); return(platforms.First(x => Directory.Exists(Path.Combine(androidNdkPath, "platforms", $"android-{x}", $"arch-{archPathMap[arch]}")))); }
public static bool ValidateNdkPlatform(TaskLoggingHelper log, string ndkPath, AndroidTargetArch arch, bool enableLLVM) { // Check that we have a compatible NDK version for the targeted ABIs. NdkUtil.NdkVersion ndkVersion; bool hasNdkVersion = NdkUtil.GetNdkToolchainRelease(ndkPath, out ndkVersion); if (NdkUtil.IsNdk64BitArch(arch) && hasNdkVersion && ndkVersion.Version < 10) { log.LogMessage(MessageImportance.High, "The detected Android NDK version is incompatible with the targeted 64-bit architecture, " + "please upgrade to NDK r10 or newer."); } // NDK r10d is buggy and cannot link x86_64 ABI shared libraries because they are 32-bits. // See https://code.google.com/p/android/issues/detail?id=161421 if (enableLLVM && ndkVersion.Version == 10 && ndkVersion.Revision == "d" && arch == AndroidTargetArch.X86_64) { log.LogCodedError("XA3004", "Android NDK r10d is buggy and provides an incompatible x86_64 libm.so. " + "See https://code.google.com/p/android/issues/detail?id=161422."); return(false); } if (enableLLVM && (ndkVersion.Version < 10 || (ndkVersion.Version == 10 && ndkVersion.Revision[0] < 'd'))) { log.LogCodedError("XA3005", "The detected Android NDK version is incompatible with the targeted LLVM configuration, " + "please upgrade to NDK r10d or newer."); } return(true); }
public override bool Execute() { Log.LogDebugMessage("Assemblies: {0}", Assemblies.Length); Log.LogDebugMessage("SupportedAbis: {0}", SupportedAbis); Log.LogDebugMessage("AutoDeps: {0}", AutoDeps); NdkUtil.Init(AndroidNdkDirectory); try { if (String.IsNullOrEmpty(AndroidNdkDirectory)) { Log.LogCodedError("XA5101", "Could not locate Android NDK. Please make sure to configure path to NDK in SDK Locations or set via /p:AndroidNdkDirectory in the MSBuild/xbuild argument."); return(false); } return(DoExecute()); } catch (XamarinAndroidException e) { Log.LogCodedError(string.Format("XA{0:0000}", e.Code), e.MessageWithoutCode); if (MonoAndroidHelper.LogInternalExceptions) { Log.LogMessage(e.ToString()); } } catch (Exception ex) { Log.LogErrorFromException(ex); } return(!Log.HasLoggedErrors); }
public override bool RunTask() { if (EnableLLVM && !NdkUtil.Init(LogCodedError, AndroidNdkDirectory)) { return(false); } return(base.RunTask()); }
public override bool RunTask() { // NdkUtil must always be initialized - once per thread if (!NdkUtil.Init(LogCodedError, AndroidNdkDirectory)) { return(false); } return(base.RunTask()); }
public async override System.Threading.Tasks.Task RunTaskAsync() { // NdkUtil must always be initialized - once per thread if (!NdkUtil.Init(LogCodedError, AndroidNdkDirectory)) { LogDebugMessage("Failed to initialize NdkUtil"); return; } bool hasValidAotMode = GetAndroidAotMode(AndroidAotMode, out AotMode); if (!hasValidAotMode) { LogCodedError("XA3002", Properties.Resources.XA3002, AndroidAotMode); return; } if (AotMode == AotMode.Interp) { LogDebugMessage("Interpreter AOT mode enabled"); return; } TryGetSequencePointsMode(AndroidSequencePointsMode, out sequencePointsMode); var nativeLibs = new List <string> (); await this.WhenAllWithLock(GetAotConfigs(), (config, lockObject) => { if (!config.Valid) { Cancel(); return; } if (!RunAotCompiler(config.AssembliesPath, config.AotCompiler, config.AotOptions, config.AssemblyPath, config.ResponseFile)) { LogCodedError("XA3001", Properties.Resources.XA3001, Path.GetFileName(config.AssemblyPath)); Cancel(); return; } File.Delete(config.ResponseFile); lock (lockObject) nativeLibs.Add(config.OutputFile); } ); NativeLibrariesReferences = nativeLibs.ToArray(); LogDebugMessage("Aot Outputs:"); LogDebugTaskItems(" NativeLibrariesReferences: ", NativeLibrariesReferences); }
public override bool Execute() { NdkUtil.Init(AndroidNdkDirectory); try { return(DoExecute()); } catch (Exception e) { Log.LogCodedError("XA3001", "{0}", e); return(false); } }
static int GetNdkApiLevel(string androidNdkPath, string androidApiLevel, AndroidTargetArch arch) { int level = int.Parse(androidApiLevel); // Some Android API levels do not exist on the NDK level. Workaround this my mapping them to the // most appropriate API level that does exist. if (level == 6 || level == 7) { level = 5; } else if (level == 10) { level = 9; } else if (level == 11) { level = 12; } else if (level == 20) { level = 19; } else if (level == 22) { level = 21; } else if (level == 23) { level = 21; } // API levels below level 21 do not provide support for 64-bit architectures. if (NdkUtil.IsNdk64BitArch(arch) && level < 21) { level = 21; } // We perform a downwards API level lookup search since we might not have hardcoded the correct API // mapping above and we do not want to crash needlessly. for (; level >= 5; level--) { try { NdkUtil.GetNdkPlatformLibPath(androidNdkPath, arch, level); break; } catch (InvalidOperationException ex) { // Path not found, continue searching... continue; } } return(level); }
public override bool RunTask() { if (EnableLLVM && !NdkUtil.Init(Log, AndroidNdkDirectory)) { return(false); } try { return(DoExecute()); } catch (Exception e) { Log.LogCodedError("XA3001", "{0}", e); return(false); } }
public override bool RunTask () { if (!NdkUtil.Init (Log, AndroidNdkDirectory)) return false; try { return DoExecute (); } catch (XamarinAndroidException e) { Log.LogCodedError (string.Format ("XA{0:0000}", e.Code), e.MessageWithoutCode); if (MonoAndroidHelper.LogInternalExceptions) Log.LogMessage (e.ToString ()); } catch (Exception ex) { Log.LogErrorFromException (ex); } return !Log.HasLoggedErrors; }
public override bool Execute() { Log.LogDebugMessage("Assemblies: {0}", Assemblies.Length); Log.LogDebugMessage("SupportedAbis: {0}", SupportedAbis); Log.LogDebugMessage("AutoDeps: {0}", AutoDeps); if (!NdkUtil.Init(Log, AndroidNdkDirectory)) { return(false); } try { return(DoExecute()); } catch (XamarinAndroidException e) { Log.LogCodedError(string.Format("XA{0:0000}", e.Code), e.MessageWithoutCode); if (MonoAndroidHelper.LogInternalExceptions) { Log.LogMessage(e.ToString()); } } catch (Exception ex) { Log.LogErrorFromException(ex); } return(!Log.HasLoggedErrors); }
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); }
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)); } } }
int GetNdkApiLevel(string androidNdkPath, string androidApiLevel, AndroidTargetArch arch) { var manifest = AndroidAppManifest.Load(ManifestFile.ItemSpec, MonoAndroidHelper.SupportedVersions); int level; if (manifest.MinSdkVersion.HasValue) { level = manifest.MinSdkVersion.Value; } else if (int.TryParse(androidApiLevel, out level)) { // level already set } else { // Probably not ideal! level = MonoAndroidHelper.SupportedVersions.MaxStableVersion.ApiLevel; } // Some Android API levels do not exist on the NDK level. Workaround this my mapping them to the // most appropriate API level that does exist. if (level == 6 || level == 7) { level = 5; } else if (level == 10) { level = 9; } else if (level == 11) { level = 12; } else if (level == 20) { level = 19; } else if (level == 22) { level = 21; } else if (level == 23) { level = 21; } // API levels below level 21 do not provide support for 64-bit architectures. if (NdkUtil.IsNdk64BitArch(arch) && level < 21) { level = 21; } // We perform a downwards API level lookup search since we might not have hardcoded the correct API // mapping above and we do not want to crash needlessly. for (; level >= 5; level--) { try { NdkUtil.GetNdkPlatformLibPath(androidNdkPath, arch, level); break; } catch (InvalidOperationException ex) { // Path not found, continue searching... continue; } } return(level); }
private void AddNativeLibraries(ArchiveFileList files, string [] supportedAbis) { var frameworkLibs = FrameworkNativeLibraries.Select(v => new LibInfo { Path = v.ItemSpec, Link = v.GetMetadata("Link"), Abi = GetNativeLibraryAbi(v), ArchiveFileName = GetArchiveFileName(v) }); AddNativeLibraries(files, supportedAbis, frameworkLibs); var libs = NativeLibraries.Concat(BundleNativeLibraries ?? Enumerable.Empty <ITaskItem> ()) .Where(v => IncludeNativeLibrary(v)) .Select(v => new LibInfo { Path = v.ItemSpec, Link = v.GetMetadata("Link"), Abi = GetNativeLibraryAbi(v), ArchiveFileName = GetArchiveFileName(v) } ); AddNativeLibraries(files, supportedAbis, libs); if (String.IsNullOrWhiteSpace(CheckedBuild)) { return; } string mode = CheckedBuild; string sanitizerName; if (String.Compare("asan", mode, StringComparison.Ordinal) == 0) { sanitizerName = "asan"; } else if (String.Compare("ubsan", mode, StringComparison.Ordinal) == 0) { sanitizerName = "ubsan_standalone"; } else { LogSanitizerWarning($"Unknown checked build mode '{CheckedBuild}'"); return; } if (!IncludeWrapSh) { LogSanitizerError("Checked builds require the wrapper script to be packaged. Please set the `$(AndroidIncludeWrapSh)` MSBuild property to `true` in your project."); return; } if (!libs.Any(info => IsWrapperScript(info.Path, info.Link))) { LogSanitizerError($"Checked builds require the wrapper script to be packaged. Please add `wrap.sh` appropriate for the {CheckedBuild} checker to your project."); return; } NdkUtil.Init(AndroidNdkDirectory); string clangDir = NdkUtil.GetClangDeviceLibraryPath(AndroidNdkDirectory); if (String.IsNullOrEmpty(clangDir)) { LogSanitizerError($"Unable to find the clang compiler directory. Is NDK installed?"); return; } foreach (string abi in supportedAbis) { string clangAbi = MonoAndroidHelper.MapAndroidAbiToClang(abi); if (String.IsNullOrEmpty(clangAbi)) { LogSanitizerError($"Unable to map Android ABI {abi} to clang ABI"); return; } string sanitizerLib = $"libclang_rt.{sanitizerName}-{clangAbi}-android.so"; string sanitizerLibPath = Path.Combine(clangDir, sanitizerLib); if (!File.Exists(sanitizerLibPath)) { LogSanitizerError($"Unable to find sanitizer runtime for the {CheckedBuild} checker at {sanitizerLibPath}"); return; } AddNativeLibrary(files, sanitizerLibPath, abi, sanitizerLib); } }
static string GetNdkToolchainLibraryDir(string binDir, AndroidTargetArch arch) { return(GetNdkToolchainLibraryDir(binDir, NdkUtil.GetArchDirName(arch))); }
IEnumerable <Config> GetLinkerConfigs() { var abis = new Dictionary <string, InputFiles> (StringComparer.Ordinal); ITaskItem[] dsos = ApplicationSharedLibraries; foreach (ITaskItem item in dsos) { string abi = item.GetMetadata("abi"); abis [abi] = GatherFilesForABI(item.ItemSpec, abi, ObjectFiles); } foreach (var kvp in abis) { string abi = kvp.Key; InputFiles inputs = kvp.Value; AndroidTargetArch arch; var linkerArgs = new List <string> { "--unresolved-symbols=ignore-in-shared-libs", "--export-dynamic", "-soname", "libxamarin-app.so", "-z", "relro", "-z", "noexecstack", "--enable-new-dtags", "--eh-frame-hdr", "-shared", "--build-id", "--warn-shared-textrel", "--fatal-warnings", "-o", QuoteFileName(inputs.OutputSharedLibrary), }; string elf_arch; switch (abi) { case "armeabi-v7a": arch = AndroidTargetArch.Arm; linkerArgs.Add("-X"); elf_arch = "armelf_linux_eabi"; break; case "arm64": case "arm64-v8a": case "aarch64": arch = AndroidTargetArch.Arm64; linkerArgs.Add("--fix-cortex-a53-843419"); elf_arch = "aarch64linux"; break; case "x86": arch = AndroidTargetArch.X86; elf_arch = "elf_i386"; break; case "x86_64": arch = AndroidTargetArch.X86_64; elf_arch = "elf_x86_64"; break; default: throw new NotSupportedException($"Unsupported Android target architecture ABI: {abi}"); } linkerArgs.Add("-m"); linkerArgs.Add(elf_arch); foreach (string file in inputs.ObjectFiles) { linkerArgs.Add(QuoteFileName(file)); } string ld = MonoAndroidHelper.GetExecutablePath(AndroidBinUtilsDirectory, $"{NdkUtil.GetNdkToolchainPrefix (arch, false)}ld"); yield return(new Config { LinkerPath = Path.Combine(AndroidBinUtilsDirectory, ld), LinkerOptions = String.Join(" ", linkerArgs), OutputSharedLibrary = inputs.OutputSharedLibrary, }); } }
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 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 SupportedAbis) { 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, }; string windowsCompilerSwitches = NdkUtil.GetCompilerTargetParameters(AndroidNdkDirectory, arch, level); var compilerNoQuotes = NdkUtil.GetNdkTool(AndroidNdkDirectory, arch, "gcc", level); var compiler = $"\"{compilerNoQuotes}\" {windowsCompilerSwitches}".Trim(); var gas = '"' + NdkUtil.GetNdkTool(AndroidNdkDirectory, arch, "as", level) + '"'; psi.EnvironmentVariables ["CC"] = compiler; psi.EnvironmentVariables ["AS"] = gas; Log.LogDebugMessage("CC=" + compiler); 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", Properties.Resources.XA5102, proc.ExitCode); return(false); } // then compile temp.c into temp.o and ... clb = new CommandLineBuilder(); // See NdkUtils.GetNdkTool for reasons why if (!String.IsNullOrEmpty(windowsCompilerSwitches)) { clb.AppendTextUnquoted(windowsCompilerSwitches); } 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] " + compiler + " " + clb); if (MonoAndroidHelper.RunProcess(compilerNoQuotes, clb.ToString(), OnCcOutputData, OnCcErrorData) != 0) { Log.LogCodedError("XA5103", Properties.Resources.XA5103, 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", level); Log.LogMessage(MessageImportance.Normal, "[LD] " + ld + " " + clb); if (MonoAndroidHelper.RunProcess(ld, clb.ToString(), OnLdOutputData, OnLdErrorData) != 0) { Log.LogCodedError("XA5201", Properties.Resources.XA5201, proc.ExitCode); return(false); } results.Add(new TaskItem(Path.Combine(outpath, "libmonodroid_bundle_app.so"))); } OutputNativeLibraries = results.ToArray(); return(true); }
IEnumerable <Config> GetAotConfigs() { if (!Directory.Exists(AotOutputDirectory)) { Directory.CreateDirectory(AotOutputDirectory); } var sdkBinDirectory = MonoAndroidHelper.GetOSBinPath(); foreach (var abi in SupportedAbis) { string aotCompiler = ""; string outdir = ""; string mtriple = ""; AndroidTargetArch arch; switch (abi) { 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 (EnableLLVM && !NdkUtil.ValidateNdkPlatform(LogMessage, LogCodedError, AndroidNdkDirectory, arch, enableLLVM:EnableLLVM)) { yield return(Config.Invalid); yield break; } outdir = Path.GetFullPath(outdir); if (!Directory.Exists(outdir)) { Directory.CreateDirectory(outdir); } // dont use a full path if the outdir is withing the WorkingDirectory. if (outdir.StartsWith(WorkingDirectory, StringComparison.InvariantCultureIgnoreCase)) { outdir = outdir.Replace(WorkingDirectory + Path.DirectorySeparatorChar, string.Empty); } int level = 0; string toolPrefix = EnableLLVM ? NdkUtil.GetNdkToolPrefix(AndroidNdkDirectory, arch, level = GetNdkApiLevel(AndroidNdkDirectory, AndroidApiLevel, arch)) : Path.Combine(AndroidBinUtilsDirectory, $"{NdkUtil.GetArchDirName (arch)}-"); var toolchainPath = toolPrefix.Substring(0, toolPrefix.LastIndexOf(Path.DirectorySeparatorChar)); var ldFlags = string.Empty; if (EnableLLVM) { if (string.IsNullOrEmpty(AndroidNdkDirectory)) { yield return(Config.Invalid); yield break; } string androidLibPath = string.Empty; try { androidLibPath = NdkUtil.GetNdkPlatformLibPath(AndroidNdkDirectory, arch, level); } catch (InvalidOperationException ex) { Diagnostic.Error(5101, ex.Message); } string toolchainLibDir; if (NdkUtil.UsingClangNDK) { toolchainLibDir = GetNdkToolchainLibraryDir(toolchainPath, arch); } else { toolchainLibDir = GetNdkToolchainLibraryDir(toolchainPath); } var libs = new List <string>(); if (NdkUtil.UsingClangNDK) { libs.Add($"-L{toolchainLibDir}"); libs.Add($"-L{androidLibPath}"); if (arch == AndroidTargetArch.Arm) { // Needed for -lunwind to work string compilerLibDir = Path.Combine(toolchainPath, "..", "sysroot", "usr", "lib", NdkUtil.GetArchDirName(arch)); libs.Add($"-L{compilerLibDir}"); } } libs.Add($"\\\"{Path.Combine (toolchainLibDir, "libgcc.a")}\\\""); libs.Add($"\\\"{Path.Combine (androidLibPath, "libc.so")}\\\""); libs.Add($"\\\"{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 (Profiles != null && Profiles.Length > 0) { aotOptions.Add("profile-only"); foreach (var p in Profiles) { var fp = Path.GetFullPath(p.ItemSpec); aotOptions.Add($"profile={fp}"); } } if (!string.IsNullOrEmpty(AotAdditionalArguments)) { aotOptions.Add(AotAdditionalArguments); } if (sequencePointsMode == SequencePointsMode.Offline) { aotOptions.Add($"msym-dir={outdir}"); } if (AotMode != AotMode.Normal) { aotOptions.Add(AotMode.ToString().ToLowerInvariant()); } aotOptions.Add($"outfile={outputFile}"); aotOptions.Add("asmwriter"); aotOptions.Add($"mtriple={mtriple}"); aotOptions.Add($"tool-prefix={toolPrefix}"); aotOptions.Add($"llvm-path={sdkBinDirectory}"); aotOptions.Add($"temp-path={tempDir}"); aotOptions.Add($"ld-flags={ldFlags}"); // we need to quote the entire --aot arguments here to make sure it is parsed // on windows as one argument. Otherwise it will be split up into multiple // values, which wont work. 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 = Path.GetFullPath(resolvedPath); yield return(new Config(assembliesPath, aotCompiler, aotOptionsStr, assemblyPath, outputFile, Path.Combine(tempDir, "response.txt"))); } } }