diff --git a/lib/std/core/env.c3 b/lib/std/core/env.c3
index 09b0b61b5..337d1812a 100644
--- a/lib/std/core/env.c3
+++ b/lib/std/core/env.c3
@@ -57,6 +57,7 @@ enum OsType
HURD,
WASI,
EMSCRIPTEN,
+ ANDROID,
}
enum ArchType
@@ -150,6 +151,7 @@ const bool FREEBSD = LIBC && OS_TYPE == FREEBSD;
const bool NETBSD = LIBC && OS_TYPE == NETBSD;
const bool BSD_FAMILY = env::FREEBSD || env::OPENBSD || env::NETBSD;
const bool WASI = LIBC && OS_TYPE == WASI;
+const bool ANDROID = LIBC && OS_TYPE == ANDROID;
const bool WASM_NOLIBC @builtin = !LIBC && ARCH_TYPE == ArchType.WASM32 || ARCH_TYPE == ArchType.WASM64;
const bool ADDRESS_SANITIZER = $$ADDRESS_SANITIZER;
const bool MEMORY_SANITIZER = $$MEMORY_SANITIZER;
@@ -182,6 +184,7 @@ macro bool os_is_posix() @const
$case SOLARIS:
$case TVOS:
$case WATCHOS:
+ $case ANDROID:
return true;
$case WIN32:
$case WASI:
diff --git a/lib/std/libc/libc.c3 b/lib/std/libc/libc.c3
index 0cf6af10b..6c0349070 100644
--- a/lib/std/libc/libc.c3
+++ b/lib/std/libc/libc.c3
@@ -203,7 +203,7 @@ const CInt STDIN_FD = 0;
const CInt STDOUT_FD = 1;
const CInt STDERR_FD = 2;
-module libc @if(env::LINUX);
+module libc @if(env::LINUX || env::ANDROID);
extern CFile __stdin @extern("stdin");
extern CFile __stdout @extern("stdout");
extern CFile __stderr @extern("stderr");
@@ -246,7 +246,7 @@ macro CFile stdin() => __acrt_iob_func(STDIN_FD);
macro CFile stdout() => __acrt_iob_func(STDOUT_FD);
macro CFile stderr() => __acrt_iob_func(STDERR_FD);
-module libc @if(env::LIBC && !env::WIN32 && !env::LINUX && !env::DARWIN && !env::BSD_FAMILY);
+module libc @if(env::LIBC && !env::WIN32 && !env::LINUX && !env::ANDROID && !env::DARWIN && !env::BSD_FAMILY);
macro CFile stdin() { return (CFile*)(uptr)STDIN_FD; }
macro CFile stdout() { return (CFile*)(uptr)STDOUT_FD; }
macro CFile stderr() { return (CFile*)(uptr)STDERR_FD; }
diff --git a/lib/std/libc/os/android.c3 b/lib/std/libc/os/android.c3
new file mode 100644
index 000000000..54f325c61
--- /dev/null
+++ b/lib/std/libc/os/android.c3
@@ -0,0 +1,62 @@
+module libc @if(env::ANDROID);
+
+// Checked for x86_64, this is notoriously incorrect when comparing with Rust code etc
+
+def Blksize_t = $typefrom(env::X86_64 ? long.typeid : CInt.typeid);
+def Nlink_t = $typefrom(env::X86_64 ? ulong.typeid : CUInt.typeid);
+def Blkcnt_t = long;
+def Ino_t = ulong;
+def Dev_t = ulong;
+def Mode_t = uint;
+def Ino64_t = ulong;
+def Blkcnt64_t = long;
+
+struct Stat @if(env::X86_64)
+{
+ Dev_t st_dev;
+ Ino_t st_ino;
+ Nlink_t st_nlink;
+ Mode_t st_mode;
+ Uid_t st_uid;
+ Gid_t st_gid;
+ CInt __pad0;
+ Dev_t st_rdev;
+ Off_t st_size;
+ Blksize_t st_blksize;
+ Blkcnt_t st_blocks;
+ Time_t st_atime;
+ long st_atime_nsec;
+ Time_t st_mtime;
+ long st_mtime_nsec;
+ Time_t st_ctime;
+ long st_ctime_nsec;
+ long[3] __unused;
+}
+
+struct Stat @if(!env::X86_64)
+{
+ Dev_t st_dev;
+ Ino_t st_ino;
+ Mode_t st_mode;
+ Nlink_t st_nlink;
+ Uid_t st_uid;
+ Gid_t st_gid;
+ Dev_t st_rdev;
+ CInt __pad1;
+ Off_t st_size;
+ Blksize_t st_blksize;
+ CInt __pad2;
+ Blkcnt_t st_blocks;
+ Time_t st_atime;
+ long st_atime_nsec;
+ Time_t st_mtime;
+ long st_mtime_nsec;
+ Time_t st_ctime;
+ long st_ctime_nsec;
+ CInt[2] __unused;
+}
+
+extern fn CInt stat(ZString path, Stat* stat);
+
+extern fn CInt get_nprocs();
+extern fn CInt get_nprocs_conf();
diff --git a/lib/std/libc/os/errno.c3 b/lib/std/libc/os/errno.c3
index 66679fb01..c5db365f9 100644
--- a/lib/std/libc/os/errno.c3
+++ b/lib/std/libc/os/errno.c3
@@ -25,4 +25,4 @@ extern fn void _set_errno(int err) @if(env::WIN32);
const ERRNO_DEFAULT @local = !env::LINUX && !env::DARWIN && !env::WIN32;
tlocal int _errno_c3 @if(ERRNO_DEFAULT) = 0;
fn void errno_set(int err) @if(ERRNO_DEFAULT) => _errno_c3 = err;
-fn int errno() @if(ERRNO_DEFAULT) => _errno_c3;
\ No newline at end of file
+fn int errno() @if(ERRNO_DEFAULT) => _errno_c3;
diff --git a/lib/std/time/os/time_posix.c3 b/lib/std/time/os/time_posix.c3
index c8431de31..46b369225 100644
--- a/lib/std/time/os/time_posix.c3
+++ b/lib/std/time/os/time_posix.c3
@@ -67,7 +67,7 @@ const CLOCK_UPTIME_RAW_APPROX = 9;
const CLOCK_PROCESS_CPUTIME_ID = 12;
const CLOCK_THREAD_CPUTIME_ID = 16;
-module std::time::os @if(env::LINUX);
+module std::time::os @if(env::LINUX || env::ANDROID);
const CLOCK_REALTIME = 0;
const CLOCK_MONOTONIC = 1;
const CLOCK_PROCESS_CPUTIME_ID = 2;
diff --git a/src/build/build.h b/src/build/build.h
index 7ff1fb33c..e7994a215 100644
--- a/src/build/build.h
+++ b/src/build/build.h
@@ -344,6 +344,7 @@ typedef enum
{
ARCH_OS_TARGET_DEFAULT = -1,
ANDROID_AARCH64 = 0,
+ ANDROID_X86_64,
ELF_AARCH64,
ELF_RISCV32,
ELF_RISCV64,
@@ -475,6 +476,11 @@ typedef struct BuildOptions_
const char *crt;
const char *crtbegin;
} linuxpaths;
+ struct
+ {
+ const char *ndk_path;
+ int api_version;
+ } android;
int build_threads;
const char **libraries_to_fetch;
const char **files;
@@ -742,6 +748,11 @@ typedef struct
const char *crt;
const char *crtbegin;
} linuxpaths;
+ struct
+ {
+ const char *ndk_path;
+ int api_version;
+ } android;
} BuildTarget;
static const char *x86_cpu_set[8] = {
diff --git a/src/build/build_options.c b/src/build/build_options.c
index 0bea7e55b..e0e4b4dce 100644
--- a/src/build/build_options.c
+++ b/src/build/build_options.c
@@ -197,6 +197,9 @@ static void usage(bool full)
print_opt("--linux-crt
", "Set the directory to use for finding crt1.o and related files.");
print_opt("--linux-crtbegin ", "Set the directory to use for finding crtbegin.o and related files.");
PRINTF("");
+ print_opt("--android-ndk ", "Set the NDK directory location.");
+ print_opt("--android-api ", "Set Android API version.");
+ PRINTF("");
print_opt("--sanitize=", "Enable sanitizer: address, memory, thread.");
}
if (!full)
@@ -984,7 +987,7 @@ static void parse_option(BuildOptions *options)
PRINTF("Available targets:");
EOUTPUT("Invalid target %s.", target);
EOUTPUT("These targets are supported:");
- for (unsigned i = 1; i <= ARCH_OS_TARGET_LAST; i++)
+ for (unsigned i = 0; i <= ARCH_OS_TARGET_LAST; i++)
{
EOUTPUT(" %s", arch_os_target[i]);
}
@@ -1229,6 +1232,18 @@ static void parse_option(BuildOptions *options)
options->linuxpaths.crtbegin = check_dir(next_arg());
return;
}
+ if (match_longopt("android-ndk"))
+ {
+ if (at_end() || next_is_opt()) error_exit("error: android-ndk needs a directory.");
+ options->android.ndk_path = check_dir(next_arg());
+ return;
+ }
+ if (match_longopt("android-api"))
+ {
+ if (at_end() || next_is_opt()) error_exit("error: android-api needs a version.");
+ options->android.api_version = atoi(next_arg());
+ return;
+ }
if (match_longopt("benchmarking"))
{
options->benchmarking = true;
@@ -1358,13 +1373,29 @@ BuildOptions parse_arguments(int argc, const char *argv[])
{
FAIL_WITH_ERR("Missing a compiler command such as 'compile' or 'build'.");
}
+ if (build_options.arch_os_target_override == ANDROID_AARCH64)
+ {
+ if (!build_options.android.ndk_path)
+ {
+ const char *ndk_path = getenv("ANDROID_NDK");
+ if (!ndk_path)
+ {
+ FAIL_WITH_ERR("Can't find Android NDK, please set --ndk-path.");
+ }
+ build_options.android.ndk_path = strdup(ndk_path);
+ }
+ if (build_options.android.api_version <= 0)
+ {
+ build_options.android.api_version = 30; // 30 = Android 11
+ }
+ }
debug_log = build_options.verbosity_level > 2;
return build_options;
}
ArchOsTarget arch_os_target_from_string(const char *target)
{
- for (unsigned i = 1; i <= ARCH_OS_TARGET_LAST; i++)
+ for (unsigned i = 0; i <= ARCH_OS_TARGET_LAST; i++)
{
if (strcmp(arch_os_target[i], target) == 0)
{
@@ -1505,7 +1536,7 @@ static void update_feature_flags(const char ***flags, const char ***removed_flag
static void print_all_targets(void)
{
PRINTF("Available targets:");
- for (unsigned i = 1; i <= ARCH_OS_TARGET_LAST; i++)
+ for (unsigned i = 0; i <= ARCH_OS_TARGET_LAST; i++)
{
PRINTF(" %s", arch_os_target[i]);
}
@@ -1534,6 +1565,7 @@ static int parse_option_select(const char *start, unsigned count, const char **e
const char *arch_os_target[ARCH_OS_TARGET_LAST + 1] = {
[ANDROID_AARCH64] = "android-aarch64",
+ [ANDROID_X86_64] = "android-x86_64",
[ELF_AARCH64] = "elf-aarch64",
[ELF_RISCV32] = "elf-riscv32",
[ELF_RISCV64] = "elf-riscv64",
diff --git a/src/build/builder.c b/src/build/builder.c
index 2af44ce3e..cb5199943 100644
--- a/src/build/builder.c
+++ b/src/build/builder.c
@@ -230,6 +230,7 @@ static LinkLibc libc_from_arch_os(ArchOsTarget target)
switch (target)
{
case ANDROID_AARCH64:
+ case ANDROID_X86_64:
case FREEBSD_X86:
case FREEBSD_X64:
case IOS_AARCH64:
@@ -412,7 +413,8 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
OVERRIDE_IF_SET(macos.sdk_version);
OVERRIDE_IF_SET(linuxpaths.crt);
OVERRIDE_IF_SET(linuxpaths.crtbegin);
-
+ OVERRIDE_IF_SET(android.ndk_path);
+ OVERRIDE_IF_SET(android.api_version);
if (options->silence_deprecation || options->verbosity_level < 0) target->silence_deprecation = options->silence_deprecation || options->verbosity_level < 0;
target->print_linking = options->print_linking || options->verbosity_level > 1;
diff --git a/src/build/project_creation.c b/src/build/project_creation.c
index e0c633e8c..52d938a3f 100644
--- a/src/build/project_creation.c
+++ b/src/build/project_creation.c
@@ -170,6 +170,7 @@ const char* MAIN_INTERFACE_TEMPLATE =
"// extern fn int some_library_function();\n";
const char* DEFAULT_TARGETS[] = {
+ "android-aarch64",
"freebsd-x64",
"linux-aarch64",
"linux-riscv32",
diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c
index 950cc8734..3326a6b31 100644
--- a/src/compiler/compiler.c
+++ b/src/compiler/compiler.c
@@ -1098,6 +1098,7 @@ static int jump_buffer_size()
return 32;
case ELF_X64:
case LINUX_X64:
+ case ANDROID_X86_64:
// Godbolt test
return 25;
case FREEBSD_X64:
diff --git a/src/compiler/enums.h b/src/compiler/enums.h
index cfe44edd8..b118ba036 100644
--- a/src/compiler/enums.h
+++ b/src/compiler/enums.h
@@ -941,7 +941,8 @@ typedef enum
OS_TYPE_HURD,
OS_TYPE_WASI,
OS_TYPE_EMSCRIPTEN,
- OS_TYPE_LAST = OS_TYPE_EMSCRIPTEN
+ OS_TYPE_ANDROID,
+ OS_TYPE_LAST = OS_TYPE_ANDROID
} OsType;
@@ -1647,5 +1648,3 @@ case TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: case TYPE_U128
case EXPR_CATCH_UNRESOLVED: case EXPR_UNRESOLVED_IDENTIFIER: case EXPR_CAST: \
case EXPR_TYPEID: case EXPR_EMBED: case EXPR_VASPLAT: case EXPR_OTHER_CONTEXT: \
case EXPR_GENERIC_IDENT: case EXPR_COMPOUND_LITERAL: case EXPR_MACRO_BODY: case EXPR_CT_SUBSCRIPT
-
-
diff --git a/src/compiler/linker.c b/src/compiler/linker.c
index a65b64bdd..f7c79c662 100644
--- a/src/compiler/linker.c
+++ b/src/compiler/linker.c
@@ -443,6 +443,71 @@ static void linker_setup_linux(const char ***args_ref, Linker linker_type, bool
add_plain_arg(ld_target(compiler.platform.arch));
}
+static void linker_setup_android(const char ***args_ref, Linker linker_type, bool is_dylib)
+{
+#ifdef __linux__
+ #define ANDROID_HOST_TAG "linux-x86_64"
+#elif __APPLE__
+ #define ANDROID_HOST_TAG "darwin-x86_64"
+#elif _WIN32
+ #define ANDROID_HOST_TAG "windows-x86_64"
+#else
+ #error Unknown Host OS
+#endif
+
+ if (is_no_pie(compiler.platform.reloc_model)) add_plain_arg("-no-pie");
+ if (is_pie(compiler.platform.reloc_model)) add_plain_arg("-pie");
+ add_plain_arg("-dynamic-linker"); add_plain_arg("/system/bin/linker64");
+
+ scratch_buffer_clear();
+ scratch_buffer_append("-L");
+ scratch_buffer_append(compiler.build.android.ndk_path);
+ scratch_buffer_append("/toolchains/llvm/prebuilt/");
+ scratch_buffer_append(ANDROID_HOST_TAG);
+ scratch_buffer_append("/sysroot/usr/lib/");
+ scratch_buffer_append(compiler.platform.target_triple);
+ scratch_buffer_append_char('/');
+ scratch_buffer_append_signed_int(compiler.build.android.api_version);
+ add_plain_arg(scratch_buffer_copy());
+
+ scratch_buffer_clear();
+ scratch_buffer_append(compiler.build.android.ndk_path);
+ scratch_buffer_append("/toolchains/llvm/prebuilt/");
+ scratch_buffer_append(ANDROID_HOST_TAG);
+ scratch_buffer_append("/sysroot/usr/lib/");
+ scratch_buffer_append(compiler.platform.target_triple);
+ scratch_buffer_append_char('/');
+ scratch_buffer_append_signed_int(compiler.build.android.api_version);
+ scratch_buffer_append("/crtbegin_dynamic.o");
+ add_plain_arg(scratch_buffer_copy());
+
+ scratch_buffer_clear();
+ scratch_buffer_append(compiler.build.android.ndk_path);
+ scratch_buffer_append("/toolchains/llvm/prebuilt/");
+ scratch_buffer_append(ANDROID_HOST_TAG);
+ scratch_buffer_append("/sysroot/usr/lib/");
+ scratch_buffer_append(compiler.platform.target_triple);
+ scratch_buffer_append_char('/');
+ scratch_buffer_append_signed_int(compiler.build.android.api_version);
+ scratch_buffer_append("/crt_pad_segment.o");
+ add_plain_arg(scratch_buffer_copy());
+
+ scratch_buffer_clear();
+ scratch_buffer_append(compiler.build.android.ndk_path);
+ scratch_buffer_append("/toolchains/llvm/prebuilt/");
+ scratch_buffer_append(ANDROID_HOST_TAG);
+ scratch_buffer_append("/sysroot/usr/lib/");
+ scratch_buffer_append(compiler.platform.target_triple);
+ scratch_buffer_append_char('/');
+ scratch_buffer_append_signed_int(compiler.build.android.api_version);
+ scratch_buffer_append("/crtend_android.o");
+ add_plain_arg(scratch_buffer_copy());
+
+ add_plain_arg("-ldl");
+ add_plain_arg("-lm");
+ add_plain_arg("-lc");
+}
+
static void linker_setup_freebsd(const char ***args_ref, Linker linker_type, bool is_dylib)
{
if (linker_type == LINKER_CC) {
@@ -594,6 +659,9 @@ static bool linker_setup(const char ***args_ref, const char **files_to_link, uns
case OS_TYPE_LINUX:
linker_setup_linux(args_ref, linker_type, is_dylib);
break;
+ case OS_TYPE_ANDROID:
+ linker_setup_android(args_ref, linker_type, is_dylib);
+ break;
case OS_TYPE_UNKNOWN:
if (link_libc())
{
@@ -694,6 +762,7 @@ Linker linker_find_linker_type(void)
case OS_TYPE_LINUX:
case OS_TYPE_NETBSD:
case OS_TYPE_OPENBSD:
+ case OS_TYPE_ANDROID:
return LINKER_LD;
case OS_DARWIN_TYPES:
return LINKER_LD64;
diff --git a/src/compiler/target.c b/src/compiler/target.c
index 7d241b55a..8a5b67803 100644
--- a/src/compiler/target.c
+++ b/src/compiler/target.c
@@ -122,6 +122,7 @@ static bool os_target_use_thread_local(OsType os)
case OS_DARWIN_TYPES:
case OS_TYPE_FREE_BSD:
case OS_TYPE_LINUX:
+ case OS_TYPE_ANDROID:
case OS_TYPE_NETBSD:
case OS_TYPE_OPENBSD:
case OS_TYPE_WIN32:
@@ -1100,7 +1101,8 @@ static char *arch_to_target_triple[ARCH_OS_TARGET_LAST + 1] = {
[FREEBSD_X64] = "x86_64-pc-freebsd",
[OPENBSD_X64] = "x86_64-pc-openbsd",
[ELF_X64] = "x86_64-unknown-elf",
- [ANDROID_AARCH64] = "aarch64-unknown-linux-android",
+ [ANDROID_AARCH64] = "aarch64-linux-android",
+ [ANDROID_X86_64] = "x86_64-linux-android",
[LINUX_AARCH64] = "aarch64-unknown-linux-gnu",
[IOS_AARCH64] = "aarch64-apple-ios",
[MACOS_AARCH64] = "aarch64-apple-macosx",
@@ -1309,6 +1311,7 @@ static OsType os_from_llvm_string(StringSlice os_string)
STRCASE("wasi", OS_TYPE_WASI)
STRCASE("emscripten", OS_TYPE_EMSCRIPTEN)
STRCASE("elf", OS_TYPE_NONE)
+ STRCASE("android", OS_TYPE_ANDROID)
return OS_TYPE_UNKNOWN;
#undef STRCASE
}
@@ -1474,6 +1477,7 @@ static ObjectFormatType object_format_from_os(OsType os, ArchType arch_type)
if (arch_is_wasm(arch_type)) return OBJ_FORMAT_WASM;
FALLTHROUGH;
case OS_TYPE_LINUX:
+ case OS_TYPE_ANDROID:
case OS_TYPE_NETBSD:
case OS_TYPE_OPENBSD:
case OS_TYPE_FREE_BSD:
@@ -1529,6 +1533,7 @@ static unsigned os_target_c_type_bits(OsType os, ArchType arch, CType type)
break;
case OS_DARWIN_TYPES:
case OS_TYPE_LINUX:
+ case OS_TYPE_ANDROID:
case OS_TYPE_NONE:
case OS_TYPE_FREE_BSD:
case OS_TYPE_NETBSD:
@@ -1706,6 +1711,7 @@ static RelocModel arch_os_reloc_default(ArchType arch, OsType os, EnvironmentTyp
if (arch == ARCH_TYPE_X86) return RELOC_NONE;
return RELOC_BIG_PIC;
case OS_TYPE_LINUX:
+ case OS_TYPE_ANDROID:
return RELOC_BIG_PIC;
case OS_TYPE_WASI:
return RELOC_NONE;
@@ -1746,6 +1752,7 @@ static RelocModel arch_os_reloc_default(ArchType arch, OsType os, EnvironmentTyp
case OS_TYPE_WASI:
return RELOC_NONE;
case OS_TYPE_LINUX:
+ case OS_TYPE_ANDROID:
return RELOC_BIG_PIE;
case OS_TYPE_OPENBSD:
return RELOC_SMALL_PIE;
@@ -1768,6 +1775,7 @@ static bool arch_os_pic_default_forced(ArchType arch, OsType os)
case OS_TYPE_NONE:
case OS_TYPE_FREE_BSD:
case OS_TYPE_LINUX:
+ case OS_TYPE_ANDROID:
case OS_TYPE_NETBSD:
case OS_TYPE_OPENBSD:
return false;
@@ -2119,4 +2127,3 @@ void target_setup(BuildTarget *target)
}
-