mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-31 13:30:08 +00:00
Merge tag 'dev-2025-04'
This commit is contained in:
+180
-9
@@ -171,6 +171,7 @@ struct TargetMetrics {
|
||||
enum Subtarget : u32 {
|
||||
Subtarget_Default,
|
||||
Subtarget_iOS,
|
||||
Subtarget_Android,
|
||||
|
||||
Subtarget_COUNT,
|
||||
};
|
||||
@@ -178,6 +179,7 @@ enum Subtarget : u32 {
|
||||
gb_global String subtarget_strings[Subtarget_COUNT] = {
|
||||
str_lit(""),
|
||||
str_lit("ios"),
|
||||
str_lit("android"),
|
||||
};
|
||||
|
||||
|
||||
@@ -204,20 +206,25 @@ enum BuildModeKind {
|
||||
BuildMode_COUNT,
|
||||
};
|
||||
|
||||
enum CommandKind : u32 {
|
||||
enum CommandKind : u64 {
|
||||
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_bundle_android = 1<<8,
|
||||
Command_bundle_macos = 1<<9,
|
||||
Command_bundle_ios = 1<<10,
|
||||
Command_bundle_orca = 1<<11,
|
||||
|
||||
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,
|
||||
Command_all = ~(u32)0,
|
||||
Command_all = ~(CommandKind)0,
|
||||
};
|
||||
|
||||
gb_global char const *odin_command_strings[32] = {
|
||||
@@ -228,6 +235,11 @@ gb_global char const *odin_command_strings[32] = {
|
||||
"version",
|
||||
"test",
|
||||
"strip-semicolon",
|
||||
"",
|
||||
"bundle android",
|
||||
"bundle macos",
|
||||
"bundle ios",
|
||||
"bundle orca",
|
||||
};
|
||||
|
||||
|
||||
@@ -527,6 +539,22 @@ struct BuildContext {
|
||||
|
||||
String minimum_os_version_string;
|
||||
bool minimum_os_version_string_given;
|
||||
|
||||
|
||||
int ODIN_ANDROID_API_LEVEL;
|
||||
|
||||
String ODIN_ANDROID_SDK;
|
||||
|
||||
String ODIN_ANDROID_NDK;
|
||||
String ODIN_ANDROID_NDK_TOOLCHAIN;
|
||||
String ODIN_ANDROID_NDK_TOOLCHAIN_LIB;
|
||||
String ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL;
|
||||
String ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT;
|
||||
|
||||
String ODIN_ANDROID_JAR_SIGNER;
|
||||
String android_keystore;
|
||||
String android_keystore_alias;
|
||||
String android_manifest;
|
||||
};
|
||||
|
||||
gb_global BuildContext build_context = {0};
|
||||
@@ -946,6 +974,14 @@ gb_internal bool is_arch_x86(void) {
|
||||
gb_global String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
|
||||
gb_global String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1};
|
||||
|
||||
gb_global String const SEPARATOR_STRING =
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
WIN32_SEPARATOR_STRING;
|
||||
#else
|
||||
NIX_SEPARATOR_STRING;
|
||||
#endif
|
||||
|
||||
|
||||
gb_global String const WASM_MODULE_NAME_SEPARATOR = str_lit("..");
|
||||
|
||||
gb_internal String internal_odin_root_dir(void);
|
||||
@@ -1461,6 +1497,103 @@ 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 && !with_sdk) {
|
||||
gb_printf_err("Error: ODIN_ANDROID_NDK not set");
|
||||
gb_exit(1);
|
||||
|
||||
}
|
||||
|
||||
if (bc->ODIN_ANDROID_NDK_TOOLCHAIN.len == 0 && !with_sdk) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal bool has_asm_extension(String const &path) {
|
||||
String ext = path_extension(path);
|
||||
if (ext == ".asm") {
|
||||
@@ -1652,6 +1785,15 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
|
||||
default:
|
||||
GB_PANIC("Unknown architecture for darwin");
|
||||
}
|
||||
} else if (metrics->os == TargetOs_linux && subtarget == Subtarget_Android) {
|
||||
switch (metrics->arch) {
|
||||
case TargetArch_arm64:
|
||||
bc->metrics.target_triplet = str_lit("aarch64-none-linux-android");
|
||||
bc->reloc_mode = RelocMode_PIC;
|
||||
break;
|
||||
default:
|
||||
GB_PANIC("Unknown architecture for -subtarget:android");
|
||||
}
|
||||
}
|
||||
|
||||
if (bc->metrics.os == TargetOs_windows) {
|
||||
@@ -1706,6 +1848,8 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
|
||||
if (subtarget == Subtarget_Default) {
|
||||
bc->metrics.target_triplet = concatenate_strings(permanent_allocator(), bc->metrics.target_triplet, bc->minimum_os_version_string);
|
||||
}
|
||||
} else if (selected_subtarget == Subtarget_Android) {
|
||||
init_android_values(bc->build_mode == BuildMode_Executable);
|
||||
}
|
||||
|
||||
if (!bc->custom_optimization_level) {
|
||||
@@ -1749,6 +1893,30 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
|
||||
if (bc->metrics.os == TargetOs_freestanding) {
|
||||
bc->ODIN_DEFAULT_TO_NIL_ALLOCATOR = !bc->ODIN_DEFAULT_TO_PANIC_ALLOCATOR;
|
||||
}
|
||||
|
||||
if (subtarget == Subtarget_Android) {
|
||||
switch (build_context.build_mode) {
|
||||
case BuildMode_DynamicLibrary:
|
||||
case BuildMode_Object:
|
||||
case BuildMode_Assembly:
|
||||
case BuildMode_LLVM_IR:
|
||||
break;
|
||||
default:
|
||||
case BuildMode_Executable:
|
||||
case BuildMode_StaticLibrary:
|
||||
if ((build_context.command_kind & Command__does_build) != 0) {
|
||||
gb_printf_err("Unsupported -build-mode for -subtarget:android\n");
|
||||
gb_printf_err("\tCurrently only supporting: \n");
|
||||
// gb_printf_err("\t\texe\n");
|
||||
gb_printf_err("\t\tshared\n");
|
||||
gb_printf_err("\t\tobject\n");
|
||||
gb_printf_err("\t\tassembly\n");
|
||||
gb_printf_err("\t\tllvm-ir\n");
|
||||
gb_exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
@@ -1947,7 +2115,10 @@ gb_internal bool init_build_paths(String init_filename) {
|
||||
output_extension = make_string(nullptr, 0);
|
||||
String const single_file_extension = str_lit(".odin");
|
||||
|
||||
if (build_context.metrics.os == TargetOs_windows) {
|
||||
if (selected_subtarget == Subtarget_Android) {
|
||||
// NOTE(bill): It's always shared!
|
||||
output_extension = STR_LIT("so");
|
||||
} else if (build_context.metrics.os == TargetOs_windows) {
|
||||
output_extension = STR_LIT("exe");
|
||||
} else if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) {
|
||||
// Do nothing: we don't want the .bin extension
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
i32 bundle_android(String init_directory);
|
||||
|
||||
i32 bundle(String init_directory) {
|
||||
switch (build_context.command_kind) {
|
||||
case Command_bundle_android:
|
||||
return bundle_android(init_directory);
|
||||
}
|
||||
gb_printf_err("Unknown odin package <platform>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
i32 bundle_android(String original_init_directory) {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
i32 result = 0;
|
||||
init_android_values(/*with_sdk*/true);
|
||||
|
||||
bool init_directory_ok = false;
|
||||
String init_directory = path_to_fullpath(temporary_allocator(), original_init_directory, &init_directory_ok);
|
||||
if (!init_directory_ok) {
|
||||
gb_printf_err("Error: '%.*s' is not a valid directory", LIT(original_init_directory));
|
||||
return 1;
|
||||
}
|
||||
init_directory = normalize_path(temporary_allocator(), init_directory, NIX_SEPARATOR_STRING);
|
||||
|
||||
int const ODIN_ANDROID_API_LEVEL = build_context.ODIN_ANDROID_API_LEVEL;
|
||||
|
||||
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));
|
||||
|
||||
|
||||
String current_directory = normalize_path(temporary_allocator(), get_working_directory(temporary_allocator()), NIX_SEPARATOR_STRING);
|
||||
defer (set_working_directory(current_directory));
|
||||
|
||||
if (current_directory.len != 0) {
|
||||
bool ok = set_working_directory(init_directory);
|
||||
if (!ok) {
|
||||
gb_printf_err("Error: Unable to currectly set the current working directory to '%.*s'\n", LIT(init_directory));
|
||||
}
|
||||
}
|
||||
|
||||
String output_filename = str_lit("test");
|
||||
String output_apk = path_remove_extension(output_filename);
|
||||
|
||||
TIME_SECTION("Android aapt");
|
||||
{
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
gb_string_clear(cmd);
|
||||
|
||||
String manifest = {};
|
||||
if (build_context.android_manifest.len != 0) {
|
||||
manifest = concatenate_strings(temporary_allocator(), current_directory, build_context.android_manifest);
|
||||
} else {
|
||||
manifest = concatenate_strings(temporary_allocator(), init_directory, str_lit("AndroidManifest.xml"));
|
||||
}
|
||||
|
||||
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");
|
||||
if (manifest.len != 0) {
|
||||
cmd = gb_string_append_fmt(cmd, " -M \"%.*s\"", LIT(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");
|
||||
{
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
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");
|
||||
if (build_context.android_keystore.len != 0) {
|
||||
String keystore = concatenate_strings(temporary_allocator(), current_directory, build_context.android_keystore);
|
||||
cmd = gb_string_append_fmt(cmd, " -keystore \"%.*s\"", LIT(keystore));
|
||||
}
|
||||
cmd = gb_string_append_fmt(cmd, " \"%.*s.apk-build\"", LIT(output_apk));
|
||||
if (build_context.android_keystore_alias.len != 0) {
|
||||
String keystore_alias = build_context.android_keystore_alias;
|
||||
cmd = gb_string_append_fmt(cmd, " \"%.*s\"", LIT(keystore_alias));
|
||||
}
|
||||
|
||||
result = system_exec_command_line_app("android-jarsigner", cmd);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
TIME_SECTION("Android zipalign");
|
||||
{
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
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;
|
||||
}
|
||||
+16
-5
@@ -645,6 +645,13 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
|
||||
break;
|
||||
}
|
||||
|
||||
if (!are_types_identical(x.type, y.type)) {
|
||||
gbString tx = type_to_string(x.type);
|
||||
gbString ty = type_to_string(y.type);
|
||||
error(call, "Mismatched types to '%.*s', '%s' vs '%s'", LIT(builtin_name), tx, ty);
|
||||
gb_string_free(ty);
|
||||
gb_string_free(tx);
|
||||
}
|
||||
|
||||
Type *vt = base_type(x.type);
|
||||
GB_ASSERT(vt->kind == Type_SimdVector);
|
||||
@@ -1675,12 +1682,16 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o
|
||||
}
|
||||
if (ce->args.count > 0) {
|
||||
Ast *arg = ce->args[0];
|
||||
Operand o = {};
|
||||
Entity *e = check_ident(c, &o, arg, nullptr, nullptr, true);
|
||||
if (e == nullptr || (e->flags & EntityFlag_Param) == 0) {
|
||||
error(ce->args[0], "'#caller_expression' expected a valid earlier parameter name");
|
||||
if (arg->kind != Ast_Ident) {
|
||||
error(arg, "'#caller_expression' expected an identifier");
|
||||
} else {
|
||||
Operand o = {};
|
||||
Entity *e = check_ident(c, &o, arg, nullptr, nullptr, true);
|
||||
if (e == nullptr || (e->flags & EntityFlag_Param) == 0) {
|
||||
error(arg, "'#caller_expression' expected a valid earlier parameter name");
|
||||
}
|
||||
arg->Ident.entity = e;
|
||||
}
|
||||
arg->Ident.entity = e;
|
||||
}
|
||||
|
||||
operand->type = t_string;
|
||||
|
||||
@@ -628,6 +628,10 @@ gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr
|
||||
Operand x = {};
|
||||
x.type = entity->type;
|
||||
x.mode = Addressing_Variable;
|
||||
if (entity->kind == Entity_Constant) {
|
||||
x.mode = Addressing_Constant;
|
||||
x.value = entity->Constant.value;
|
||||
}
|
||||
if (!check_is_assignable_to(ctx, &x, e->type)) {
|
||||
gbString expr_str = expr_to_string(init);
|
||||
gbString op_type_str = type_to_string(entity->type);
|
||||
|
||||
+7
-6
@@ -8979,8 +8979,14 @@ gb_internal ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node
|
||||
o->expr = node;
|
||||
return Expr_Expr;
|
||||
}
|
||||
|
||||
Type *left_type = nullptr;
|
||||
Type *right_type = nullptr;
|
||||
check_or_else_split_types(c, &x, name, &left_type, &right_type);
|
||||
add_type_and_value(c, arg, x.mode, x.type, x.value);
|
||||
|
||||
bool y_is_diverging = false;
|
||||
check_expr_base(c, &y, default_value, x.type);
|
||||
check_expr_base(c, &y, default_value, left_type);
|
||||
switch (y.mode) {
|
||||
case Addressing_NoValue:
|
||||
if (is_diverging_expr(y.expr)) {
|
||||
@@ -9005,11 +9011,6 @@ gb_internal ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node
|
||||
return Expr_Expr;
|
||||
}
|
||||
|
||||
Type *left_type = nullptr;
|
||||
Type *right_type = nullptr;
|
||||
check_or_else_split_types(c, &x, name, &left_type, &right_type);
|
||||
add_type_and_value(c, arg, x.mode, x.type, x.value);
|
||||
|
||||
if (left_type != nullptr) {
|
||||
if (!y_is_diverging) {
|
||||
check_assignment(c, &y, left_type, name);
|
||||
|
||||
@@ -1149,6 +1149,7 @@ gb_internal void init_universal(void) {
|
||||
GlobalEnumValue values[Subtarget_COUNT] = {
|
||||
{"Default", Subtarget_Default},
|
||||
{"iOS", Subtarget_iOS},
|
||||
{"Android", Subtarget_Android},
|
||||
};
|
||||
|
||||
auto fields = add_global_enum_type(str_lit("Odin_Platform_Subtarget_Type"), values, gb_count_of(values));
|
||||
|
||||
+163
-44
@@ -7,19 +7,15 @@ struct LinkerData {
|
||||
Array<String> output_temp_paths;
|
||||
String output_base;
|
||||
String output_name;
|
||||
#if defined(GB_SYSTEM_OSX)
|
||||
b8 needs_system_library_linked;
|
||||
#endif
|
||||
bool needs_system_library_linked;
|
||||
};
|
||||
|
||||
gb_internal i32 system_exec_command_line_app(char const *name, char const *fmt, ...);
|
||||
gb_internal bool system_exec_command_line_app_output(char const *command, gbString *output);
|
||||
|
||||
#if defined(GB_SYSTEM_OSX)
|
||||
gb_internal void linker_enable_system_library_linking(LinkerData *ld) {
|
||||
ld->needs_system_library_linked = 1;
|
||||
ld->needs_system_library_linked = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
gb_internal void linker_data_init(LinkerData *ld, CheckerInfo *info, String const &init_fullpath) {
|
||||
gbAllocator ha = heap_allocator();
|
||||
@@ -28,9 +24,7 @@ gb_internal void linker_data_init(LinkerData *ld, CheckerInfo *info, String cons
|
||||
array_init(&ld->foreign_libraries, ha, 0, 1024);
|
||||
ptr_set_init(&ld->foreign_libraries_set, 1024);
|
||||
|
||||
#if defined(GB_SYSTEM_OSX)
|
||||
ld->needs_system_library_linked = 0;
|
||||
#endif
|
||||
ld->needs_system_library_linked = false;
|
||||
|
||||
if (build_context.out_filepath.len == 0) {
|
||||
ld->output_name = remove_directory_from_path(init_fullpath);
|
||||
@@ -136,6 +130,9 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool is_cross_linking = false;
|
||||
bool is_android = false;
|
||||
|
||||
if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) {
|
||||
#if defined(GB_SYSTEM_UNIX)
|
||||
result = system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s %.*s",
|
||||
@@ -147,22 +144,29 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
);
|
||||
#endif
|
||||
} else if (build_context.cross_compiling && build_context.different_os) {
|
||||
gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n",
|
||||
LIT(target_os_names[build_context.metrics.os]),
|
||||
LIT(target_arch_names[build_context.metrics.arch])
|
||||
);
|
||||
build_context.keep_object_files = true;
|
||||
switch (selected_subtarget) {
|
||||
case Subtarget_Android:
|
||||
is_cross_linking = true;
|
||||
is_android = true;
|
||||
goto try_cross_linking;
|
||||
default:
|
||||
gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n",
|
||||
LIT(target_os_names[build_context.metrics.os]),
|
||||
LIT(target_arch_names[build_context.metrics.arch])
|
||||
);
|
||||
build_context.keep_object_files = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
try_cross_linking:;
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
bool is_windows = true;
|
||||
bool is_windows = build_context.metrics.os == TargetOs_windows;
|
||||
#else
|
||||
bool is_windows = false;
|
||||
#endif
|
||||
#if defined(GB_SYSTEM_OSX)
|
||||
bool is_osx = true;
|
||||
#else
|
||||
bool is_osx = false;
|
||||
#endif
|
||||
|
||||
bool is_osx = build_context.metrics.os == TargetOs_darwin;
|
||||
|
||||
|
||||
if (is_windows) {
|
||||
@@ -414,23 +418,27 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
} else {
|
||||
timings_start_section(timings, str_lit("ld-link"));
|
||||
|
||||
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;
|
||||
|
||||
// Link using `clang`, unless overridden by `ODIN_CLANG_PATH` environment variable.
|
||||
const char* clang_path = gb_get_env("ODIN_CLANG_PATH", permanent_allocator());
|
||||
if (clang_path == NULL) {
|
||||
clang_path = "clang";
|
||||
}
|
||||
|
||||
// NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe
|
||||
char cwd[256];
|
||||
#if !defined(GB_SYSTEM_WINDOWS)
|
||||
getcwd(&cwd[0], 256);
|
||||
#endif
|
||||
//printf("%s\n", cwd);
|
||||
|
||||
// NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library
|
||||
// files can be passed with -l:
|
||||
gbString lib_str = gb_string_make(heap_allocator(), "-L/");
|
||||
gbString lib_str = gb_string_make(heap_allocator(), "");
|
||||
defer (gb_string_free(lib_str));
|
||||
#if !defined(GB_SYSTEM_WINDOWS)
|
||||
lib_str = gb_string_appendc(lib_str, "-L/ ");
|
||||
#endif
|
||||
|
||||
StringSet asm_files = {};
|
||||
string_set_init(&asm_files, 64);
|
||||
@@ -496,19 +504,20 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
}
|
||||
|
||||
String obj_format;
|
||||
#if defined(GB_ARCH_64_BIT)
|
||||
if (is_osx) {
|
||||
obj_format = str_lit("macho64");
|
||||
if (build_context.metrics.ptr_size == 8) {
|
||||
if (is_osx) {
|
||||
obj_format = str_lit("macho64");
|
||||
} else {
|
||||
obj_format = str_lit("elf64");
|
||||
}
|
||||
} else {
|
||||
obj_format = str_lit("elf64");
|
||||
GB_ASSERT(build_context.metrics.ptr_size == 4);
|
||||
if (is_osx) {
|
||||
obj_format = str_lit("macho32");
|
||||
} else {
|
||||
obj_format = str_lit("elf32");
|
||||
}
|
||||
}
|
||||
#elif defined(GB_ARCH_32_BIT)
|
||||
if (is_osx) {
|
||||
obj_format = str_lit("macho32");
|
||||
} else {
|
||||
obj_format = str_lit("elf32");
|
||||
}
|
||||
#endif // GB_ARCH_*_BIT
|
||||
|
||||
if (build_context.metrics.arch == TargetArch_riscv64) {
|
||||
result = system_exec_command_line_app("clang",
|
||||
@@ -618,6 +627,78 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
|
||||
gbString object_files = gb_string_make(heap_allocator(), "");
|
||||
defer (gb_string_free(object_files));
|
||||
|
||||
|
||||
if (is_android) { // NOTE(bill): glue code needed for Android
|
||||
TIME_SECTION("Android Native App Glue Compile");
|
||||
|
||||
String android_glue_object = {};
|
||||
String android_glue_static_lib = {};
|
||||
|
||||
char hash_buf[64] = {};
|
||||
gb_snprintf(hash_buf, gb_size_of(hash_buf), "%p", &hash_buf);
|
||||
String hash = make_string_c(hash_buf);
|
||||
|
||||
String temp_dir = normalize_path(temporary_allocator(), temporary_directory(temporary_allocator()), NIX_SEPARATOR_STRING);
|
||||
android_glue_object = concatenate4_strings(temporary_allocator(), temp_dir, str_lit("android_native_app_glue-"), hash, str_lit(".o"));
|
||||
android_glue_static_lib = concatenate4_strings(permanent_allocator(), temp_dir, str_lit("libandroid_native_app_glue-"), hash, str_lit(".a"));
|
||||
|
||||
gbString glue = gb_string_make(heap_allocator(), clang_path);
|
||||
defer (gb_string_free(glue));
|
||||
|
||||
glue = gb_string_append_fmt(glue, " --target=aarch64-linux-android%d ", ODIN_ANDROID_API_LEVEL);
|
||||
glue = gb_string_appendc(glue, "-c \"");
|
||||
glue = gb_string_append_length(glue, ODIN_ANDROID_NDK.text, ODIN_ANDROID_NDK.len);
|
||||
glue = gb_string_appendc(glue, "sources/android/native_app_glue/android_native_app_glue.c");
|
||||
glue = gb_string_appendc(glue, "\" ");
|
||||
glue = gb_string_appendc(glue, "-o \"");
|
||||
glue = gb_string_append_length(glue, android_glue_object.text, android_glue_object.len);
|
||||
glue = gb_string_appendc(glue, "\" ");
|
||||
|
||||
glue = gb_string_appendc(glue, "\"-I");
|
||||
glue = gb_string_append_length(glue, ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len);
|
||||
glue = gb_string_appendc(glue, "sysroot/usr/include/");
|
||||
glue = gb_string_appendc(glue, "\" ");
|
||||
|
||||
glue = gb_string_appendc(glue, "\"-I");
|
||||
glue = gb_string_append_length(glue, ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len);
|
||||
glue = gb_string_appendc(glue, "sysroot/usr/include/aarch64-linux-android/");
|
||||
glue = gb_string_appendc(glue, "\" ");
|
||||
|
||||
|
||||
glue = gb_string_appendc(glue, "-Wno-macro-redefined ");
|
||||
|
||||
result = system_exec_command_line_app("android-native-app-glue-compile", glue);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
TIME_SECTION("Android Native App Glue ar");
|
||||
|
||||
gbString ar = gb_string_make_length(heap_allocator(), ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len);
|
||||
defer (gb_string_free(ar));
|
||||
|
||||
ar = gb_string_appendc(ar, "bin/llvm-ar");
|
||||
|
||||
ar = gb_string_appendc(ar, " rcs ");
|
||||
|
||||
ar = gb_string_appendc(ar, "\"");
|
||||
ar = gb_string_append_length(ar, android_glue_static_lib.text, android_glue_static_lib.len);
|
||||
ar = gb_string_appendc(ar, "\" ");
|
||||
|
||||
ar = gb_string_appendc(ar, "\"");
|
||||
ar = gb_string_append_length(ar, android_glue_object.text, android_glue_object.len);
|
||||
ar = gb_string_appendc(ar, "\" ");
|
||||
|
||||
result = system_exec_command_line_app("android-native-app-glue-ar", ar);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(android_glue_static_lib));
|
||||
}
|
||||
|
||||
|
||||
for (String object_path : gen->output_object_paths) {
|
||||
object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path));
|
||||
}
|
||||
@@ -661,7 +742,9 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' ");
|
||||
link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' ");
|
||||
}
|
||||
|
||||
} else if (is_android) {
|
||||
// Always shared even in android!
|
||||
link_settings = gb_string_appendc(link_settings, "-shared ");
|
||||
}
|
||||
|
||||
if (build_context.build_mode == BuildMode_Executable && build_context.reloc_mode == RelocMode_PIC) {
|
||||
@@ -670,6 +753,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
if (build_context.metrics.os != TargetOs_openbsd
|
||||
&& build_context.metrics.os != TargetOs_haiku
|
||||
&& build_context.metrics.arch != TargetArch_riscv64
|
||||
&& !is_android
|
||||
) {
|
||||
// OpenBSD and Haiku default to PIE executable. do not pass -no-pie for it.
|
||||
link_settings = gb_string_appendc(link_settings, "-no-pie ");
|
||||
@@ -701,6 +785,29 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
// This points the linker to where the entry point is
|
||||
link_settings = gb_string_appendc(link_settings, "-e _main ");
|
||||
}
|
||||
} else if (build_context.metrics.os == TargetOs_openbsd) {
|
||||
// OpenBSD ports install shared libraries in /usr/local/lib. Also, we must explicitly link libpthread.
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "-lpthread -Wl,-L/usr/local/lib ");
|
||||
// Until the LLVM back-end can be adapted to emit endbr64 instructions on amd64, we
|
||||
// need to pass -z nobtcfi in order to allow the resulting program to run under
|
||||
// OpenBSD 7.4 and newer. Once support is added at compile time, this can be dropped.
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "-Wl,-z,nobtcfi ");
|
||||
}
|
||||
|
||||
if (is_android) {
|
||||
GB_ASSERT(ODIN_ANDROID_NDK_TOOLCHAIN_LIB.len != 0);
|
||||
GB_ASSERT(ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL.len != 0);
|
||||
GB_ASSERT(ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT.len != 0);
|
||||
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "\"-L");
|
||||
platform_lib_str = gb_string_append_length(platform_lib_str, ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL.text, ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL.len);
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "\" ");
|
||||
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "\"--sysroot=");
|
||||
platform_lib_str = gb_string_append_length(platform_lib_str, ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT.text, ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT.len);
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "\" ");
|
||||
|
||||
link_settings = gb_string_appendc(link_settings, "-u ANativeActivity_onCreate ");
|
||||
}
|
||||
|
||||
if (!build_context.no_rpath) {
|
||||
@@ -709,24 +816,31 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
if (build_context.metrics.os == TargetOs_darwin) {
|
||||
link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,@loader_path ");
|
||||
} else {
|
||||
link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN ");
|
||||
if (is_android) {
|
||||
// ignore
|
||||
} else {
|
||||
link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!build_context.no_crt) {
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "-lm ");
|
||||
lib_str = gb_string_appendc(lib_str, "-lm ");
|
||||
if (build_context.metrics.os == TargetOs_darwin) {
|
||||
// NOTE: adding this causes a warning about duplicate libraries, I think it is
|
||||
// automatically assumed/added by clang when you don't do `-nostdlib`.
|
||||
// platform_lib_str = gb_string_appendc(platform_lib_str, "-lSystem ");
|
||||
// lib_str = gb_string_appendc(lib_str, "-lSystem ");
|
||||
} else {
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "-lc ");
|
||||
lib_str = gb_string_appendc(lib_str, "-lc ");
|
||||
}
|
||||
}
|
||||
|
||||
gbString link_command_line = gb_string_make(heap_allocator(), clang_path);
|
||||
defer (gb_string_free(link_command_line));
|
||||
|
||||
if (is_android) {
|
||||
link_command_line = gb_string_append_fmt(link_command_line, " --target=aarch64-linux-android%d ", ODIN_ANDROID_API_LEVEL);
|
||||
}
|
||||
link_command_line = gb_string_appendc(link_command_line, " -Wno-unused-command-line-argument ");
|
||||
link_command_line = gb_string_appendc(link_command_line, object_files);
|
||||
link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s\" ", LIT(output_filename));
|
||||
@@ -736,6 +850,11 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.extra_linker_flags));
|
||||
link_command_line = gb_string_append_fmt(link_command_line, " %s ", link_settings);
|
||||
|
||||
|
||||
if (is_android) {
|
||||
TIME_SECTION("Linking");
|
||||
}
|
||||
|
||||
if (build_context.linker_choice == Linker_lld) {
|
||||
link_command_line = gb_string_append_fmt(link_command_line, " -fuse-ld=lld");
|
||||
result = system_exec_command_line_app("lld-link", link_command_line);
|
||||
|
||||
+33
-12
@@ -1126,30 +1126,51 @@ gb_internal lbProcedure *lb_create_objc_names(lbModule *main_module) {
|
||||
return p;
|
||||
}
|
||||
|
||||
gb_internal void lb_finalize_objc_names(lbProcedure *p) {
|
||||
gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
|
||||
if (p == nullptr) {
|
||||
return;
|
||||
}
|
||||
lbModule *m = p->module;
|
||||
GB_ASSERT(m == &p->module->gen->default_module);
|
||||
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
StringSet handled = {};
|
||||
string_set_init(&handled);
|
||||
defer (string_set_destroy(&handled));
|
||||
|
||||
auto args = array_make<lbValue>(temporary_allocator(), 1);
|
||||
|
||||
LLVMSetLinkage(p->value, LLVMInternalLinkage);
|
||||
lb_begin_procedure_body(p);
|
||||
for (auto const &entry : m->objc_classes) {
|
||||
String name = entry.key;
|
||||
args[0] = lb_const_value(m, t_cstring, exact_value_string(name));
|
||||
lbValue ptr = lb_emit_runtime_call(p, "objc_lookUpClass", args);
|
||||
lb_addr_store(p, entry.value.local_module_addr, ptr);
|
||||
|
||||
auto register_thing = [&handled, &m, &args](lbProcedure *p, lbObjCGlobal const &g, char const *call) {
|
||||
if (!string_set_update(&handled, g.name)) {
|
||||
lbAddr addr = {};
|
||||
lbValue *found = string_map_get(&m->members, g.global_name);
|
||||
if (found) {
|
||||
addr = lb_addr(*found);
|
||||
} else {
|
||||
lbValue v = {};
|
||||
LLVMTypeRef t = lb_type(m, g.type);
|
||||
v.value = LLVMAddGlobal(m->mod, t, g.global_name);
|
||||
v.type = alloc_type_pointer(g.type);
|
||||
addr = lb_addr(v);
|
||||
LLVMSetInitializer(v.value, LLVMConstNull(t));
|
||||
}
|
||||
|
||||
args[0] = lb_const_value(m, t_cstring, exact_value_string(g.name));
|
||||
lbValue ptr = lb_emit_runtime_call(p, call, args);
|
||||
lb_addr_store(p, addr, ptr);
|
||||
}
|
||||
};
|
||||
|
||||
for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_classes, &g); /**/) {
|
||||
register_thing(p, g, "objc_lookUpClass");
|
||||
}
|
||||
|
||||
for (auto const &entry : m->objc_selectors) {
|
||||
String name = entry.key;
|
||||
args[0] = lb_const_value(m, t_cstring, exact_value_string(name));
|
||||
lbValue ptr = lb_emit_runtime_call(p, "sel_registerName", args);
|
||||
lb_addr_store(p, entry.value.local_module_addr, ptr);
|
||||
for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_selectors, &g); /**/) {
|
||||
register_thing(p, g, "sel_registerName");
|
||||
}
|
||||
|
||||
lb_end_procedure_body(p);
|
||||
@@ -2637,7 +2658,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
||||
|
||||
if (gen->objc_names) {
|
||||
TIME_SECTION("Finalize objc names");
|
||||
lb_finalize_objc_names(gen->objc_names);
|
||||
lb_finalize_objc_names(gen, gen->objc_names);
|
||||
}
|
||||
|
||||
if (build_context.ODIN_DEBUG) {
|
||||
|
||||
+12
-7
@@ -143,11 +143,6 @@ struct lbPadType {
|
||||
LLVMTypeRef type;
|
||||
};
|
||||
|
||||
struct lbObjcRef {
|
||||
Entity * entity;
|
||||
lbAddr local_module_addr;
|
||||
};
|
||||
|
||||
struct lbModule {
|
||||
LLVMModuleRef mod;
|
||||
LLVMContextRef ctx;
|
||||
@@ -198,8 +193,9 @@ struct lbModule {
|
||||
RecursiveMutex debug_values_mutex;
|
||||
PtrMap<void *, LLVMMetadataRef> debug_values;
|
||||
|
||||
StringMap<lbObjcRef> objc_classes;
|
||||
StringMap<lbObjcRef> objc_selectors;
|
||||
|
||||
StringMap<lbAddr> objc_classes;
|
||||
StringMap<lbAddr> objc_selectors;
|
||||
|
||||
PtrMap<u64/*type hash*/, lbAddr> map_cell_info_map; // address of runtime.Map_Info
|
||||
PtrMap<u64/*type hash*/, lbAddr> map_info_map; // address of runtime.Map_Cell_Info
|
||||
@@ -218,6 +214,13 @@ struct lbEntityCorrection {
|
||||
char const *cname;
|
||||
};
|
||||
|
||||
struct lbObjCGlobal {
|
||||
lbModule *module;
|
||||
gbString global_name;
|
||||
String name;
|
||||
Type * type;
|
||||
};
|
||||
|
||||
struct lbGenerator : LinkerData {
|
||||
CheckerInfo *info;
|
||||
|
||||
@@ -235,6 +238,8 @@ struct lbGenerator : LinkerData {
|
||||
lbProcedure *objc_names;
|
||||
|
||||
MPSCQueue<lbEntityCorrection> entities_to_correct_linkage;
|
||||
MPSCQueue<lbObjCGlobal> objc_selectors;
|
||||
MPSCQueue<lbObjCGlobal> objc_classes;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ gb_internal bool lb_is_elem_const(Ast *elem, Type *elem_type) {
|
||||
|
||||
gb_internal bool lb_is_const_nil(lbValue value) {
|
||||
LLVMValueRef v = value.value;
|
||||
if (LLVMIsConstant(v)) {
|
||||
if (v != nullptr && LLVMIsConstant(v)) {
|
||||
if (LLVMIsAConstantAggregateZero(v)) {
|
||||
return true;
|
||||
} else if (LLVMIsAConstantPointerNull(v)) {
|
||||
@@ -1125,10 +1125,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
|
||||
visited[index] = true;
|
||||
} else {
|
||||
if (!visited[index]) {
|
||||
values[index] = lb_const_value(m, f->type, {}, false).value;
|
||||
values[index] = lb_const_value(m, f->type, {}, /*allow_local*/false, is_rodata).value;
|
||||
visited[index] = true;
|
||||
}
|
||||
|
||||
|
||||
unsigned idx_list_len = cast(unsigned)sel.index.count-1;
|
||||
unsigned *idx_list = gb_alloc_array(temporary_allocator(), unsigned, idx_list_len);
|
||||
|
||||
@@ -1139,6 +1140,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
|
||||
i32 index = sel.index[j];
|
||||
Type *cvt = base_type(cv_type);
|
||||
|
||||
|
||||
if (cvt->kind == Type_Struct) {
|
||||
if (cvt->Struct.is_raw_union) {
|
||||
// sanity check which should have been caught by `lb_is_nested_possibly_constant`
|
||||
@@ -1164,8 +1166,40 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
|
||||
}
|
||||
if (is_constant) {
|
||||
LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, allow_local, is_rodata).value;
|
||||
if (LLVMIsConstant(elem_value)) {
|
||||
if (LLVMIsConstant(elem_value) && LLVMIsConstant(values[index])) {
|
||||
values[index] = llvm_const_insert_value(m, values[index], elem_value, idx_list, idx_list_len);
|
||||
} else if (is_local) {
|
||||
#if 1
|
||||
lbProcedure *p = m->curr_procedure;
|
||||
GB_ASSERT(p != nullptr);
|
||||
if (LLVMIsConstant(values[index])) {
|
||||
lbAddr addr = lb_add_local_generated(p, f->type, false);
|
||||
lb_addr_store(p, addr, lbValue{values[index], f->type});
|
||||
values[index] = lb_addr_load(p, addr).value;
|
||||
}
|
||||
|
||||
GB_ASSERT(LLVMIsALoadInst(values[index]));
|
||||
|
||||
LLVMValueRef ptr = LLVMGetOperand(values[index], 0);
|
||||
|
||||
LLVMValueRef *indices = gb_alloc_array(temporary_allocator(), LLVMValueRef, idx_list_len);
|
||||
LLVMTypeRef lt_u32 = lb_type(m, t_u32);
|
||||
for (unsigned i = 0; i < idx_list_len; i++) {
|
||||
indices[i] = LLVMConstInt(lt_u32, idx_list[i], false);
|
||||
}
|
||||
|
||||
ptr = LLVMBuildGEP2(p->builder, lb_type(m, f->type), ptr, indices, idx_list_len, "");
|
||||
ptr = LLVMBuildPointerCast(p->builder, ptr, lb_type(m, alloc_type_pointer(tav.type)), "");
|
||||
|
||||
if (LLVMIsALoadInst(elem_value)) {
|
||||
i64 sz = type_size_of(tav.type);
|
||||
LLVMValueRef src = LLVMGetOperand(elem_value, 0);
|
||||
lb_mem_copy_non_overlapping(p, {ptr, t_rawptr}, {src, t_rawptr}, lb_const_int(m, t_int, sz), false);
|
||||
} else {
|
||||
LLVMBuildStore(p->builder, elem_value, ptr);
|
||||
}
|
||||
#endif
|
||||
is_constant = false;
|
||||
} else {
|
||||
is_constant = false;
|
||||
}
|
||||
@@ -1205,7 +1239,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
|
||||
LLVMValueRef val = values[i];
|
||||
if (!LLVMIsConstant(val)) {
|
||||
GB_ASSERT(is_local);
|
||||
GB_ASSERT(LLVMGetInstructionOpcode(val) == LLVMLoad);
|
||||
GB_ASSERT(LLVMIsALoadInst(val));
|
||||
is_constant = false;
|
||||
}
|
||||
}
|
||||
@@ -1237,7 +1271,15 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
|
||||
LLVMValueRef val = old_values[i];
|
||||
if (!LLVMIsConstant(val)) {
|
||||
LLVMValueRef dst = LLVMBuildStructGEP2(p->builder, llvm_addr_type(p->module, v.addr), v.addr.value, cast(unsigned)i, "");
|
||||
// if (LLVMIsALoadInst(val)) {
|
||||
// Type *ptr_type = v.addr.type;
|
||||
// i64 sz = type_size_of(type_deref(ptr_type));
|
||||
|
||||
// LLVMValueRef src = LLVMGetOperand(val, 0);
|
||||
// lb_mem_copy_non_overlapping(p, {dst, ptr_type}, {src, ptr_type}, lb_const_int(m, t_int, sz), false);
|
||||
// } else {
|
||||
LLVMBuildStore(p->builder, val, dst);
|
||||
// }
|
||||
}
|
||||
}
|
||||
return lb_addr_load(p, v);
|
||||
|
||||
@@ -1089,7 +1089,7 @@ gb_internal void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, T
|
||||
#if LLVM_VERSION_MAJOR <= 18
|
||||
LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block);
|
||||
#else
|
||||
LLVMDIBuilderInsertDbgValueRecordAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block);
|
||||
LLVMDIBuilderInsertDeclareRecordAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -3493,7 +3493,8 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
|
||||
if (tv.value.kind != ExactValue_Invalid) {
|
||||
// NOTE(bill): Short on constant values
|
||||
return lb_const_value(p->module, type, tv.value);
|
||||
bool allow_local = true;
|
||||
return lb_const_value(p->module, type, tv.value, allow_local);
|
||||
} else if (tv.mode == Addressing_Type) {
|
||||
// NOTE(bill, 2023-01-16): is this correct? I hope so at least
|
||||
return lb_typeid(m, tv.type);
|
||||
|
||||
@@ -171,6 +171,8 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) {
|
||||
}
|
||||
|
||||
mpsc_init(&gen->entities_to_correct_linkage, heap_allocator());
|
||||
mpsc_init(&gen->objc_selectors, heap_allocator());
|
||||
mpsc_init(&gen->objc_classes, heap_allocator());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2972,6 +2972,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
constraints = gb_string_appendc(constraints, "}");
|
||||
}
|
||||
|
||||
constraints = gb_string_appendc(constraints, ",~{memory}");
|
||||
|
||||
inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints));
|
||||
}
|
||||
break;
|
||||
@@ -3034,6 +3036,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
constraints = gb_string_appendc(constraints, "}");
|
||||
}
|
||||
|
||||
constraints = gb_string_appendc(constraints, ",~{memory}");
|
||||
|
||||
inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints));
|
||||
}
|
||||
break;
|
||||
@@ -3059,6 +3063,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
constraints = gb_string_appendc(constraints, "}");
|
||||
}
|
||||
|
||||
constraints = gb_string_appendc(constraints, ",~{memory}");
|
||||
|
||||
inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints));
|
||||
} else {
|
||||
char asm_string[] = "svc #0";
|
||||
@@ -3078,6 +3084,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
constraints = gb_string_appendc(constraints, "}");
|
||||
}
|
||||
|
||||
constraints = gb_string_appendc(constraints, ",~{memory}");
|
||||
|
||||
inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints));
|
||||
}
|
||||
}
|
||||
@@ -3104,6 +3112,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
constraints = gb_string_appendc(constraints, "}");
|
||||
}
|
||||
|
||||
constraints = gb_string_appendc(constraints, ",~{memory}");
|
||||
|
||||
inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2094,41 +2094,65 @@ gb_internal void lb_set_wasm_export_attributes(LLVMValueRef value, String export
|
||||
}
|
||||
|
||||
|
||||
|
||||
gb_internal lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &name) {
|
||||
lbObjcRef *found = string_map_get(&p->module->objc_selectors, name);
|
||||
lbModule *m = p->module;
|
||||
lbAddr *found = string_map_get(&m->objc_selectors, name);
|
||||
if (found) {
|
||||
return found->local_module_addr;
|
||||
return *found;
|
||||
}
|
||||
|
||||
lbModule *default_module = &p->module->gen->default_module;
|
||||
Entity *entity = {};
|
||||
|
||||
if (default_module != p->module) {
|
||||
found = string_map_get(&default_module->objc_selectors, name);
|
||||
if (found) {
|
||||
entity = found->entity;
|
||||
}
|
||||
gbString global_name = gb_string_make(permanent_allocator(), "__$objc_SEL::");
|
||||
global_name = gb_string_append_length(global_name, name.text, name.len);
|
||||
|
||||
LLVMTypeRef t = lb_type(m, t_objc_SEL);
|
||||
lbValue g = {};
|
||||
g.value = LLVMAddGlobal(m->mod, t, global_name);
|
||||
g.type = alloc_type_pointer(t_objc_SEL);
|
||||
|
||||
if (default_module == m) {
|
||||
LLVMSetInitializer(g.value, LLVMConstNull(t));
|
||||
lb_add_member(m, make_string_c(global_name), g);
|
||||
} else {
|
||||
LLVMSetLinkage(g.value, LLVMExternalLinkage);
|
||||
}
|
||||
|
||||
if (!entity) {
|
||||
gbString global_name = gb_string_make(permanent_allocator(), "__$objc_SEL::");
|
||||
global_name = gb_string_append_length(global_name, name.text, name.len);
|
||||
mpsc_enqueue(&m->gen->objc_selectors, lbObjCGlobal{m, global_name, name, t_objc_SEL});
|
||||
|
||||
lbAddr default_addr = lb_add_global_generated_with_name(default_module, t_objc_SEL, {},
|
||||
make_string(cast(u8 const *)global_name, gb_string_length(global_name)),
|
||||
&entity);
|
||||
string_map_set(&default_module->objc_selectors, name, lbObjcRef{entity, default_addr});
|
||||
lbAddr addr = lb_addr(g);
|
||||
string_map_set(&m->objc_selectors, name, addr);
|
||||
return addr;
|
||||
}
|
||||
|
||||
gb_internal lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name) {
|
||||
lbModule *m = p->module;
|
||||
lbAddr *found = string_map_get(&m->objc_classes, name);
|
||||
if (found) {
|
||||
return *found;
|
||||
}
|
||||
|
||||
lbValue ptr = lb_find_value_from_entity(p->module, entity);
|
||||
lbAddr local_addr = lb_addr(ptr);
|
||||
lbModule *default_module = &p->module->gen->default_module;
|
||||
|
||||
if (default_module != p->module) {
|
||||
string_map_set(&p->module->objc_selectors, name, lbObjcRef{entity, local_addr});
|
||||
gbString global_name = gb_string_make(permanent_allocator(), "__$objc_Class::");
|
||||
global_name = gb_string_append_length(global_name, name.text, name.len);
|
||||
|
||||
LLVMTypeRef t = lb_type(m, t_objc_Class);
|
||||
lbValue g = {};
|
||||
g.value = LLVMAddGlobal(m->mod, t, global_name);
|
||||
g.type = alloc_type_pointer(t_objc_Class);
|
||||
|
||||
if (default_module == m) {
|
||||
LLVMSetInitializer(g.value, LLVMConstNull(t));
|
||||
lb_add_member(m, make_string_c(global_name), g);
|
||||
} else {
|
||||
LLVMSetLinkage(g.value, LLVMExternalLinkage);
|
||||
}
|
||||
mpsc_enqueue(&m->gen->objc_classes, lbObjCGlobal{m, global_name, name, t_objc_Class});
|
||||
|
||||
return local_addr;
|
||||
lbAddr addr = lb_addr(g);
|
||||
string_map_set(&m->objc_classes, name, addr);
|
||||
return addr;
|
||||
}
|
||||
|
||||
gb_internal lbValue lb_handle_objc_find_selector(lbProcedure *p, Ast *expr) {
|
||||
@@ -2157,41 +2181,6 @@ gb_internal lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr)
|
||||
return lb_addr_load(p, dst);
|
||||
}
|
||||
|
||||
gb_internal lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name) {
|
||||
lbObjcRef *found = string_map_get(&p->module->objc_classes, name);
|
||||
if (found) {
|
||||
return found->local_module_addr;
|
||||
}
|
||||
|
||||
lbModule *default_module = &p->module->gen->default_module;
|
||||
Entity *entity = {};
|
||||
|
||||
if (default_module != p->module) {
|
||||
found = string_map_get(&default_module->objc_classes, name);
|
||||
if (found) {
|
||||
entity = found->entity;
|
||||
}
|
||||
}
|
||||
|
||||
if (!entity) {
|
||||
gbString global_name = gb_string_make(permanent_allocator(), "__$objc_Class::");
|
||||
global_name = gb_string_append_length(global_name, name.text, name.len);
|
||||
|
||||
lbAddr default_addr = lb_add_global_generated_with_name(default_module, t_objc_Class, {},
|
||||
make_string(cast(u8 const *)global_name, gb_string_length(global_name)),
|
||||
&entity);
|
||||
string_map_set(&default_module->objc_classes, name, lbObjcRef{entity, default_addr});
|
||||
}
|
||||
|
||||
lbValue ptr = lb_find_value_from_entity(p->module, entity);
|
||||
lbAddr local_addr = lb_addr(ptr);
|
||||
|
||||
if (default_module != p->module) {
|
||||
string_map_set(&p->module->objc_classes, name, lbObjcRef{entity, local_addr});
|
||||
}
|
||||
|
||||
return local_addr;
|
||||
}
|
||||
|
||||
gb_internal lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) {
|
||||
ast_node(ce, CallExpr, expr);
|
||||
|
||||
+70
-11
@@ -74,6 +74,7 @@ gb_global Timings global_timings = {0};
|
||||
#include "cached.cpp"
|
||||
|
||||
#include "linker.cpp"
|
||||
#include "bundle_command.cpp"
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS) && defined(ODIN_TILDE_BACKEND)
|
||||
#define ALLOW_TILDE 1
|
||||
@@ -408,6 +409,10 @@ enum BuildFlagKind {
|
||||
BuildFlag_Subsystem,
|
||||
#endif
|
||||
|
||||
BuildFlag_AndroidKeystore,
|
||||
BuildFlag_AndroidKeystoreAlias,
|
||||
BuildFlag_AndroidManifest,
|
||||
|
||||
BuildFlag_COUNT,
|
||||
};
|
||||
|
||||
@@ -426,12 +431,12 @@ struct BuildFlag {
|
||||
BuildFlagKind kind;
|
||||
String name;
|
||||
BuildFlagParamKind param_kind;
|
||||
u32 command_support;
|
||||
u64 command_support;
|
||||
bool allow_multiple;
|
||||
};
|
||||
|
||||
|
||||
gb_internal void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind, u32 command_support, bool allow_multiple=false) {
|
||||
gb_internal void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind, u64 command_support, bool allow_multiple=false) {
|
||||
BuildFlag flag = {kind, name, param_kind, command_support, allow_multiple};
|
||||
array_add(build_flags, flag);
|
||||
}
|
||||
@@ -567,7 +572,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_TargetFeatures, str_lit("target-features"), BuildFlagParam_String, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_StrictTargetFeatures, str_lit("strict-target-features"), BuildFlagParam_None, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_MinimumOSVersion, str_lit("minimum-os-version"), BuildFlagParam_String, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_MinimumOSVersion, str_lit("minimum-os-version"), BuildFlagParam_String, Command__does_build | Command_bundle_android);
|
||||
|
||||
add_flag(&build_flags, BuildFlag_RelocMode, str_lit("reloc-mode"), BuildFlagParam_String, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_DisableRedZone, str_lit("disable-red-zone"), BuildFlagParam_None, Command__does_build);
|
||||
@@ -624,9 +629,20 @@ 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_bundle_android);
|
||||
add_flag(&build_flags, BuildFlag_AndroidKeystoreAlias, str_lit("android-keystore-alias"), BuildFlagParam_String, Command_bundle_android);
|
||||
add_flag(&build_flags, BuildFlag_AndroidManifest, str_lit("android-manifest"), BuildFlagParam_String, Command_bundle_android);
|
||||
|
||||
GB_ASSERT(args.count >= 3);
|
||||
Array<String> flag_args = array_slice(args, 3, args.count);
|
||||
|
||||
Array<String> flag_args = {};
|
||||
|
||||
if (build_context.command_kind == Command_bundle_android) {
|
||||
GB_ASSERT(args.count >= 4);
|
||||
flag_args = array_slice(args, 4, args.count);
|
||||
} else {
|
||||
GB_ASSERT(args.count >= 3);
|
||||
flag_args = array_slice(args, 3, args.count);
|
||||
}
|
||||
|
||||
bool set_flags[BuildFlag_COUNT] = {};
|
||||
|
||||
@@ -1105,8 +1121,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
String str = value.value_string;
|
||||
bool found = false;
|
||||
|
||||
if (selected_target_metrics->metrics->os != TargetOs_darwin) {
|
||||
gb_printf_err("-subtarget can only be used with darwin based targets at the moment\n");
|
||||
if (selected_target_metrics->metrics->os != TargetOs_darwin &&
|
||||
selected_target_metrics->metrics->os != TargetOs_linux ) {
|
||||
gb_printf_err("-subtarget can only be used with darwin and linux based targets at the moment\n");
|
||||
bad_flags = true;
|
||||
break;
|
||||
}
|
||||
@@ -1637,6 +1654,20 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
}
|
||||
#endif
|
||||
|
||||
case BuildFlag_AndroidKeystore:
|
||||
GB_ASSERT(value.kind == ExactValue_String);
|
||||
build_context.android_keystore = value.value_string;
|
||||
break;
|
||||
|
||||
case BuildFlag_AndroidKeystoreAlias:
|
||||
GB_ASSERT(value.kind == ExactValue_String);
|
||||
build_context.android_keystore_alias = value.value_string;
|
||||
break;
|
||||
|
||||
case BuildFlag_AndroidManifest:
|
||||
GB_ASSERT(value.kind == ExactValue_String);
|
||||
build_context.android_manifest = value.value_string;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1652,8 +1683,8 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
gb_printf_err("'%.*s' is supported with the following commands:\n", LIT(name));
|
||||
gb_printf_err("\t");
|
||||
i32 count = 0;
|
||||
for (u32 i = 0; i < 32; i++) {
|
||||
if (found_bf.command_support & (1<<i)) {
|
||||
for (u64 i = 0; i < 64; i++) {
|
||||
if (found_bf.command_support & (1ull<<i)) {
|
||||
if (count > 0) {
|
||||
gb_printf_err(", ");
|
||||
}
|
||||
@@ -2236,6 +2267,10 @@ 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 == "bundle") {
|
||||
print_usage_line(1, "bundle <platform> Bundles a directory in a specific layout for that platform");
|
||||
print_usage_line(2, "Supported platforms:");
|
||||
print_usage_line(3, "android");
|
||||
}
|
||||
|
||||
bool doc = command == "doc";
|
||||
@@ -2245,6 +2280,7 @@ gb_internal void print_show_help(String const arg0, String command, String optio
|
||||
bool strip_semicolon = command == "strip-semicolon";
|
||||
bool check_only = command == "check" || strip_semicolon;
|
||||
bool check = run_or_build || check_only;
|
||||
bool bundle = command == "bundle";
|
||||
|
||||
if (command == "help") {
|
||||
doc = true;
|
||||
@@ -2512,13 +2548,15 @@ gb_internal void print_show_help(String const arg0, String command, String optio
|
||||
}
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
if (run_or_build || bundle) {
|
||||
if (print_flag("-minimum-os-version:<string>")) {
|
||||
print_usage_line(2, "Sets the minimum OS version targeted by the application.");
|
||||
print_usage_line(2, "Default: -minimum-os-version:11.0.0");
|
||||
print_usage_line(2, "Only used when target is Darwin, if given, linking mismatched versions will emit a warning.");
|
||||
}
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
if (print_flag("-no-bounds-check")) {
|
||||
print_usage_line(2, "Disables bounds checking program wide.");
|
||||
}
|
||||
@@ -3299,6 +3337,19 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
print_show_help(args[0], args[1], args[2]);
|
||||
return 0;
|
||||
}
|
||||
} else if (command == "bundle") {
|
||||
if (args.count < 4) {
|
||||
usage(args[0]);
|
||||
return 1;
|
||||
}
|
||||
if (args[2] == "android") {
|
||||
build_context.command_kind = Command_bundle_android;
|
||||
} else {
|
||||
gb_printf_err("Unknown package command: '%.*s'\n", LIT(args[2]));
|
||||
usage(args[0]);
|
||||
return 1;
|
||||
}
|
||||
init_filename = args[3];
|
||||
} else if (command == "root") {
|
||||
gb_printf("%.*s", LIT(odin_root_dir()));
|
||||
return 0;
|
||||
@@ -3333,10 +3384,14 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
}
|
||||
|
||||
if (!single_file_package) {
|
||||
gb_printf_err("ERROR: `%.*s %.*s` takes a package as its first argument.\n", LIT(args[0]), LIT(command));
|
||||
gb_printf_err("ERROR: `%.*s %.*s` takes a package/directory as its first argument.\n", LIT(args[0]), LIT(command));
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -3370,6 +3425,10 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (command == "bundle") {
|
||||
return bundle(init_filename);
|
||||
}
|
||||
|
||||
// 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"),
|
||||
|
||||
+64
-12
@@ -30,28 +30,80 @@ gb_internal String remove_directory_from_path(String const &s) {
|
||||
}
|
||||
|
||||
|
||||
// NOTE(Mark Naughton): getcwd as String
|
||||
#if !defined(GB_SYSTEM_WINDOWS)
|
||||
gb_internal String get_current_directory(void) {
|
||||
char cwd[256];
|
||||
getcwd(cwd, 256);
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
gb_global SRWLOCK cwd_lock;
|
||||
|
||||
return make_string_c(cwd);
|
||||
String get_working_directory(gbAllocator allocator) {
|
||||
AcquireSRWLockExclusive(&cwd_lock);
|
||||
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
DWORD sz_utf16 = GetCurrentDirectoryW(0, nullptr);
|
||||
wchar_t *dir_buf_wstr = gb_alloc_array(temporary_allocator(), wchar_t, sz_utf16);
|
||||
if (dir_buf_wstr == nullptr) {
|
||||
ReleaseSRWLockExclusive(&cwd_lock);
|
||||
return {};
|
||||
}
|
||||
|
||||
DWORD n = GetCurrentDirectoryW(sz_utf16, dir_buf_wstr);
|
||||
GB_ASSERT(n+1 == sz_utf16);
|
||||
ReleaseSRWLockExclusive(&cwd_lock);
|
||||
|
||||
|
||||
isize buf_len = sz_utf16*4;
|
||||
u8 *buf = gb_alloc_array(allocator, u8, buf_len);
|
||||
gb_ucs2_to_utf8(buf, buf_len, cast(u16 *)dir_buf_wstr);
|
||||
|
||||
return make_string_c(cast(char const *)buf);
|
||||
}
|
||||
|
||||
bool set_working_directory(String dir) {
|
||||
bool ok = false;
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
char const *cdir = alloc_cstring(temporary_allocator(), dir);
|
||||
wchar_t *wstr = gb__alloc_utf8_to_ucs2(temporary_allocator(), cdir, nullptr);
|
||||
|
||||
AcquireSRWLockExclusive(&cwd_lock);
|
||||
|
||||
ok = SetCurrentDirectoryW(wstr);
|
||||
|
||||
ReleaseSRWLockExclusive(&cwd_lock);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
#else
|
||||
gb_internal String get_current_directory(void) {
|
||||
gbAllocator a = heap_allocator();
|
||||
|
||||
wchar_t cwd[256];
|
||||
GetCurrentDirectoryW(256, cwd);
|
||||
String get_working_directory(gbAllocator allocator) {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
String16 wstr = make_string16_c(cwd);
|
||||
auto buf = array_make<char>(temporary_allocator());
|
||||
size_t size = PATH_MAX;
|
||||
|
||||
return string16_to_string(a, wstr);
|
||||
char const *cwd;
|
||||
for (; cwd == nullptr; size *= 2) {
|
||||
array_resize(&buf, size);
|
||||
|
||||
cwd = getcwd(buf.data, buf.count);
|
||||
if (cwd == nullptr && errno != ERANGE) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return copy_string(allocator, make_string_c(cwd));
|
||||
}
|
||||
|
||||
bool set_working_directory(String dir) {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
char const *cdir = alloc_cstring(temporary_allocator(), dir);
|
||||
return !chdir(cdir);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
gb_internal bool path_is_directory(String path);
|
||||
|
||||
gb_internal String directory_from_path(String const &s) {
|
||||
|
||||
@@ -273,6 +273,15 @@ gb_internal String path_extension(String const &str, bool include_dot = true) {
|
||||
return substring(str, include_dot ? pos : pos + 1, str.len);
|
||||
}
|
||||
|
||||
|
||||
gb_internal String path_remove_extension(String const &str) {
|
||||
isize pos = string_extension_position(str);
|
||||
if (pos < 0) {
|
||||
return str;
|
||||
}
|
||||
return substring(str, 0, pos);
|
||||
}
|
||||
|
||||
gb_internal String string_trim_whitespace(String str) {
|
||||
while (str.len > 0 && rune_is_whitespace(str[str.len-1])) {
|
||||
str.len--;
|
||||
|
||||
Reference in New Issue
Block a user