From 1a7c1d107a26df00bc6c9379178fccb55569b667 Mon Sep 17 00:00:00 2001 From: Laytan Date: Wed, 4 Sep 2024 22:18:55 +0200 Subject: [PATCH 1/3] set -rpath to \$ORIGIN and expect libraries next to executable just like Windows --- src/linker.cpp | 14 ++++++++------ src/parser.cpp | 14 -------------- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/linker.cpp b/src/linker.cpp index faca28932..25b9cfdc3 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -548,14 +548,12 @@ gb_internal i32 linker_stage(LinkerData *gen) { // available at runtime wherever the executable is run, so we make require those to be // local to the executable (unless the system collection is used, in which case we search // the system library paths for the library file). - if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o"))) { + if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o")) || string_ends_with(lib, str_lit(".so")) || string_contains_string(lib, str_lit(".so."))) { // static libs and object files, absolute full path relative to the file in which the lib was imported from lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib)); - } else if (string_ends_with(lib, str_lit(".so")) || string_contains_string(lib, str_lit(".so."))) { - // dynamic lib, relative path to executable - // NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible - // at runtime to the executable - lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib)); + + // NOTE(laytan): If .so, I think we can check for the existence of "$OUT_DIRECTORY/$lib" here and print an error telling the user to copy over the file, or we can even do the copy for them? + } 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)); @@ -643,6 +641,10 @@ gb_internal i32 linker_stage(LinkerData *gen) { } } + // Set the rpath to the $ORIGIN (the path of the executable), + // so that dynamic libraries are looked for at that path. + gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN "); + if (!build_context.no_crt) { platform_lib_str = gb_string_appendc(platform_lib_str, "-lm "); if (build_context.metrics.os == TargetOs_darwin) { diff --git a/src/parser.cpp b/src/parser.cpp index e3143dd33..88147d465 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5932,20 +5932,6 @@ gb_internal bool determine_path_from_string(BlockingMutex *file_mutex, Ast *node do_error(node, "Unknown library collection: '%.*s'", LIT(collection_name)); return false; } - } else { -#if !defined(GB_SYSTEM_WINDOWS) - // @NOTE(vassvik): foreign imports of shared libraries that are not in the system collection on - // linux/mac have to be local to the executable for consistency with shared libraries. - // Unix does not have a concept of "import library" for shared/dynamic libraries, - // so we need to pass the relative path to the linker, and add the current - // working directory of the exe to the library search paths. - // Static libraries can be linked directly with the full pathname - // - if (node->kind == Ast_ForeignImportDecl && (string_ends_with(file_str, str_lit(".so")) || string_contains_string(file_str, str_lit(".so.")))) { - *path = file_str; - return true; - } -#endif } if (is_package_name_reserved(file_str)) { From 0aa971207ba14f791b1cae3652e67e674710cf8e Mon Sep 17 00:00:00 2001 From: Laytan Date: Wed, 4 Sep 2024 22:38:19 +0200 Subject: [PATCH 2/3] add -no-rpath --- src/build_settings.cpp | 1 + src/linker.cpp | 8 +++++--- src/main.cpp | 9 +++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index fe0e478c7..fb10a25f6 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -411,6 +411,7 @@ struct BuildContext { bool no_dynamic_literals; bool no_output_files; bool no_crt; + bool no_rpath; bool no_entry_point; bool no_thread_local; bool use_lld; diff --git a/src/linker.cpp b/src/linker.cpp index 25b9cfdc3..cdda87697 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -641,9 +641,11 @@ gb_internal i32 linker_stage(LinkerData *gen) { } } - // Set the rpath to the $ORIGIN (the path of the executable), - // so that dynamic libraries are looked for at that path. - gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN "); + if (!build_context.no_rpath) { + // Set the rpath to the $ORIGIN (the path of the executable), + // so that dynamic libraries are looked for at that path. + gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN "); + } if (!build_context.no_crt) { platform_lib_str = gb_string_appendc(platform_lib_str, "-lm "); diff --git a/src/main.cpp b/src/main.cpp index a03126caf..d13065364 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -325,6 +325,7 @@ enum BuildFlagKind { BuildFlag_NoTypeAssert, BuildFlag_NoDynamicLiterals, BuildFlag_NoCRT, + BuildFlag_NoRPath, BuildFlag_NoEntryPoint, BuildFlag_UseLLD, BuildFlag_UseSeparateModules, @@ -532,6 +533,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_NoThreadLocal, str_lit("no-thread-local"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_NoRPath, str_lit("no-rpath"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check &~ Command_test); add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_UseSeparateModules, str_lit("use-separate-modules"), BuildFlagParam_None, Command__does_build); @@ -1181,6 +1183,9 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_NoCRT: build_context.no_crt = true; break; + case BuildFlag_NoRPath: + build_context.no_rpath = true; + break; case BuildFlag_NoEntryPoint: build_context.no_entry_point = true; break; @@ -2310,6 +2315,10 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(2, "Disables automatic linking with the C Run Time."); print_usage_line(0, ""); + print_usage_line(1, "-no-rpath"); + print_usage_line(2, "Disables automatic addition of an rpath linked to the executable directory."); + print_usage_line(0, ""); + print_usage_line(1, "-no-thread-local"); print_usage_line(2, "Ignores @thread_local attribute, effectively treating the program as if it is single-threaded."); print_usage_line(0, ""); From 6778598bc648a4c605fb1b488185fad59668185a Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 4 Sep 2024 23:45:30 +0200 Subject: [PATCH 3/3] support the rpath changes on macos --- .github/workflows/ci.yml | 10 +++++----- src/linker.cpp | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e547959aa..421b5c586 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -257,16 +257,16 @@ jobs: run: sudo apt-get install -y qemu-user qemu-user-static gcc-12-riscv64-linux-gnu libc6-riscv64-cross - name: Odin run - run: ./odin run examples/demo -vet -strict-style -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" + run: ./odin run examples/demo -vet -strict-style -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath - name: Odin run -debug - run: ./odin run examples/demo -debug -vet -strict-style -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" + run: ./odin run examples/demo -debug -vet -strict-style -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath - name: Normal Core library tests - run: ./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" + run: ./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath - name: Optimized Core library tests - run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" + run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath - name: Internals tests - run: ./odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" + run: ./odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath diff --git a/src/linker.cpp b/src/linker.cpp index cdda87697..500fead69 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -549,11 +549,7 @@ gb_internal i32 linker_stage(LinkerData *gen) { // local to the executable (unless the system collection is used, in which case we search // the system library paths for the library file). if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o")) || string_ends_with(lib, str_lit(".so")) || string_contains_string(lib, str_lit(".so."))) { - // static libs and object files, absolute full path relative to the file in which the lib was imported from lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib)); - - // NOTE(laytan): If .so, I think we can check for the existence of "$OUT_DIRECTORY/$lib" here and print an error telling the user to copy over the file, or we can even do the copy for them? - } 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)); @@ -642,9 +638,13 @@ gb_internal i32 linker_stage(LinkerData *gen) { } if (!build_context.no_rpath) { - // Set the rpath to the $ORIGIN (the path of the executable), + // Set the rpath to the $ORIGIN/@loader_path (the path of the executable), // so that dynamic libraries are looked for at that path. - gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN "); + 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 (!build_context.no_crt) {