aboutsummaryrefslogtreecommitdiff
path: root/src/linker.cpp
diff options
context:
space:
mode:
authorCourtney Strachan <courtney.strachan@gmail.com>2025-10-06 02:41:44 +0100
committerGitHub <noreply@github.com>2025-10-06 02:41:44 +0100
commit6de2d6e8ca687c989bbb7806e5cbe8d791e425bf (patch)
tree03a2e0a84c7c1530215f8e3f59a7f643b39b3677 /src/linker.cpp
parentdbbe96ae5c343f0e803de6ee508207a62571534f (diff)
parent0f97382fa3e46da80705c00dfe02f3deb9562e4f (diff)
Merge branch 'odin-lang:master' into master
Diffstat (limited to 'src/linker.cpp')
-rw-r--r--src/linker.cpp362
1 files changed, 297 insertions, 65 deletions
diff --git a/src/linker.cpp b/src/linker.cpp
index cf2ef638d..f1e0335d5 100644
--- a/src/linker.cpp
+++ b/src/linker.cpp
@@ -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",
@@ -146,32 +143,50 @@ gb_internal i32 linker_stage(LinkerData *gen) {
LIT(target_arch_names[build_context.metrics.arch])
);
#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;
+ } else if (build_context.cross_compiling && (build_context.different_os || selected_subtarget != Subtarget_Default)) {
+ 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;
+ String section_name = str_lit("msvc-link");
+ bool is_windows = build_context.metrics.os == TargetOs_windows;
#else
+ String section_name = str_lit("lld-link");
bool is_windows = false;
#endif
- #if defined(GB_SYSTEM_OSX)
- bool is_osx = true;
- #else
- bool is_osx = false;
+
+ bool is_osx = build_context.metrics.os == TargetOs_darwin;
+
+
+ switch (build_context.linker_choice) {
+ case Linker_Default: break;
+ case Linker_lld: section_name = str_lit("lld-link"); break;
+ #if defined(GB_SYSTEM_LINUX)
+ case Linker_mold: section_name = str_lit("mold-link"); break;
#endif
+ #if defined(GB_SYSTEM_WINDOWS)
+ case Linker_radlink: section_name = str_lit("rad-link"); break;
+ #endif
+ default:
+ gb_printf_err("'%.*s' linker is not support for this platform\n", LIT(linker_choices[build_context.linker_choice]));
+ return 1;
+ }
if (is_windows) {
- String section_name = str_lit("msvc-link");
- switch (build_context.linker_choice) {
- case Linker_Default: break;
- case Linker_lld: section_name = str_lit("lld-link"); break;
- case Linker_radlink: section_name = str_lit("rad-link"); break;
- }
timings_start_section(timings, section_name);
gbString lib_str = gb_string_make(heap_allocator(), "");
@@ -273,13 +288,20 @@ gb_internal i32 linker_stage(LinkerData *gen) {
if (build_context.build_mode == BuildMode_DynamicLibrary) {
link_settings = gb_string_append_fmt(link_settings, " /DLL");
+ if (build_context.no_entry_point) {
+ link_settings = gb_string_append_fmt(link_settings, " /NOENTRY");
+ }
} else {
- link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup");
+ // For i386 with CRT, libcmt provides the entry point
+ // For other cases or no_crt, we need to specify the entry point
+ if (!(build_context.metrics.arch == TargetArch_i386 && !build_context.no_crt)) {
+ link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup");
+ }
}
- if (build_context.pdb_filepath != "") {
- String pdb_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_PDB]);
- link_settings = gb_string_append_fmt(link_settings, " /PDB:\"%.*s\"", LIT(pdb_path));
+ if (build_context.build_paths[BuildPath_Symbols].name != "") {
+ String symbol_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Symbols]);
+ link_settings = gb_string_append_fmt(link_settings, " /PDB:\"%.*s\"", LIT(symbol_path));
}
if (build_context.build_mode != BuildMode_StaticLibrary) {
@@ -317,7 +339,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
"",
LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename),
link_settings,
- LIT(build_context.ODIN_WINDOWS_SUBSYSTEM),
+ LIT(windows_subsystem_names[build_context.ODIN_WINDOWS_SUBSYSTEM]),
LIT(build_context.link_flags),
LIT(build_context.extra_linker_flags),
lib_str
@@ -337,7 +359,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
"",
LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename),
link_settings,
- LIT(build_context.ODIN_WINDOWS_SUBSYSTEM),
+ LIT(windows_subsystem_names[build_context.ODIN_WINDOWS_SUBSYSTEM]),
LIT(build_context.link_flags),
LIT(build_context.extra_linker_flags),
lib_str
@@ -400,7 +422,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
"",
LIT(vs_exe_path), LIT(linker_name), object_files, LIT(res_path), LIT(output_filename),
link_settings,
- LIT(build_context.ODIN_WINDOWS_SUBSYSTEM),
+ LIT(windows_subsystem_names[build_context.ODIN_WINDOWS_SUBSYSTEM]),
LIT(build_context.link_flags),
LIT(build_context.extra_linker_flags),
lib_str
@@ -412,25 +434,32 @@ gb_internal i32 linker_stage(LinkerData *gen) {
}
}
} else {
- timings_start_section(timings, str_lit("ld-link"));
+
+ timings_start_section(timings, section_name);
+
+ 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());
+ bool has_odin_clang_path_env = true;
if (clang_path == NULL) {
clang_path = "clang";
+ has_odin_clang_path_env = false;
}
- // 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 +525,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");
- } else {
- obj_format = str_lit("elf64");
- }
- #elif defined(GB_ARCH_32_BIT)
- if (is_osx) {
- obj_format = str_lit("macho32");
+ 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("elf32");
+ GB_ASSERT(build_context.metrics.ptr_size == 4);
+ 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",
@@ -579,7 +609,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
// Do not add libc again, this is added later already, and omitted with
// the `-no-crt` flag, not skipping here would cause duplicate library
// warnings when linking on darwin and might link libc silently even with `-no-crt`.
- if (lib == str_lit("System.framework") || lib == str_lit("c")) {
+ if (lib == str_lit("System.framework") || lib == str_lit("System") || lib == str_lit("c")) {
continue;
}
@@ -594,7 +624,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
// object
// dynamic lib
// static libs, absolute full path relative to the file in which the lib was imported from
- lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
+ lib_str = gb_string_append_fmt(lib_str, " \"%.*s\" ", LIT(lib));
} else {
// dynamic or static system lib, just link regularly searching system library paths
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
@@ -618,8 +648,86 @@ 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_length(heap_allocator(), ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len);
+ defer (gb_string_free(glue));
+
+ glue = gb_string_append_fmt(glue, "bin/clang");
+ 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, "--sysroot \"");
+ glue = gb_string_append_length(glue, ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len);
+ glue = gb_string_appendc(glue, "sysroot");
+ 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));
+ object_files = gb_string_append_fmt(object_files, "\'%.*s\' ", LIT(object_path));
}
gbString link_settings = gb_string_make_reserve(heap_allocator(), 32);
@@ -661,7 +769,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 +780,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 ");
@@ -679,7 +790,65 @@ gb_internal i32 linker_stage(LinkerData *gen) {
gbString platform_lib_str = gb_string_make(heap_allocator(), "");
defer (gb_string_free(platform_lib_str));
if (build_context.metrics.os == TargetOs_darwin) {
- platform_lib_str = gb_string_appendc(platform_lib_str, "-Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib ");
+ // Get the SDK path.
+ gbString darwin_sdk_path = gb_string_make(temporary_allocator(), "");
+
+ char const* darwin_platform_name = "MacOSX";
+ char const* darwin_xcrun_sdk_name = "macosx";
+ char const* darwin_min_version_id = "macosx";
+
+ const char* original_clang_path = clang_path;
+
+ // NOTE(harold): We set the clang_path to run through xcrun because otherwise it complaints about the the sysroot
+ // being set to 'MacOSX' even though we've set the sysroot to the correct SDK (-Wincompatible-sysroot).
+ // This is because it is likely not using the SDK's toolchain Apple Clang but another one installed in the system.
+ switch (selected_subtarget) {
+ case Subtarget_iPhone:
+ darwin_platform_name = "iPhoneOS";
+ darwin_xcrun_sdk_name = "iphoneos";
+ darwin_min_version_id = "ios";
+ if (!has_odin_clang_path_env) {
+ clang_path = "xcrun --sdk iphoneos clang";
+ }
+ break;
+ case Subtarget_iPhoneSimulator:
+ darwin_platform_name = "iPhoneSimulator";
+ darwin_xcrun_sdk_name = "iphonesimulator";
+ darwin_min_version_id = "ios-simulator";
+ if (!has_odin_clang_path_env) {
+ clang_path = "xcrun --sdk iphonesimulator clang";
+ }
+ break;
+ }
+
+ gbString darwin_find_sdk_cmd = gb_string_make(temporary_allocator(), "");
+ darwin_find_sdk_cmd = gb_string_append_fmt(darwin_find_sdk_cmd, "xcrun --sdk %s --show-sdk-path", darwin_xcrun_sdk_name);
+
+ if (!system_exec_command_line_app_output(darwin_find_sdk_cmd, &darwin_sdk_path)) {
+
+ // Fallback to default clang, since `xcrun --sdk` did not work.
+ clang_path = original_clang_path;
+
+ // Best-effort fallback to known locations
+ gbString darwin_sdk_path = gb_string_make(temporary_allocator(), "");
+ darwin_sdk_path = gb_string_append_fmt(darwin_sdk_path, "/Library/Developer/CommandLineTools/SDKs/%s.sdk", darwin_platform_name);
+
+ if (!path_is_directory(make_string_c(darwin_sdk_path))) {
+ gb_string_clear(darwin_sdk_path);
+ darwin_sdk_path = gb_string_append_fmt(darwin_sdk_path, "/Applications/Xcode.app/Contents/Developer/Platforms/%s.platform/Developer/SDKs/%s.sdk", darwin_platform_name);
+
+ if (!path_is_directory(make_string_c(darwin_sdk_path))) {
+ gb_printf_err("Failed to find %s SDK\n", darwin_platform_name);
+ return -1;
+ }
+ }
+ } else {
+ // Trim the trailing newline.
+ darwin_sdk_path = gb_string_trim_space(darwin_sdk_path);
+ }
+ platform_lib_str = gb_string_append_fmt(platform_lib_str, "--sysroot %s ", darwin_sdk_path);
+
+ platform_lib_str = gb_string_appendc(platform_lib_str, "-L/usr/local/lib ");
// Homebrew's default library path, checking if it exists to avoid linking warnings.
if (gb_file_exists("/opt/homebrew/lib")) {
@@ -693,14 +862,57 @@ gb_internal i32 linker_stage(LinkerData *gen) {
// Only specify this flag if the user has given a minimum version to target.
// This will cause warnings to show up for mismatched libraries.
- if (build_context.minimum_os_version_string_given) {
- link_settings = gb_string_append_fmt(link_settings, "-mmacosx-version-min=%.*s ", LIT(build_context.minimum_os_version_string));
+ // NOTE(harold): For device subtargets we have to explicitly set the default version to
+ // avoid the same warning since we configure our own minimum version when compiling for devices.
+ if (build_context.minimum_os_version_string_given || selected_subtarget != Subtarget_Default) {
+ link_settings = gb_string_append_fmt(link_settings, "-m%s-version-min=%.*s ", darwin_min_version_id, LIT(build_context.minimum_os_version_string));
}
if (build_context.build_mode != BuildMode_DynamicLibrary) {
// 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_freebsd) {
+ if (build_context.sanitizer_flags & (SanitizerFlag_Address | SanitizerFlag_Memory)) {
+ // It's imperative that `pthread` is linked before `libc`,
+ // otherwise ASan/MSan will be unable to call `pthread_key_create`
+ // because FreeBSD's `libthr` implementation of `pthread`
+ // needs to replace the relevant stubs first.
+ //
+ // (Presumably TSan implements its own `pthread` interface,
+ // which is why it isn't required.)
+ //
+ // See: https://reviews.llvm.org/D39254
+ platform_lib_str = gb_string_appendc(platform_lib_str, "-lpthread ");
+ }
+ // FreeBSD pkg installs third-party shared libraries in /usr/local/lib.
+ platform_lib_str = gb_string_appendc(platform_lib_str, "-Wl,-L/usr/local/lib ");
+ } 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, "-landroid ");
+ platform_lib_str = gb_string_appendc(platform_lib_str, "-llog ");
+
+ 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 +921,36 @@ 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);
+ gbString link_command_line = gb_string_make(heap_allocator(), "");
defer (gb_string_free(link_command_line));
+ if (is_android) {
+ gbString ndk_bin_directory = gb_string_make_length(temporary_allocator(), ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len);
+ link_command_line = gb_string_appendc(link_command_line, ndk_bin_directory);
+ link_command_line = gb_string_appendc(link_command_line, "bin/clang");
+ link_command_line = gb_string_append_fmt(link_command_line, " --target=aarch64-linux-android%d ", ODIN_ANDROID_API_LEVEL);
+ } else {
+ link_command_line = gb_string_appendc(link_command_line, clang_path);
+ }
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,9 +960,17 @@ 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);
+ } else if (build_context.linker_choice == Linker_mold) {
+ link_command_line = gb_string_append_fmt(link_command_line, " -fuse-ld=mold");
+ result = system_exec_command_line_app("mold-link", link_command_line);
} else {
result = system_exec_command_line_app("ld-link", link_command_line);
}