You're breathtaking!
This commit is contained in:
68
Source/Tools/Flax.Build/Platforms/Android/AndroidNdk.cs
Normal file
68
Source/Tools/Flax.Build/Platforms/Android/AndroidNdk.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Flax.Build.Platforms
|
||||
{
|
||||
/// <summary>
|
||||
/// The Android NDK.
|
||||
/// </summary>
|
||||
/// <seealso cref="Sdk" />
|
||||
public sealed class AndroidNdk : Sdk
|
||||
{
|
||||
/// <summary>
|
||||
/// The singleton instance.
|
||||
/// </summary>
|
||||
public static readonly AndroidNdk Instance = new AndroidNdk();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override TargetPlatform[] Platforms => new []
|
||||
{
|
||||
TargetPlatform.Windows,
|
||||
TargetPlatform.Linux,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AndroidNdk"/> class.
|
||||
/// </summary>
|
||||
public AndroidNdk()
|
||||
{
|
||||
if (!Platforms.Contains(Platform.BuildTargetPlatform))
|
||||
return;
|
||||
|
||||
// Find Android NDK folder path
|
||||
var sdkPath = Environment.GetEnvironmentVariable("ANDROID_NDK");
|
||||
if (string.IsNullOrEmpty(sdkPath))
|
||||
{
|
||||
// Look for ndk installed side-by-side with an sdk
|
||||
if (AndroidSdk.Instance.IsValid)
|
||||
{
|
||||
var subdirs = Directory.GetDirectories(Path.Combine(AndroidSdk.Instance.RootPath, "ndk"));
|
||||
if (subdirs.Length != 0)
|
||||
{
|
||||
Array.Sort(subdirs, (a, b) => Version.Parse(Path.GetFileName(a)).CompareTo(Version.Parse(Path.GetFileName(b))));
|
||||
sdkPath = subdirs.Last();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!Directory.Exists(sdkPath))
|
||||
{
|
||||
Log.Warning(string.Format("Specified Android NDK folder in ANDROID_NDK env variable doesn't exist ({0})", sdkPath));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(sdkPath))
|
||||
{
|
||||
var lines = File.ReadAllLines(Path.Combine(sdkPath, "source.properties"));
|
||||
if (lines.Length > 1)
|
||||
{
|
||||
RootPath = sdkPath;
|
||||
var ver = lines[1].Substring(lines[1].IndexOf(" = ", StringComparison.Ordinal) + 2);
|
||||
Version = Version.Parse(ver);
|
||||
IsValid = true;
|
||||
Log.Info(string.Format("Found Android NDK {1} at {0}", RootPath, Version));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
46
Source/Tools/Flax.Build/Platforms/Android/AndroidPlatform.cs
Normal file
46
Source/Tools/Flax.Build/Platforms/Android/AndroidPlatform.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Flax.Build.Platforms
|
||||
{
|
||||
/// <summary>
|
||||
/// The Android build platform implementation.
|
||||
/// </summary>
|
||||
/// <seealso cref="Platform" />
|
||||
/// <seealso cref="UnixPlatform" />
|
||||
public class AndroidPlatform : UnixPlatform
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override TargetPlatform Target => TargetPlatform.Android;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool HasRequiredSDKsInstalled { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool HasSharedLibrarySupport => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ExecutableFileExtension => ".so";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string BinaryFilePrefix => "lib";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AndroidPlatform"/> class.
|
||||
/// </summary>
|
||||
public AndroidPlatform()
|
||||
{
|
||||
HasRequiredSDKsInstalled = AndroidSdk.Instance.IsValid && AndroidNdk.Instance.IsValid;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Toolchain CreateToolchain(TargetArchitecture architecture)
|
||||
{
|
||||
var ndk = AndroidNdk.Instance.RootPath;
|
||||
var toolchainRoot = Path.Combine(ndk, "toolchains", "llvm", "prebuilt", AndroidSdk.GetHostName());
|
||||
return new AndroidToolchain(this, architecture, toolchainRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
110
Source/Tools/Flax.Build/Platforms/Android/AndroidSdk.cs
Normal file
110
Source/Tools/Flax.Build/Platforms/Android/AndroidSdk.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Flax.Build.Platforms
|
||||
{
|
||||
/// <summary>
|
||||
/// The Android SDK.
|
||||
/// </summary>
|
||||
/// <seealso cref="Sdk" />
|
||||
public sealed class AndroidSdk : Sdk
|
||||
{
|
||||
/// <summary>
|
||||
/// The singleton instance.
|
||||
/// </summary>
|
||||
public static readonly AndroidSdk Instance = new AndroidSdk();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override TargetPlatform[] Platforms => new []
|
||||
{
|
||||
TargetPlatform.Windows,
|
||||
TargetPlatform.Linux,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AndroidSdk"/> class.
|
||||
/// </summary>
|
||||
public AndroidSdk()
|
||||
{
|
||||
if (!Platforms.Contains(Platform.BuildTargetPlatform))
|
||||
return;
|
||||
|
||||
// Find Android SDK folder path
|
||||
var sdkPath = Environment.GetEnvironmentVariable("ANDROID_SDK");
|
||||
if (string.IsNullOrEmpty(sdkPath))
|
||||
{
|
||||
// Look for adb in Android folders of some common locations
|
||||
string uniqueFile = Path.Combine("platform-tools", "adb.exe");
|
||||
string[] searchDirs =
|
||||
{
|
||||
// <user>/AppData/Local
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||
// Program Files
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
|
||||
// Program Files (x86)
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + " (x86)",
|
||||
// <user>/AppData/Roaming
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
};
|
||||
sdkPath = null;
|
||||
foreach (string searchDir in searchDirs)
|
||||
{
|
||||
string androidDir = Path.Combine(searchDir, "Android");
|
||||
if (Directory.Exists(androidDir))
|
||||
{
|
||||
string[] subDirs = Directory.GetDirectories(androidDir, "*sdk*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string subDir in subDirs)
|
||||
{
|
||||
string path = Path.Combine(subDir, uniqueFile);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
sdkPath = subDir;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sdkPath != null)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!Directory.Exists(sdkPath))
|
||||
{
|
||||
Log.Warning(string.Format("Specified Android SDK folder in ANDROID_SDK env variable doesn't exist ({0})", sdkPath));
|
||||
}
|
||||
if (string.IsNullOrEmpty(sdkPath))
|
||||
{
|
||||
Log.Warning("Missing Android SDK. Cannot build for Android platform.");
|
||||
}
|
||||
else
|
||||
{
|
||||
RootPath = sdkPath;
|
||||
Version = new Version(1, 0);
|
||||
IsValid = true;
|
||||
Log.Info(string.Format("Found Android SDK at {0}", RootPath));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the host platform used in Android SDK toolset.
|
||||
/// </summary>
|
||||
/// <returns>The name.</returns>
|
||||
public static string GetHostName()
|
||||
{
|
||||
string hostName;
|
||||
switch (Platform.BuildPlatform.Target)
|
||||
{
|
||||
case TargetPlatform.Windows:
|
||||
hostName = Environment.Is64BitOperatingSystem ? "windows-x86_64" : "windows";
|
||||
break;
|
||||
case TargetPlatform.Linux:
|
||||
hostName = "linux-x86_64";
|
||||
break;
|
||||
default: throw new InvalidPlatformException(Platform.BuildPlatform.Target);
|
||||
}
|
||||
return hostName;
|
||||
}
|
||||
}
|
||||
}
|
||||
198
Source/Tools/Flax.Build/Platforms/Android/AndroidToolchain.cs
Normal file
198
Source/Tools/Flax.Build/Platforms/Android/AndroidToolchain.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Flax.Build.Graph;
|
||||
using Flax.Build.NativeCpp;
|
||||
|
||||
namespace Flax.Build
|
||||
{
|
||||
partial class Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the Android API level to use (eg. 24).
|
||||
/// </summary>
|
||||
[CommandLine("androidPlatformApi", "<version>", "Specifies the Android API level to use (eg. 24).")]
|
||||
public static int AndroidPlatformApi = 24;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Flax.Build.Platforms
|
||||
{
|
||||
/// <summary>
|
||||
/// The Android build toolchain implementation.
|
||||
/// </summary>
|
||||
/// <seealso cref="Platform" />
|
||||
/// <seealso cref="UnixToolchain" />
|
||||
public class AndroidToolchain : UnixToolchain
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AndroidToolchain"/> class.
|
||||
/// </summary>
|
||||
/// <param name="platform">The platform.</param>
|
||||
/// <param name="architecture">The target architecture.</param>
|
||||
/// <param name="toolchainRoot">The toolchain root path.</param>
|
||||
public AndroidToolchain(AndroidPlatform platform, TargetArchitecture architecture, string toolchainRoot)
|
||||
: base(platform, architecture, toolchainRoot, false, string.Empty)
|
||||
{
|
||||
var toolchain = ToolsetRoot.Replace('\\', '/');
|
||||
SystemIncludePaths.Add(Path.Combine(toolchain, "sources/usr/include/c++/v1").Replace('\\', '/'));
|
||||
SystemIncludePaths.Add(Path.Combine(toolchain, "sysroot/usr/include").Replace('\\', '/'));
|
||||
SystemIncludePaths.Add(Path.Combine(toolchain, "sysroot/usr/local/include").Replace('\\', '/'));
|
||||
SystemIncludePaths.Add(Path.Combine(toolchain, "lib64/clang/9.0.8/include").Replace('\\', '/'));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Android ABI name for a given processor architecture.
|
||||
/// </summary>
|
||||
/// <param name="architecture">The architecture.</param>
|
||||
/// <returns>The Android ABI name.</returns>
|
||||
public static string GetAbiName(TargetArchitecture architecture)
|
||||
{
|
||||
switch (architecture)
|
||||
{
|
||||
case TargetArchitecture.x86: return "x86";
|
||||
case TargetArchitecture.x64: return "x86_64";
|
||||
case TargetArchitecture.ARM: return "armeabi-v7a";
|
||||
case TargetArchitecture.ARM64: return "arm64-v8a";
|
||||
default: throw new InvalidArchitectureException(architecture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void SetupEnvironment(BuildOptions options)
|
||||
{
|
||||
base.SetupEnvironment(options);
|
||||
|
||||
options.CompileEnv.PreprocessorDefinitions.Add("PLATFORM_ANDROID");
|
||||
options.CompileEnv.PreprocessorDefinitions.Add(string.Format("__ANDROID_API__={0}", Configuration.AndroidPlatformApi));
|
||||
|
||||
options.LinkEnv.InputLibraries.Add("c");
|
||||
options.LinkEnv.InputLibraries.Add("z");
|
||||
options.LinkEnv.InputLibraries.Add("log");
|
||||
options.LinkEnv.InputLibraries.Add("android");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void SetupCompileCppFilesArgs(TaskGraph graph, BuildOptions options, List<string> args, string outputPath)
|
||||
{
|
||||
base.SetupCompileCppFilesArgs(graph, options, args, outputPath);
|
||||
|
||||
var toolchain = ToolsetRoot.Replace('\\', '/');
|
||||
args.Add(string.Format("--target={0}", ArchitectureName));
|
||||
args.Add(string.Format("--gcc-toolchain=\"{0}\"", toolchain));
|
||||
args.Add(string.Format("--sysroot=\"{0}/sysroot\"", toolchain));
|
||||
|
||||
args.Add("-fpic");
|
||||
args.Add("-funwind-tables");
|
||||
args.Add("-no-canonical-prefixes");
|
||||
if (options.Configuration != TargetConfiguration.Release)
|
||||
{
|
||||
args.Add("-fstack-protector-strong");
|
||||
args.Add("-D_FORTIFY_SOURCE=2");
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Add("-D_FORTIFY_SOURCE=1");
|
||||
}
|
||||
if (options.CompileEnv.DebugInformation)
|
||||
{
|
||||
args.Add("-g2 -gdwarf-4");
|
||||
args.Add("-fno-omit-frame-pointer");
|
||||
args.Add("-fno-function-sections");
|
||||
}
|
||||
|
||||
switch (Architecture)
|
||||
{
|
||||
case TargetArchitecture.x86:
|
||||
args.Add("-march=atom");
|
||||
if (Configuration.AndroidPlatformApi < 24)
|
||||
args.Add("-mstackrealign");
|
||||
break;
|
||||
case TargetArchitecture.x64:
|
||||
args.Add("-march=atom");
|
||||
break;
|
||||
case TargetArchitecture.ARM:
|
||||
args.Add("-march=armv7-a");
|
||||
args.Add("-mfloat-abi=softfp");
|
||||
args.Add("-mfpu=vfpv3-d16");
|
||||
break;
|
||||
case TargetArchitecture.ARM64:
|
||||
args.Add("-march=armv8-a");
|
||||
break;
|
||||
default: throw new InvalidArchitectureException(Architecture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void SetupLinkFilesArgs(TaskGraph graph, BuildOptions options, List<string> args, string outputFilePath)
|
||||
{
|
||||
base.SetupLinkFilesArgs(graph, options, args, outputFilePath);
|
||||
|
||||
args.Add("-shared");
|
||||
args.Add("-no-canonical-prefixes");
|
||||
args.Add("-Wl,-Bsymbolic");
|
||||
args.Add("-Wl,--build-id=sha1");
|
||||
args.Add("-Wl,-gc-sections");
|
||||
|
||||
if (options.LinkEnv.Output == LinkerOutput.Executable)
|
||||
{
|
||||
args.Add("-u ANativeActivity_onCreate");
|
||||
}
|
||||
|
||||
string target;
|
||||
switch (Architecture)
|
||||
{
|
||||
case TargetArchitecture.x86:
|
||||
target = "i686-none-linux-android";
|
||||
break;
|
||||
case TargetArchitecture.x64:
|
||||
target = "x86_64-none-linux-android";
|
||||
break;
|
||||
case TargetArchitecture.ARM:
|
||||
target = "armv7-none-linux-androideabi";
|
||||
break;
|
||||
case TargetArchitecture.ARM64:
|
||||
target = "aarch64-none-linux-android";
|
||||
break;
|
||||
default: throw new InvalidArchitectureException(Architecture);
|
||||
}
|
||||
|
||||
var toolchain = ToolsetRoot.Replace('\\', '/');
|
||||
args.Add(string.Format("--sysroot=\"{0}/sysroot\"", toolchain));
|
||||
args.Add(string.Format("--gcc-toolchain=\"{0}\"", toolchain));
|
||||
args.Add("--target=" + target + Configuration.AndroidPlatformApi);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void SetupArchiveFilesArgs(TaskGraph graph, BuildOptions options, List<string> args, string outputFilePath)
|
||||
{
|
||||
// Remove -o from the output file specifier
|
||||
args[1] = string.Format("\"{0}\"", outputFilePath);
|
||||
|
||||
base.SetupArchiveFilesArgs(graph, options, args, outputFilePath);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Task CreateArchive(TaskGraph graph, BuildOptions options, string outputFilePath)
|
||||
{
|
||||
var task = base.CreateArchive(graph, options, outputFilePath);
|
||||
task.CommandPath = LlvmArPath;
|
||||
return task;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Task CreateBinary(TaskGraph graph, BuildOptions options, string outputFilePath)
|
||||
{
|
||||
// Bundle STL library for the executable files for runtime
|
||||
if (options.LinkEnv.Output == LinkerOutput.Executable)
|
||||
{
|
||||
graph.AddCopyFile(Path.Combine(Path.GetDirectoryName(outputFilePath), "libc++_shared.so"), Path.Combine(AndroidNdk.Instance.RootPath, "sources/cxx-stl/llvm-libc++/libs/", GetAbiName(Architecture), "libc++_shared.so"));
|
||||
}
|
||||
|
||||
var task = base.CreateBinary(graph, options, outputFilePath);
|
||||
task.CommandPath = ClangPath;
|
||||
return task;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user