1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-09 09:34:49 +09:00

[Android] Add NdkToolFinder task & Fix up AOT app build (#88210)

Since we bumped to NDK 23, having the aot compiler itself generate shared libraries stopped working. This is due to NDK 23 moving most of the toolchain into a common bin directory. AS was left over in each of these directories as an alias to bin/<triple>-as.

This change adds a task to collect all of the important NDK toolchain paths. It also fixes up the aot build when AOTWithLibraryFiles is set to true and we want the aot compiler to produce shared libraries.
This commit is contained in:
Steve Pfister 2023-07-06 04:22:37 -07:00 committed by GitHub
parent cd9d54165b
commit b3d2503a06
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 553 additions and 37 deletions

View file

@ -149,6 +149,7 @@
<AppleAppBuilderDir>$([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'AppleAppBuilder', 'Debug', '$(NetCoreAppToolCurrent)'))</AppleAppBuilderDir>
<AndroidAppBuilderDir>$([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'AndroidAppBuilder', 'Debug', '$(NetCoreAppToolCurrent)', 'publish'))</AndroidAppBuilderDir>
<MobileBuildTasksDir>$([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'MobileBuildTasks', 'Debug', '$(NetCoreAppToolCurrent)'))</MobileBuildTasksDir>
<WasmAppBuilderDir>$([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'WasmAppBuilder', 'Debug', '$(NetCoreAppToolCurrent)'))</WasmAppBuilderDir>
<WasmBuildTasksDir>$([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'WasmBuildTasks', 'Debug', '$(NetCoreAppToolCurrent)', 'publish'))</WasmBuildTasksDir>
<WorkloadBuildTasksDir>$([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'WorkloadBuildTasks', 'Debug', '$(NetCoreAppToolCurrent)'))</WorkloadBuildTasksDir>
@ -162,6 +163,7 @@
<Crossgen2SdkOverrideTargetsPath Condition="'$(MSBuildRuntimeType)' == 'Core'">$([MSBuild]::NormalizePath('$(ArtifactsBinDir)', 'Crossgen2Tasks', 'Debug', '$(NetCoreAppToolCurrent)', 'Microsoft.NET.CrossGen.targets'))</Crossgen2SdkOverrideTargetsPath>
<AppleAppBuilderTasksAssemblyPath>$([MSBuild]::NormalizePath('$(AppleAppBuilderDir)', 'AppleAppBuilder.dll'))</AppleAppBuilderTasksAssemblyPath>
<AndroidAppBuilderTasksAssemblyPath>$([MSBuild]::NormalizePath('$(AndroidAppBuilderDir)', 'AndroidAppBuilder.dll'))</AndroidAppBuilderTasksAssemblyPath>
<MobileBuildTasksAssemblyPath>$([MSBuild]::NormalizePath('$(MobileBuildTasksDir)', 'MobileBuildTasks.dll'))</MobileBuildTasksAssemblyPath>
<WasmAppBuilderTasksAssemblyPath>$([MSBuild]::NormalizePath('$(WasmAppBuilderDir)', 'WasmAppBuilder.dll'))</WasmAppBuilderTasksAssemblyPath>
<WasmBuildTasksAssemblyPath>$([MSBuild]::NormalizePath('$(WasmBuildTasksDir)', 'WasmBuildTasks.dll'))</WasmBuildTasksAssemblyPath>
<WasmAppHostDir>$([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'WasmAppHost', 'wasm', '$(Configuration)'))</WasmAppHostDir>

View file

@ -239,6 +239,7 @@ typedef struct MonoAotOptions {
gboolean deterministic;
gboolean allow_errors;
char *tool_prefix;
char *as_prefix;
char *ld_flags;
char *ld_name;
char *mtriple;
@ -8825,6 +8826,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
opts->nunbox_arbitrary_trampolines = atoi (arg + strlen ("nunbox-arbitrary-trampolines="));
} else if (str_begins_with (arg, "tool-prefix=")) {
opts->tool_prefix = g_strdup (arg + strlen ("tool-prefix="));
} else if (str_begins_with (arg, "as-prefix=")) {
opts->as_prefix = g_strdup (arg + strlen ("as-prefix="));
} else if (str_begins_with (arg, "ld-flags=")) {
opts->ld_flags = g_strdup (arg + strlen ("ld-flags="));
} else if (str_begins_with (arg, "ld-name=")) {
@ -13123,6 +13126,7 @@ compile_asm (MonoAotCompile *acfg)
char *command, *objfile;
char *outfile_name, *tmp_outfile_name, *llvm_ofile;
const char *tool_prefix = acfg->aot_opts.tool_prefix ? acfg->aot_opts.tool_prefix : "";
const char *as_prefix = acfg->aot_opts.as_prefix ? acfg->aot_opts.as_prefix : tool_prefix;
char *ld_flags = acfg->aot_opts.ld_flags ? acfg->aot_opts.ld_flags : g_strdup("");
#ifdef TARGET_WIN32_MSVC
@ -13214,7 +13218,7 @@ compile_asm (MonoAotCompile *acfg)
g_string_append (acfg->as_args, "-c -x assembler ");
#endif
command = g_strdup_printf ("\"%s%s\" %s %s -o %s %s", tool_prefix, AS_NAME, AS_OPTIONS,
command = g_strdup_printf ("\"%s%s\" %s %s -o %s %s", as_prefix, AS_NAME, AS_OPTIONS,
acfg->as_args ? acfg->as_args->str : "",
wrap_path (objfile), wrap_path (acfg->tmpfname));
aot_printf (acfg, "Executing the native assembler: %s\n", command);
@ -13225,7 +13229,7 @@ compile_asm (MonoAotCompile *acfg)
}
if (acfg->llvm && !acfg->llvm_owriter) {
command = g_strdup_printf ("\"%s%s\" %s %s -o %s %s", tool_prefix, AS_NAME, AS_OPTIONS,
command = g_strdup_printf ("\"%s%s\" %s %s -o %s %s", as_prefix, AS_NAME, AS_OPTIONS,
acfg->as_args ? acfg->as_args->str : "",
wrap_path (acfg->llvm_ofile), wrap_path (acfg->llvm_sfile));
aot_printf (acfg, "Executing the native assembler: %s\n", command);
@ -14222,6 +14226,7 @@ aot_opts_free (MonoAotOptions *aot_opts)
g_list_free (aot_opts->direct_pinvoke_lists);
g_free (aot_opts->dedup_include);
g_free (aot_opts->tool_prefix);
g_free (aot_opts->as_prefix);
g_free (aot_opts->ld_flags);
g_free (aot_opts->ld_name);
g_free (aot_opts->mtriple);

View file

@ -4,6 +4,10 @@
<UseMonoRuntime>true</UseMonoRuntime>
<UseMonoJustInterp Condition="'$(RunAOTCompilation)' == 'true' and '$(MonoForceInterpreter)' == 'true'">true</UseMonoJustInterp>
<_HostOS Condition="$([MSBuild]::IsOSPlatform('Windows'))">windows</_HostOS>
<_HostOS Condition="$([MSBuild]::IsOSPlatform('OSX'))">osx</_HostOS>
<_HostOS Condition="'$(_HostOS)' == ''">linux</_HostOS>
<_IsLibraryMode Condition="'$(NativeLib)' != ''">true</_IsLibraryMode>
<AndroidBuildAfterThisTarget Condition="'$(AndroidBuildAfterThisTarget)' == ''">Publish</AndroidBuildAfterThisTarget>

View file

@ -8,6 +8,9 @@
<EnableDefaultAssembliesToBundle Condition="'$(EnableDefaultAssembliesToBundle)' == ''">false</EnableDefaultAssembliesToBundle>
</PropertyGroup>
<UsingTask Condition="'$(RunAOTCompilation)' == 'true'"
TaskName="NdkToolFinderTask"
AssemblyFile="$(MobileBuildTasksAssemblyPath)" />
<UsingTask Condition="'$(AndroidGenerateAppBundle)' == 'true'"
TaskName="AndroidAppBuilderTask"
AssemblyFile="$(AndroidAppBuilderTasksAssemblyPath)" />
@ -37,7 +40,6 @@
<BundleDir>$(AndroidBundleDir)</BundleDir>
<_MonoHeaderPath>$([MSBuild]::NormalizeDirectory($(MicrosoftNetCoreAppRuntimePackRidNativeDir), 'include', 'mono-2.0'))</_MonoHeaderPath>
<_AotModuleTablePath>$(AndroidBundleDir)\modules.c</_AotModuleTablePath>
</PropertyGroup>
<PropertyGroup>
@ -94,6 +96,15 @@
<_AOTMode Condition="'$(UseMonoJustInterp)' != 'true'">Normal</_AOTMode>
<_AOTMode Condition="'$(UseMonoJustInterp)' == 'true'">JustInterp</_AOTMode>
<_AOTMode Condition="'$(ForceFullAOT)' == 'true'">Full</_AOTMode>
<_AotOutputType>AsmOnly</_AotOutputType>
</PropertyGroup>
<!-- Should consider renaming property to something more appropriate-->
<PropertyGroup Condition="'$(AOTWithLibraryFiles)' == 'true'">
<_AotOutputType>Library</_AotOutputType>
<_AotLibraryFormat>So</_AotLibraryFormat>
</PropertyGroup>
<PropertyGroup Condition="'$(AOTWithLibraryFiles)' != 'true'">
<_AotModuleTablePath>$(AndroidBundleDir)\modules.c</_AotModuleTablePath>
</PropertyGroup>
<PropertyGroup Condition="'$(_IsLibraryMode)' == 'true'">
@ -126,6 +137,28 @@
<ProcessArguments>@(MonoAOTCompilerDefaultProcessArguments, ';')</ProcessArguments>
</PropertyGroup>
<PropertyGroup>
<AndroidLibraryMinApiLevel Condition="'$(AndroidLibraryMinApiLevel)' == ''">21</AndroidLibraryMinApiLevel>
</PropertyGroup>
<NdkToolFinderTask
Condition="'$(AOTWithLibraryFiles)' == 'true'"
Architecture="$(TargetArchitecture)"
HostOS="$(_HostOS)"
MinApiLevel="$(AndroidLibraryMinApiLevel)">
<Output TaskParameter="AsPrefixPath" PropertyName="_AsPrefixPath" />
<Output TaskParameter="ToolPrefixPath" PropertyName="_ToolPrefixPath" />
<Output TaskParameter="Triple" PropertyName="_Triple" />
<Output TaskParameter="LdName" PropertyName="_LdName" />
<Output TaskParameter="LdPath" PropertyName="_LdPath" />
<Output TaskParameter="ClangPath" PropertyName="_ClangPath" />
</NdkToolFinderTask>
<PropertyGroup Condition="'$(AOTWithLibraryFiles)' == 'true'">
<_AsPrefixPath>$([MSBuild]::EnsureTrailingSlash('$(_AsPrefixPath)'))</_AsPrefixPath>
<_ToolPrefixPath>$([MSBuild]::EnsureTrailingSlash('$(_ToolPrefixPath)'))</_ToolPrefixPath>
</PropertyGroup>
<ItemGroup>
<_AotInputAssemblies Include="@(_AssembliesToBundleInternal)"
Condition="'%(_AssembliesToBundleInternal._InternalForceInterpret)' != 'true'">
@ -182,17 +215,20 @@
<MonoAOTCompiler
AotModulesTablePath="$(_AotModuleTablePath)"
AsPrefix="$(_AsPrefixPath)"
Assemblies="@(_AotInputAssemblies)"
CompilerBinaryPath="@(MonoAotCrossCompiler->WithMetadataValue('RuntimeIdentifier','$(TargetOS.ToLowerInvariant())-$(TargetArchitecture.ToLowerInvariant())'))"
DirectPInvokes="@(DirectPInvokes)"
DirectPInvokeLists="@(DirectPInvokeLists)"
EnableUnmanagedCallersOnlyMethodsExport="$(_EnableUnmanagedCallersOnlyMethodsExport)"
IntermediateOutputPath="$(_MobileIntermediateOutputPath)"
LibraryFormat="$(_AotLibraryFormat)"
LLVMPath="$(MonoAotCrossDir)"
MibcProfilePath="@(ProfiledAOTProfilePaths)"
Mode="$(_AOTMode)"
OutputDir="$(_MobileIntermediateOutputPath)"
OutputType="AsmOnly"
OutputType="$(_AotOutputType)"
ToolPrefix="$(_ToolPrefixPath)"
UseAotDataFile="$(_UseAotDataFile)"
UseLLVM="$(MonoEnableLLVM)">
<Output TaskParameter="CompiledAssemblies" ItemName="_AssembliesToBundleInternal" />

View file

@ -11,8 +11,13 @@
</PropertyGroup>
<Import Project="$(RepoTasksDir)AotCompilerTask\MonoAOTCompiler.props" />
<UsingTask TaskName="AndroidAppBuilderTask" AssemblyFile="$(AndroidAppBuilderTasksAssemblyPath)"/>
<UsingTask TaskName="MonoAOTCompiler" AssemblyFile="$(MonoAOTCompilerTasksAssemblyPath)" />
<UsingTask TaskName="AndroidAppBuilderTask"
AssemblyFile="$(AndroidAppBuilderTasksAssemblyPath)"/>
<UsingTask TaskName="MonoAOTCompiler"
AssemblyFile="$(MonoAOTCompilerTasksAssemblyPath)" />
<UsingTask Condition="'$(RunAOTCompilation)' == 'true'"
TaskName="NdkToolFinderTask"
AssemblyFile="$(MobileBuildTasksAssemblyPath)" />
<PropertyGroup Condition="'$(RunAOTCompilation)' == 'true'">
<_MobileIntermediateOutputPath>$(IntermediateOutputPath)mobile</_MobileIntermediateOutputPath>
@ -36,46 +41,57 @@
Condition="'$(ForceAOT)' == 'true'"/>
<RemoveDir Directories="$(ApkDir)" />
<PropertyGroup>
<AndroidAbi Condition="'$(TargetArchitecture)' == 'arm64'">arm64-v8a</AndroidAbi>
<AndroidAbi Condition="'$(TargetArchitecture)' == 'arm'">armeabi-v7a</AndroidAbi>
<AndroidAbi Condition="'$(TargetArchitecture)' == 'x64'">x86_64</AndroidAbi>
<AndroidAbi Condition="'$(TargetArchitecture)' == 'x86'">x86</AndroidAbi>
</PropertyGroup>
<Message Importance="High" Text="Path: $(PublishDir)" />
<Message Importance="High" Text="SourceDir: $(OutputPath)" />
<PropertyGroup Condition="'$(ForceAOT)' == 'true' and '$(AOTWithLibraryFiles)' != 'true'">
<_AotOutputType>AsmOnly</_AotOutputType>
<_AotModulesTablePath>$(ApkDir)\modules.c</_AotModulesTablePath>
</PropertyGroup>
<PropertyGroup Condition="'$(ForceAOT)' == 'true' and '$(AOTWithLibraryFiles)' == 'true'">
<_AotOutputType>Library</_AotOutputType>
<_AotLibraryFormat>So</_AotLibraryFormat>
<_PrebuiltOS Condition="$([MSBuild]::IsOSPlatform('Linux'))">linux-x86_64</_PrebuiltOS>
<_PrebuiltOS Condition="$([MSBuild]::IsOSPlatform('OSX'))">darwin-x86_64</_PrebuiltOS>
<_PrebuiltOS Condition="$([MSBuild]::IsOSPlatform('Windows'))">windows-x86_64</_PrebuiltOS>
<_PrebuiltAbi Condition="'$(TargetArchitecture)' == 'arm'">arm-linux-androideabi$</_PrebuiltAbi>
<_PrebuiltAbi Condition="'$(TargetArchitecture)' == 'arm64'">aarch64-linux-android</_PrebuiltAbi>
<_PrebuiltAbi Condition="'$(TargetArchitecture)' == 'x64'">x86_64-linux-android</_PrebuiltAbi>
<_PrebuiltAbi Condition="'$(TargetArchitecture)' == 'x86'">i686-linux-android</_PrebuiltAbi>
<_AotToolPrefix>$(ANDROID_NDK_ROOT)\toolchains\llvm\prebuilt\$(_PrebuiltOS)\bin\$(_PrebuiltAbi)-</_AotToolPrefix>
<_AotMode Condition="'$(AotMode)' == ''">Normal</_AotMode>
</PropertyGroup>
<PropertyGroup Condition="'$(ForceAOT)' == 'true' and '$(AOTWithLibraryFiles)' != 'true'">
<_AotOutputType>AsmOnly</_AotOutputType>
<_AotModulesTablePath>$(ApkDir)\modules.c</_AotModulesTablePath>
<_AotMode Condition="'$(AotMode)' == ''">Full</_AotMode>
</PropertyGroup>
<PropertyGroup>
<AndroidLibraryMinApiLevel Condition="'$(AndroidLibraryMinApiLevel)' == ''">21</AndroidLibraryMinApiLevel>
</PropertyGroup>
<NdkToolFinderTask
Condition="'$(AOTWithLibraryFiles)' == 'true'"
Architecture="$(TargetArchitecture)"
HostOS="$(_HostOS)"
MinApiLevel="$(AndroidLibraryMinApiLevel)">
<Output TaskParameter="AsPrefixPath" PropertyName="_AsPrefixPath" />
<Output TaskParameter="ToolPrefixPath" PropertyName="_ToolPrefixPath" />
<Output TaskParameter="Triple" PropertyName="_Triple" />
<Output TaskParameter="LdName" PropertyName="_LdName" />
<Output TaskParameter="LdPath" PropertyName="_LdPath" />
<Output TaskParameter="ClangPath" PropertyName="_ClangPath" />
</NdkToolFinderTask>
<PropertyGroup Condition="'$(AOTWithLibraryFiles)' == 'true'">
<_AsPrefixPath>$([MSBuild]::EnsureTrailingSlash('$(_AsPrefixPath)'))</_AsPrefixPath>
<_ToolPrefixPath>$([MSBuild]::EnsureTrailingSlash('$(_ToolPrefixPath)'))</_ToolPrefixPath>
</PropertyGroup>
<MonoAOTCompiler Condition="'$(ForceAOT)' == 'true'"
CompilerBinaryPath="@(MonoAotCrossCompiler->WithMetadataValue('RuntimeIdentifier','$(TargetOS)-$(TargetArchitecture.ToLowerInvariant())'))"
OutputDir="$(_MobileIntermediateOutputPath)"
Mode="Full"
OutputType="$(_AotOutputType)"
Assemblies="@(AotInputAssemblies)"
AotModulesTablePath="$(_AotModulesTablePath)"
ToolPrefix="$(_AotToolPrefix)"
LibraryFormat="$(_AotLibraryFormat)"
AsPrefix="$(_AsPrefixPath)"
Assemblies="@(AotInputAssemblies)"
CompilerBinaryPath="@(MonoAotCrossCompiler->WithMetadataValue('RuntimeIdentifier','$(TargetOS)-$(TargetArchitecture.ToLowerInvariant())'))"
IntermediateOutputPath="$(IntermediateOutputPath)"
UseLLVM="$(UseLLVM)"
LLVMPath="$(MonoAotCrossDir)">
LibraryFormat="$(_AotLibraryFormat)"
LLVMPath="$(MonoAotCrossDir)"
Mode="$(_AotMode)"
OutputDir="$(_MobileIntermediateOutputPath)"
OutputType="$(_AotOutputType)"
ToolPrefix="$(_ToolPrefixPath)"
UseAotDataFile="false"
UseLLVM="$(UseLLVM)">
<Output TaskParameter="CompiledAssemblies" ItemName="BundleAssemblies" />
</MonoAOTCompiler>

View file

@ -35,6 +35,5 @@ run:
/p:RunActivity=false \
'/p:RuntimeComponents="$(RUNTIME_COMPONENTS)"' \
'/p:DiagnosticPorts="$(DIAGNOSTIC_PORTS)"'
clean:
rm -rf ../../../../artifacts/bin/AndroidSampleApp

View file

@ -231,6 +231,11 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
/// </summary>
public string? ToolPrefix { get; set; }
/// <summary>
/// Prepends a prefix to the name of the assembler (as) tool ran by the AOT compiler.
/// </summary>
public string? AsPrefix { get; set; }
/// <summary>
/// Path to the directory where msym artifacts are stored.
/// </summary>
@ -723,6 +728,11 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
aotArgs.Add($"tool-prefix={ToolPrefix}");
}
if (!string.IsNullOrEmpty(AsPrefix))
{
aotArgs.Add($"as-prefix={AsPrefix}");
}
string assemblyFilename = Path.GetFileName(assembly);
if (isDedup)
@ -845,7 +855,11 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
ProxyFile proxyFile = _cache.NewFile(llvmObjectFile);
proxyFiles.Add(proxyFile);
aotArgs.Add($"llvm-outfile={proxyFile.TempFile}");
aotAssembly.SetMetadata("LlvmObjectFile", proxyFile.TargetFile);
if (UseStaticLinking)
{
aotAssembly.SetMetadata("LlvmObjectFile", proxyFile.TargetFile);
}
}
}

View file

@ -345,6 +345,15 @@ internal static class Utils
}
#endif
public static bool IsWindows()
{
#if NETCOREAPP
return OperatingSystem.IsWindows();
#else
return true;
#endif
}
public static bool IsManagedAssembly(string filePath)
{
if (!File.Exists(filePath))

View file

@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
namespace Microsoft.Android.Build.Ndk
{
public sealed class AndroidArch(string archName, string abi, string triple)
{
public string ArchName { get; set; } = archName;
public string Abi { get; set; } = abi;
public string Triple { get; set; } = triple;
}
}

View file

@ -0,0 +1,127 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace Microsoft.Android.Build.Ndk
{
public sealed class Ndk
{
private static string ndkPath = "";
private static NdkVersion? ndkVersion;
public static string NdkPath
{
get
{
if (string.IsNullOrEmpty(ndkPath))
{
ndkPath = GetNdkPath(GetProbingPaths());
}
return ndkPath!;
}
}
public static NdkVersion NdkVersion
{
get
{
#pragma warning disable IDE0074 // Use compound assignment
if (ndkVersion == null)
{
ndkVersion = ReadVersion();
}
#pragma warning restore IDE0074
return ndkVersion;
}
}
private static string GetNdkPath(IEnumerable<string> probingPaths)
{
string ret = "";
foreach(string path in probingPaths)
{
if (Directory.Exists(path))
{
ret = path;
break;
}
}
return ret;
}
private static List<string> GetProbingPaths()
{
List<string> paths = new List<string>();
string? ndkEnvPath = Environment.GetEnvironmentVariable("ANDROID_NDK_ROOT");
string[] fixedNdkPaths = (Utils.IsWindows()) ?
new string[]
{
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Android", "android-sdk", "ndk-bundle"),
Path.Combine(Environment.GetFolderPath (Environment.SpecialFolder.ProgramFilesX86), "Android", "android-sdk-windows", "ndk-bundle"),
!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ProgramW6432"))
? Path.Combine(Environment.GetEnvironmentVariable("ProgramW6432") ?? "", "Android", "android-sdk", "ndk-bundle")
: Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Android", "android-sdk", "ndk-bundle"),
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Android", "android-sdk", "ndk-bundle"),
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Android", "android-sdk", "ndk-bundle"),
@"C:\android-sdk-windows"
}
:
new string[]
{
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Android", "sdk")
};
if (!string.IsNullOrEmpty(ndkEnvPath))
{
paths.Add(ndkEnvPath!);
}
paths.AddRange(fixedNdkPaths);
return paths;
}
private static NdkVersion ReadVersion()
{
string sourcePropertiesPath = Path.Combine(NdkPath, "source.properties");
if (!File.Exists(sourcePropertiesPath))
{
throw new Exception("Could not find NDK version information");
}
var splitChars = new char[] {'='};
string? ver = null;
foreach(string l in File.ReadAllLines(sourcePropertiesPath))
{
string line = l.Trim ();
if (!line.StartsWith("Pkg.Revision", StringComparison.Ordinal))
{
continue;
}
string[] parts = line.Split(splitChars, 2);
if (parts.Length != 2)
{
throw new Exception($"Invalid NDK version format in '{sourcePropertiesPath}'");
}
ver = parts [1].Trim();
}
return new NdkVersion(ver);
}
}
}

View file

@ -0,0 +1,117 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Microsoft.Android.Build.Ndk
{
public sealed class NdkTools
{
private string toolRootPath;
private string toolPrefixPath;
private string asPrefixPath;
private string clangPath;
private string ldName;
private string ldPath;
private string netArch;
private string hostOS;
private string apiLevel;
private static readonly Dictionary<string, string> validHosts = new Dictionary<string, string>()
{
{ "osx", "darwin-x86_64" },
{ "linux", "linux-x86_64" },
{ "windows", "windows-x86_64" }
};
private static readonly Dictionary<string, AndroidArch> validArches = new Dictionary<string, AndroidArch>()
{
{ "arm", new AndroidArch("arm", "armeabi-v7a", "arm-linux-androideabi") },
{ "arm64", new AndroidArch("aarch64", "aarch64-v8a", "aarch64-linux-android") },
{ "x86", new AndroidArch("x86", "x86", "i686-linux-android") },
{ "x64", new AndroidArch("x86_64", "x86_64", "x86_64-linux-android") }
};
public NdkTools(string netArch, string hostOS, string apiLevel)
{
string cmdExt = Utils.IsWindows() ? ".cmd" : "";
this.netArch = netArch;
this.apiLevel = apiLevel;
ValidateRequiredProps(hostOS);
this.hostOS = validHosts[hostOS];
toolRootPath = Path.Combine(Ndk.NdkPath, "toolchains", "llvm", "prebuilt", this.hostOS);
asPrefixPath = Path.Combine(toolRootPath, Triple, "bin");
toolPrefixPath = Path.Combine(toolRootPath, "bin");
clangPath = Path.Combine(ToolPrefixPath, $"{Triple}{apiLevel}-clang{cmdExt}");
ldPath = toolPrefixPath;
ldName = "ld";
}
public string ToolPrefixPath
{
get => toolPrefixPath;
}
public string AsPrefixPath
{
get => asPrefixPath;
}
public string Triple
{
get => validArches[netArch].Triple;
}
public string LdName
{
get => ldName;
}
public string LdPath
{
get => ldPath;
}
public string ClangPath
{
get => clangPath;
}
private void ValidateRequiredProps(string hostOS)
{
if (Ndk.NdkVersion.Main.Major != 23)
{
throw new Exception($"NDK 23 is required. An unsupported NDK version was found ({Ndk.NdkVersion.Main.Major}).");
}
try
{
string triple = Triple;
}
catch (KeyNotFoundException)
{
throw new Exception("An invalid target architecture was supplied. Only arm64, x64, arm, and x86 are supported.");
}
try
{
string host = validHosts[hostOS];
}
catch(KeyNotFoundException)
{
throw new Exception("An invalid HostOS value was supplied. Only windows, osx, and linux are supported.");
}
}
}
}

View file

@ -0,0 +1,48 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
namespace Microsoft.Android.Build.Ndk
{
public class NdkVersion
{
public Version Main { get; }
public string Tag { get; } = "";
public NdkVersion() => Main = new Version(0, 0);
public NdkVersion(string? version)
{
string? ver = version?.Trim();
if (string.IsNullOrEmpty(ver))
{
throw new ArgumentException ("must be a non-empty string", nameof (version));
}
int tagIdx = ver.IndexOf('-');
if (tagIdx >= 0)
{
Tag = ver.Substring(tagIdx + 1);
ver = ver.Substring(0, tagIdx - 1);
}
if (!Version.TryParse(ver, out Version? ndkVersion) || ndkVersion == null)
{
throw new InvalidOperationException ($"Failed to parse '{ver}' as a valid NDK version.");
}
Main = ndkVersion;
}
public override string ToString()
{
if (!string.IsNullOrEmpty(Tag))
{
return $"{Main}-{Tag}";
}
return Main.ToString();
}
}
}

View file

@ -0,0 +1,87 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text;
using Microsoft.Android.Build.Ndk;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace Microsoft.Android.Build.Tasks
{
public class NdkToolFinderTask : Task
{
/// <summary>
/// The dotnet specific target android architecture
/// </summary>
[Required]
[NotNull]
public string? Architecture { get; set; }
/// <summary>
/// The dotnet specific host OS being used (windows, linux, osx)
/// </summary>
[Required]
[NotNull]
public string? HostOS { get; set; }
/// <summary>
/// The minimum API level supported. This is important when using clang
/// </summary>
[Required]
[NotNull]
public string? MinApiLevel { get; set; }
/// <summary>
/// The path to the folder that contains the android native assembler (as).
/// May not be supported in newer NDK versions.
/// </summary>
[Output]
public string? AsPrefixPath { get; set; } = ""!;
/// <summary>
/// The path to the api level specific clang being used
/// </summary>
[Output]
public string? ClangPath { get; set; } = ""!;
/// <summary>
/// The name of the linker being used.
/// </summary>
[Output]
public string? LdName { get; set; } = ""!;
/// <summary>
/// The path to the linker being used
/// </summary>
[Output]
public string? LdPath { get; set; } = ""!;
/// <summary>
/// The path to the NDK toolchain bin folder
/// </summary>
[Output]
public string? ToolPrefixPath { get; set; } = ""!;
/// <summary>
/// The LLVM triple for the android target.
[Output]
public string? Triple { get; set; } = ""!;
public override bool Execute()
{
NdkTools tools = new NdkTools(Architecture, HostOS, MinApiLevel);
AsPrefixPath = tools.AsPrefixPath;
ToolPrefixPath = tools.ToolPrefixPath;
Triple = tools.Triple;
LdName = tools.LdName;
LdPath = tools.LdPath;
ClangPath = tools.ClangPath;
return true;
}
}
}

View file

@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(TargetFrameworkForNETCoreTasks);$(TargetFrameworkForNETFrameworkTasks)</TargetFrameworks>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn),CA1050</NoWarn>
<!-- Ignore nullable warnings on net4* -->
<NoWarn Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETFramework'">$(NoWarn),CS8604,CS8602</NoWarn>
<NoWarn Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) != '.NETFramework'">$(NoWarn),CA1850</NoWarn>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">
<Compile Include="..\Common\IsExternalInit.cs" />
<Compile Include="$(RepoRoot)src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Utils.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="$(MicrosoftBuildVersion)" />
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="$(MicrosoftBuildTasksCoreVersion)" />
</ItemGroup>
<Target Name="GetFilesToPackage" Returns="@(FilesToPackage)">
<ItemGroup>
<!-- non-net4* -->
<FilesToPackage Include="$(OutputPath)$(TargetFrameworkForNETCoreTasks)\$(MSBuildProjectName)*"
TargetPath="tasks\$(TargetFrameworkForNETCoreTasks)" />
<!-- for net472 we need all the dependent assemblies too, so copy from the publish folder -->
<FilesToPackage Include="$(OutputPath)$(TargetFrameworkForNETFrameworkTasks)\*"
TargetPath="tasks\$(TargetFrameworkForNETFrameworkTasks)" />
</ItemGroup>
</Target>
</Project>

View file

@ -3,6 +3,7 @@
<OutputType>Exe</OutputType>
<MonoForceInterpreter>false</MonoForceInterpreter>
<RunAOTCompilation>true</RunAOTCompilation>
<AOTWithLibraryFiles>true</AOTWithLibraryFiles>
<TestRuntime>true</TestRuntime>
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
<MainLibraryFileName>Android.Device_Emulator.Aot_Llvm.Test.dll</MainLibraryFileName>