aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2025-03-26 18:03:36 +0000
committergingerBill <bill@gingerbill.org>2025-03-26 18:03:36 +0000
commitf13a075cd197a906fe6d5c500dc4f95244eef902 (patch)
tree3b982c1623f212b8a0f0bcf3ef6b6843607b3dd4 /src
parent346836a098acbf8a79c6affc06f3a24c35761b8c (diff)
Begin work on `odin package-android` command
Diffstat (limited to 'src')
-rw-r--r--src/build_settings.cpp217
-rw-r--r--src/linker.cpp146
-rw-r--r--src/main.cpp24
-rw-r--r--src/package_android.cpp163
4 files changed, 295 insertions, 255 deletions
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index 1823dc8b0..21a692c47 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -209,15 +209,15 @@ enum BuildModeKind {
enum CommandKind : u32 {
Command_run = 1<<0,
Command_build = 1<<1,
- Command_check = 1<<3,
- Command_doc = 1<<5,
- Command_version = 1<<6,
- Command_test = 1<<7,
+ Command_check = 1<<2,
+ Command_doc = 1<<3,
+ Command_version = 1<<4,
+ Command_test = 1<<5,
- Command_strip_semicolon = 1<<8,
- Command_bug_report = 1<<9,
+ Command_strip_semicolon = 1<<6,
+ Command_bug_report = 1<<7,
- Command_pkg_android = 1<<16,
+ Command_package_android = 1<<8,
Command__does_check = Command_run|Command_build|Command_check|Command_doc|Command_test|Command_strip_semicolon,
Command__does_build = Command_run|Command_build|Command_test,
@@ -232,6 +232,8 @@ gb_global char const *odin_command_strings[32] = {
"version",
"test",
"strip-semicolon",
+ "",
+ "package-android",
};
@@ -1489,6 +1491,107 @@ gb_internal bool has_ansi_terminal_colours(void) {
return build_context.has_ansi_terminal_colours && !json_errors();
}
+gb_internal void init_android_values(bool with_sdk) {
+ auto *bc = &build_context;
+ { // Android SDK/API Level
+ String default_level = str_lit("34");
+ if (!bc->minimum_os_version_string_given) {
+ bc->minimum_os_version_string = default_level;
+ }
+ BigInt level = {};
+ bool success = false;
+ big_int_from_string(&level, bc->minimum_os_version_string, &success);
+ if (!success) {
+ gb_printf_err("Warning: Invalid -minimum-os-version:%.*s for -subtarget:Android, defaulting to %.*s\n", LIT(bc->minimum_os_version_string), LIT(default_level));
+ bc->minimum_os_version_string = default_level;
+ big_int_from_string(&level, bc->minimum_os_version_string, &success);
+ GB_ASSERT(success);
+ }
+
+ i64 new_level = big_int_to_i64(&level);
+
+ if (new_level >= 21) {
+ bc->ODIN_ANDROID_API_LEVEL = cast(int)new_level;
+ } else {
+ gb_printf_err("Warning: Invalid -minimum-os-version:%.*s for -subtarget:Android, defaulting to %.*s\n", LIT(bc->minimum_os_version_string), LIT(default_level));
+ bc->ODIN_ANDROID_API_LEVEL = atoi(cast(char const *)default_level.text);
+ }
+ }
+ bc->ODIN_ANDROID_NDK = normalize_path(permanent_allocator(), make_string_c(gb_get_env("ODIN_ANDROID_NDK", permanent_allocator())), NIX_SEPARATOR_STRING);
+ bc->ODIN_ANDROID_NDK_TOOLCHAIN = normalize_path(permanent_allocator(), make_string_c(gb_get_env("ODIN_ANDROID_NDK_TOOLCHAIN", permanent_allocator())), NIX_SEPARATOR_STRING);
+ bc->ODIN_ANDROID_SDK = normalize_path(permanent_allocator(), make_string_c(gb_get_env("ODIN_ANDROID_SDK", permanent_allocator())), NIX_SEPARATOR_STRING);
+
+ #if defined(GB_SYSTEM_WINDOWS)
+ if (bc->ODIN_ANDROID_SDK.len == 0) {
+ bc->ODIN_ANDROID_SDK = normalize_path(permanent_allocator(),
+ path_to_fullpath(permanent_allocator(), str_lit("%LocalAppData%/Android/Sdk"), nullptr),
+ NIX_SEPARATOR_STRING);
+ }
+ #endif
+
+ if (bc->ODIN_ANDROID_NDK.len != 0 && bc->ODIN_ANDROID_NDK_TOOLCHAIN.len == 0) {
+ String arch = str_lit("x86_64");
+ #if defined (GB_CPU_ARM)
+ // TODO(bill): this is a complete guess
+ arch = str_lit("aarch64");
+ #endif
+ #if defined(GB_SYSTEM_WINDOWS)
+ bc->ODIN_ANDROID_NDK_TOOLCHAIN = concatenate4_strings(temporary_allocator(), bc->ODIN_ANDROID_NDK, str_lit("toolchains/llvm/prebuilt/"), str_lit("windows-"), arch);
+ #elif defined(GB_SYSTEM_OSX)
+ // TODO(bill): is this name even correct?
+ bc->ODIN_ANDROID_NDK_TOOLCHAIN = concatenate4_strings(temporary_allocator(), bc->ODIN_ANDROID_NDK, str_lit("toolchains/llvm/prebuilt/"), str_lit("darwin-"), arch);
+ #elif defined(GB_SYSTEM_LINUX)
+ bc->ODIN_ANDROID_NDK_TOOLCHAIN = concatenate4_strings(temporary_allocator(), bc->ODIN_ANDROID_NDK, str_lit("toolchains/llvm/prebuilt/"), str_lit("linux-"), arch);
+ #endif
+
+ bc->ODIN_ANDROID_NDK_TOOLCHAIN = normalize_path(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN, NIX_SEPARATOR_STRING);
+ }
+
+ if (bc->ODIN_ANDROID_NDK.len == 0) {
+ gb_printf_err("Error: ODIN_ANDROID_NDK not set");
+ gb_exit(1);
+
+ }
+
+ if (bc->ODIN_ANDROID_NDK_TOOLCHAIN.len == 0) {
+ gb_printf_err("Error: ODIN_ANDROID_NDK not set");
+ gb_exit(1);
+ }
+
+ bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB = concatenate_strings(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN, str_lit("sysroot/usr/lib/aarch64-linux-android/"));
+
+ char buf[32] = {};
+ gb_snprintf(buf, gb_size_of(buf), "%d/", bc->ODIN_ANDROID_API_LEVEL);
+ bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL = concatenate_strings(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB, make_string_c(buf));
+
+ bc->ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT = concatenate_strings(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN, str_lit("sysroot/"));
+
+
+ bc->ODIN_ANDROID_JAR_SIGNER = normalize_path(permanent_allocator(), make_string_c(gb_get_env("ODIN_ANDROID_JAR_SIGNER", permanent_allocator())), NIX_SEPARATOR_STRING);
+ if (with_sdk) {
+ if (bc->ODIN_ANDROID_SDK.len == 0) {
+ gb_printf_err("Error: ODIN_ANDROID_SDK not set, which is required for -build-mode:executable for -subtarget:android");
+ gb_exit(1);
+ }
+ if (bc->ODIN_ANDROID_JAR_SIGNER.len == 0) {
+ gb_printf_err("Error: ODIN_ANDROID_JAR_SIGNER not set, which is required for -build-mode:executable for -subtarget:android");
+ gb_exit(1);
+ }
+ if (bc->android_keystore.len == 0) {
+ gb_printf_err("Error: -android-keystore:<string> has not been set\n");
+ gb_exit(1);
+ }
+ if (bc->android_keystore_alias.len == 0) {
+ gb_printf_err("Error: -android-keystore_alias:<string> has not been set\n");
+ gb_exit(1);
+ }
+ if (bc->android_manifest.len == 0) {
+ gb_printf_err("Error: -android-manifest:<string> has not been set\n");
+ gb_exit(1);
+ }
+ }
+}
+
gb_internal bool has_asm_extension(String const &path) {
String ext = path_extension(path);
if (ext == ".asm") {
@@ -1744,105 +1847,7 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
bc->metrics.target_triplet = concatenate_strings(permanent_allocator(), bc->metrics.target_triplet, bc->minimum_os_version_string);
}
} else if (selected_subtarget == Subtarget_Android) {
-
- { // Android SDK/API Level
- String default_level = str_lit("34");
- if (!bc->minimum_os_version_string_given) {
- bc->minimum_os_version_string = default_level;
- }
- BigInt level = {};
- bool success = false;
- big_int_from_string(&level, bc->minimum_os_version_string, &success);
- if (!success) {
- gb_printf_err("Warning: Invalid -minimum-os-version:%.*s for -subtarget:Android, defaulting to %.*s\n", LIT(bc->minimum_os_version_string), LIT(default_level));
- bc->minimum_os_version_string = default_level;
- big_int_from_string(&level, bc->minimum_os_version_string, &success);
- GB_ASSERT(success);
- }
-
- i64 new_level = big_int_to_i64(&level);
-
- if (new_level >= 21) {
- bc->ODIN_ANDROID_API_LEVEL = cast(int)new_level;
- } else {
- gb_printf_err("Warning: Invalid -minimum-os-version:%.*s for -subtarget:Android, defaulting to %.*s\n", LIT(bc->minimum_os_version_string), LIT(default_level));
- bc->ODIN_ANDROID_API_LEVEL = atoi(cast(char const *)default_level.text);
- }
- }
- bc->ODIN_ANDROID_NDK = normalize_path(permanent_allocator(), make_string_c(gb_get_env("ODIN_ANDROID_NDK", permanent_allocator())), NIX_SEPARATOR_STRING);
- bc->ODIN_ANDROID_NDK_TOOLCHAIN = normalize_path(permanent_allocator(), make_string_c(gb_get_env("ODIN_ANDROID_NDK_TOOLCHAIN", permanent_allocator())), NIX_SEPARATOR_STRING);
- bc->ODIN_ANDROID_SDK = normalize_path(permanent_allocator(), make_string_c(gb_get_env("ODIN_ANDROID_SDK", permanent_allocator())), NIX_SEPARATOR_STRING);
-
- #if defined(GB_SYSTEM_WINDOWS)
- if (bc->ODIN_ANDROID_SDK.len == 0) {
- bc->ODIN_ANDROID_SDK = normalize_path(permanent_allocator(),
- path_to_fullpath(permanent_allocator(), str_lit("%LocalAppData%/Android/Sdk"), nullptr),
- NIX_SEPARATOR_STRING);
- }
- #endif
-
- if (bc->ODIN_ANDROID_NDK.len != 0 && bc->ODIN_ANDROID_NDK_TOOLCHAIN.len == 0) {
- String arch = str_lit("x86_64");
- #if defined (GB_CPU_ARM)
- // TODO(bill): this is a complete guess
- arch = str_lit("aarch64");
- #endif
- #if defined(GB_SYSTEM_WINDOWS)
- bc->ODIN_ANDROID_NDK_TOOLCHAIN = concatenate4_strings(temporary_allocator(), bc->ODIN_ANDROID_NDK, str_lit("toolchains/llvm/prebuilt/"), str_lit("windows-"), arch);
- #elif defined(GB_SYSTEM_OSX)
- // TODO(bill): is this name even correct?
- bc->ODIN_ANDROID_NDK_TOOLCHAIN = concatenate4_strings(temporary_allocator(), bc->ODIN_ANDROID_NDK, str_lit("toolchains/llvm/prebuilt/"), str_lit("darwin-"), arch);
- #elif defined(GB_SYSTEM_LINUX)
- bc->ODIN_ANDROID_NDK_TOOLCHAIN = concatenate4_strings(temporary_allocator(), bc->ODIN_ANDROID_NDK, str_lit("toolchains/llvm/prebuilt/"), str_lit("linux-"), arch);
- #endif
-
- bc->ODIN_ANDROID_NDK_TOOLCHAIN = normalize_path(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN, NIX_SEPARATOR_STRING);
- }
-
- if (bc->ODIN_ANDROID_NDK.len == 0) {
- gb_printf_err("Error: ODIN_ANDROID_NDK not set");
- gb_exit(1);
-
- }
-
- if (bc->ODIN_ANDROID_NDK_TOOLCHAIN.len == 0) {
- gb_printf_err("Error: ODIN_ANDROID_NDK not set");
- gb_exit(1);
- }
-
- bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB = concatenate_strings(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN, str_lit("sysroot/usr/lib/aarch64-linux-android/"));
-
- char buf[32] = {};
- gb_snprintf(buf, gb_size_of(buf), "%d/", bc->ODIN_ANDROID_API_LEVEL);
- bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL = concatenate_strings(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB, make_string_c(buf));
-
- bc->ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT = concatenate_strings(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN, str_lit("sysroot/"));
-
-
- bc->ODIN_ANDROID_JAR_SIGNER = normalize_path(permanent_allocator(), make_string_c(gb_get_env("ODIN_ANDROID_JAR_SIGNER", permanent_allocator())), NIX_SEPARATOR_STRING);
- if (bc->build_mode == BuildMode_Executable) {
- if (bc->ODIN_ANDROID_SDK.len == 0) {
- gb_printf_err("Error: ODIN_ANDROID_SDK not set, which is required for -build-mode:executable for -subtarget:android");
- gb_exit(1);
- }
- if (bc->ODIN_ANDROID_JAR_SIGNER.len == 0) {
- gb_printf_err("Error: ODIN_ANDROID_JAR_SIGNER not set, which is required for -build-mode:executable for -subtarget:android");
- gb_exit(1);
- }
- if (bc->android_keystore.len == 0) {
- gb_printf_err("Error: -android-keystore:<string> has not been set\n");
- gb_exit(1);
- }
- if (bc->android_keystore_alias.len == 0) {
- gb_printf_err("Error: -android-keystore_alias:<string> has not been set\n");
- gb_exit(1);
- }
- if (bc->android_manifest.len == 0) {
- gb_printf_err("Error: -android-manifest:<string> has not been set\n");
- gb_exit(1);
- }
- }
-
+ init_android_values(bc->build_mode == BuildMode_Executable);
}
if (!bc->custom_optimization_level) {
diff --git a/src/linker.cpp b/src/linker.cpp
index 5880014e1..ed82f2fe9 100644
--- a/src/linker.cpp
+++ b/src/linker.cpp
@@ -868,152 +868,6 @@ try_cross_linking:;
return result;
}
}
- if (is_android && build_context.build_mode == BuildMode_Executable) {
- String android_sdk_build_tools = concatenate3_strings(temporary_allocator(),
- build_context.ODIN_ANDROID_SDK, str_lit("build-tools"), NIX_SEPARATOR_STRING);
-
- Array<FileInfo> list = {};
- ReadDirectoryError rd_err = read_directory(android_sdk_build_tools, &list);
- defer (array_free(&list));
-
- switch (rd_err) {
- case ReadDirectory_InvalidPath:
- gb_printf_err("Invalid path: %.*s\n", LIT(android_sdk_build_tools));
- return 1;
- case ReadDirectory_NotExists:
- gb_printf_err("Path does not exist: %.*s\n", LIT(android_sdk_build_tools));
- return 1;
- case ReadDirectory_Permission:
- gb_printf_err("Unknown error whilst reading path %.*s\n", LIT(android_sdk_build_tools));
- return 1;
- case ReadDirectory_NotDir:
- gb_printf_err("Expected a directory for a package, got a file: %.*s\n", LIT(android_sdk_build_tools));
- return 1;
- case ReadDirectory_Empty:
- gb_printf_err("Empty directory: %.*s\n", LIT(android_sdk_build_tools));
- return 1;
- case ReadDirectory_Unknown:
- gb_printf_err("Unknown error whilst reading path %.*s\n", LIT(android_sdk_build_tools));
- return 1;
- }
-
- auto possible_valid_dirs = array_make<FileInfo>(heap_allocator(), 0, list.count);
- defer (array_free(&possible_valid_dirs));
-
-
- for (FileInfo fi : list) if (fi.is_dir) {
- bool all_numbers = true;
- for (isize i = 0; i < fi.name.len; i++) {
- u8 c = fi.name[i];
- if ('0' <= c && c <= '9') {
- // true
- } else if (i == 0) {
- all_numbers = false;
- } else if (c == '.') {
- break;
- } else {
- all_numbers = false;
- }
- }
-
- if (all_numbers) {
- array_add(&possible_valid_dirs, fi);
- }
- }
-
- if (possible_valid_dirs.count == 0) {
- gb_printf_err("Unable to find any Android SDK/API Level in %.*s\n", LIT(android_sdk_build_tools));
- return 1;
- }
-
- int *dir_numbers = gb_alloc_array(temporary_allocator(), int, possible_valid_dirs.count);
-
- char buf[1024] = {};
- for_array(i, possible_valid_dirs) {
- FileInfo fi = possible_valid_dirs[i];
- isize n = gb_min(gb_size_of(buf)-1, fi.name.len);
- memcpy(buf, fi.name.text, n);
- buf[n] = 0;
-
- dir_numbers[i] = atoi(buf);
- }
-
- isize closest_number_idx = -1;
- for (isize i = 0; i < possible_valid_dirs.count; i++) {
- if (dir_numbers[i] >= ODIN_ANDROID_API_LEVEL) {
- if (closest_number_idx < 0) {
- closest_number_idx = i;
- } else if (dir_numbers[i] < dir_numbers[closest_number_idx]) {
- closest_number_idx = i;
- }
- }
- }
-
- if (closest_number_idx < 0) {
- gb_printf_err("Unable to find any Android SDK/API Level in %.*s meeting the minimum API level of %d\n", LIT(android_sdk_build_tools), ODIN_ANDROID_API_LEVEL);
- return 1;
- }
-
- String api_number = possible_valid_dirs[closest_number_idx].name;
-
- android_sdk_build_tools = concatenate_strings(temporary_allocator(), android_sdk_build_tools, api_number);
- String android_sdk_platforms = concatenate_strings(temporary_allocator(),
- build_context.ODIN_ANDROID_SDK,
- make_string_c(gb_bprintf("platforms/android-%d/", dir_numbers[closest_number_idx]))
- );
-
-
-
- android_sdk_build_tools = normalize_path(temporary_allocator(), android_sdk_build_tools, NIX_SEPARATOR_STRING);
- android_sdk_platforms = normalize_path(temporary_allocator(), android_sdk_platforms, NIX_SEPARATOR_STRING);
-
- gbString cmd = gb_string_make(heap_allocator(), "");
- defer (gb_string_free(cmd));
-
- TIME_SECTION("Android aapt");
-
- String output_apk = path_remove_extension(output_filename);
-
- cmd = gb_string_append_length(cmd, android_sdk_build_tools.text, android_sdk_build_tools.len);
- cmd = gb_string_appendc(cmd, "aapt");
- cmd = gb_string_appendc(cmd, " package -f");
- cmd = gb_string_append_fmt(cmd, " -M \"%.*s\"", LIT(build_context.android_manifest));
- cmd = gb_string_append_fmt(cmd, " -I \"%.*sandroid.jar\"", LIT(android_sdk_platforms));
- cmd = gb_string_append_fmt(cmd, " -F \"%.*s.apk-build\"", LIT(output_apk));
-
- result = system_exec_command_line_app("android-aapt", cmd);
- if (result) {
- return result;
- }
-
- TIME_SECTION("Android jarsigner");
- gb_string_clear(cmd);
-
- cmd = gb_string_append_length(cmd, build_context.ODIN_ANDROID_JAR_SIGNER.text, build_context.ODIN_ANDROID_JAR_SIGNER.len);
- cmd = gb_string_append_fmt(cmd, " -storepass android -keystore \"%.*s\" \"%.*s.apk-build\" \"%.*s\"",
- LIT(build_context.android_keystore),
- LIT(output_apk),
- LIT(build_context.android_keystore_alias)
- );
- result = system_exec_command_line_app("android-jarsigner", cmd);
- if (result) {
- return result;
- }
-
- TIME_SECTION("Android zipalign");
- gb_string_clear(cmd);
-
- cmd = gb_string_append_length(cmd, android_sdk_build_tools.text, android_sdk_build_tools.len);
- cmd = gb_string_appendc(cmd, "zipalign");
- cmd = gb_string_appendc(cmd, " -f 4");
- cmd = gb_string_append_fmt(cmd, " \"%.*s.apk-build\" \"%.*s.apk\"", LIT(output_apk), LIT(output_apk));
-
-
- result = system_exec_command_line_app("android-zipalign", cmd);
- if (result) {
- return result;
- }
- }
}
}
diff --git a/src/main.cpp b/src/main.cpp
index 22121db73..1456717c5 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -74,6 +74,7 @@ gb_global Timings global_timings = {0};
#include "cached.cpp"
#include "linker.cpp"
+#include "package_android.cpp"
#if defined(GB_SYSTEM_WINDOWS) && defined(ODIN_TILDE_BACKEND)
#define ALLOW_TILDE 1
@@ -628,9 +629,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_Subsystem, str_lit("subsystem"), BuildFlagParam_String, Command__does_build);
#endif
- add_flag(&build_flags, BuildFlag_AndroidKeystore, str_lit("android-keystore"), BuildFlagParam_String, Command__does_build);
- add_flag(&build_flags, BuildFlag_AndroidKeystoreAlias, str_lit("android-keystore-alias"), BuildFlagParam_String, Command__does_build);
- add_flag(&build_flags, BuildFlag_AndroidManifest, str_lit("android-manifest"), BuildFlagParam_String, Command__does_build);
+ add_flag(&build_flags, BuildFlag_AndroidKeystore, str_lit("android-keystore"), BuildFlagParam_String, Command__does_build | Command_package_android);
+ add_flag(&build_flags, BuildFlag_AndroidKeystoreAlias, str_lit("android-keystore-alias"), BuildFlagParam_String, Command__does_build | Command_package_android);
+ add_flag(&build_flags, BuildFlag_AndroidManifest, str_lit("android-manifest"), BuildFlagParam_String, Command__does_build | Command_package_android);
GB_ASSERT(args.count >= 3);
@@ -2259,6 +2260,8 @@ gb_internal void print_show_help(String const arg0, String command, String optio
} else if (command == "strip-semicolon") {
print_usage_line(1, "strip-semicolon");
print_usage_line(2, "Parses and type checks .odin file(s) and then removes unneeded semicolons from the entire project.");
+ } else if (command == "package-android") {
+ print_usage_line(1, "package-android Packages directory in a specific layout as an APK");
}
bool doc = command == "doc";
@@ -3322,6 +3325,13 @@ int main(int arg_count, char const **arg_ptr) {
print_show_help(args[0], args[1], args[2]);
return 0;
}
+ } else if (command == "package-android") {
+ if (args.count < 3) {
+ usage(args[0]);
+ return 1;
+ }
+ build_context.command_kind = Command_package_android;
+ init_filename = args[2];
} else if (command == "root") {
gb_printf("%.*s", LIT(odin_root_dir()));
return 0;
@@ -3360,6 +3370,10 @@ int main(int arg_count, char const **arg_ptr) {
if (init_filename == "-file") {
gb_printf_err("Did you mean `%.*s %.*s <filename.odin> -file`?\n", LIT(args[0]), LIT(command));
} else {
+ if (!gb_file_exists(cast(const char*)init_filename.text)) {
+ gb_printf_err("The file '%.*s' was not found.\n", LIT(init_filename));
+ return 1;
+ }
gb_printf_err("Did you mean `%.*s %.*s %.*s -file`?\n", LIT(args[0]), LIT(command), LIT(init_filename));
}
@@ -3393,6 +3407,10 @@ int main(int arg_count, char const **arg_ptr) {
return 0;
}
+ if (command == "package-android") {
+ return package_android(args);
+ }
+
// NOTE(bill): add 'shared' directory if it is not already set
if (!find_library_collection_path(str_lit("shared"), nullptr)) {
add_library_collection(str_lit("shared"),
diff --git a/src/package_android.cpp b/src/package_android.cpp
new file mode 100644
index 000000000..9e6ddeff1
--- /dev/null
+++ b/src/package_android.cpp
@@ -0,0 +1,163 @@
+i32 package_android(Array<String> args) {
+ i32 result = 0;
+
+ init_android_values(/*with_sdk*/true);
+
+ int const ODIN_ANDROID_API_LEVEL = build_context.ODIN_ANDROID_API_LEVEL;
+
+ String ODIN_ANDROID_NDK = build_context.ODIN_ANDROID_NDK;
+ String ODIN_ANDROID_NDK_TOOLCHAIN = build_context.ODIN_ANDROID_NDK_TOOLCHAIN;
+ String ODIN_ANDROID_NDK_TOOLCHAIN_LIB = build_context.ODIN_ANDROID_NDK_TOOLCHAIN_LIB;
+ String ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL = build_context.ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL;
+ String ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT = build_context.ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT;
+
+
+ String android_sdk_build_tools = concatenate3_strings(temporary_allocator(),
+ build_context.ODIN_ANDROID_SDK, str_lit("build-tools"), NIX_SEPARATOR_STRING);
+
+ Array<FileInfo> list = {};
+ ReadDirectoryError rd_err = read_directory(android_sdk_build_tools, &list);
+ defer (array_free(&list));
+
+ switch (rd_err) {
+ case ReadDirectory_InvalidPath:
+ gb_printf_err("Invalid path: %.*s\n", LIT(android_sdk_build_tools));
+ return 1;
+ case ReadDirectory_NotExists:
+ gb_printf_err("Path does not exist: %.*s\n", LIT(android_sdk_build_tools));
+ return 1;
+ case ReadDirectory_Permission:
+ gb_printf_err("Unknown error whilst reading path %.*s\n", LIT(android_sdk_build_tools));
+ return 1;
+ case ReadDirectory_NotDir:
+ gb_printf_err("Expected a directory for a package, got a file: %.*s\n", LIT(android_sdk_build_tools));
+ return 1;
+ case ReadDirectory_Empty:
+ gb_printf_err("Empty directory: %.*s\n", LIT(android_sdk_build_tools));
+ return 1;
+ case ReadDirectory_Unknown:
+ gb_printf_err("Unknown error whilst reading path %.*s\n", LIT(android_sdk_build_tools));
+ return 1;
+ }
+
+ auto possible_valid_dirs = array_make<FileInfo>(heap_allocator(), 0, list.count);
+ defer (array_free(&possible_valid_dirs));
+
+
+ for (FileInfo fi : list) if (fi.is_dir) {
+ bool all_numbers = true;
+ for (isize i = 0; i < fi.name.len; i++) {
+ u8 c = fi.name[i];
+ if ('0' <= c && c <= '9') {
+ // true
+ } else if (i == 0) {
+ all_numbers = false;
+ } else if (c == '.') {
+ break;
+ } else {
+ all_numbers = false;
+ }
+ }
+
+ if (all_numbers) {
+ array_add(&possible_valid_dirs, fi);
+ }
+ }
+
+ if (possible_valid_dirs.count == 0) {
+ gb_printf_err("Unable to find any Android SDK/API Level in %.*s\n", LIT(android_sdk_build_tools));
+ return 1;
+ }
+
+ int *dir_numbers = gb_alloc_array(temporary_allocator(), int, possible_valid_dirs.count);
+
+ char buf[1024] = {};
+ for_array(i, possible_valid_dirs) {
+ FileInfo fi = possible_valid_dirs[i];
+ isize n = gb_min(gb_size_of(buf)-1, fi.name.len);
+ memcpy(buf, fi.name.text, n);
+ buf[n] = 0;
+
+ dir_numbers[i] = atoi(buf);
+ }
+
+ isize closest_number_idx = -1;
+ for (isize i = 0; i < possible_valid_dirs.count; i++) {
+ if (dir_numbers[i] >= ODIN_ANDROID_API_LEVEL) {
+ if (closest_number_idx < 0) {
+ closest_number_idx = i;
+ } else if (dir_numbers[i] < dir_numbers[closest_number_idx]) {
+ closest_number_idx = i;
+ }
+ }
+ }
+
+ if (closest_number_idx < 0) {
+ gb_printf_err("Unable to find any Android SDK/API Level in %.*s meeting the minimum API level of %d\n", LIT(android_sdk_build_tools), ODIN_ANDROID_API_LEVEL);
+ return 1;
+ }
+
+ String api_number = possible_valid_dirs[closest_number_idx].name;
+
+ android_sdk_build_tools = concatenate_strings(temporary_allocator(), android_sdk_build_tools, api_number);
+ String android_sdk_platforms = concatenate_strings(temporary_allocator(),
+ build_context.ODIN_ANDROID_SDK,
+ make_string_c(gb_bprintf("platforms/android-%d/", dir_numbers[closest_number_idx]))
+ );
+
+
+
+ android_sdk_build_tools = normalize_path(temporary_allocator(), android_sdk_build_tools, NIX_SEPARATOR_STRING);
+ android_sdk_platforms = normalize_path(temporary_allocator(), android_sdk_platforms, NIX_SEPARATOR_STRING);
+
+ gbString cmd = gb_string_make(heap_allocator(), "");
+ defer (gb_string_free(cmd));
+
+ TIME_SECTION("Android aapt");
+
+ String output_filename = str_lit("test");
+
+ String output_apk = path_remove_extension(output_filename);
+
+ cmd = gb_string_append_length(cmd, android_sdk_build_tools.text, android_sdk_build_tools.len);
+ cmd = gb_string_appendc(cmd, "aapt");
+ cmd = gb_string_appendc(cmd, " package -f");
+ cmd = gb_string_append_fmt(cmd, " -M \"%.*s\"", LIT(build_context.android_manifest));
+ cmd = gb_string_append_fmt(cmd, " -I \"%.*sandroid.jar\"", LIT(android_sdk_platforms));
+ cmd = gb_string_append_fmt(cmd, " -F \"%.*s.apk-build\"", LIT(output_apk));
+
+ result = system_exec_command_line_app("android-aapt", cmd);
+ if (result) {
+ return result;
+ }
+
+ TIME_SECTION("Android jarsigner");
+ gb_string_clear(cmd);
+
+ cmd = gb_string_append_length(cmd, build_context.ODIN_ANDROID_JAR_SIGNER.text, build_context.ODIN_ANDROID_JAR_SIGNER.len);
+ cmd = gb_string_append_fmt(cmd, " -storepass android -keystore \"%.*s\" \"%.*s.apk-build\" \"%.*s\"",
+ LIT(build_context.android_keystore),
+ LIT(output_apk),
+ LIT(build_context.android_keystore_alias)
+ );
+ result = system_exec_command_line_app("android-jarsigner", cmd);
+ if (result) {
+ return result;
+ }
+
+ TIME_SECTION("Android zipalign");
+ gb_string_clear(cmd);
+
+ cmd = gb_string_append_length(cmd, android_sdk_build_tools.text, android_sdk_build_tools.len);
+ cmd = gb_string_appendc(cmd, "zipalign");
+ cmd = gb_string_appendc(cmd, " -f 4");
+ cmd = gb_string_append_fmt(cmd, " \"%.*s.apk-build\" \"%.*s.apk\"", LIT(output_apk), LIT(output_apk));
+
+
+ result = system_exec_command_line_app("android-zipalign", cmd);
+ if (result) {
+ return result;
+ }
+
+ return 0;
+}