Browse Source

Merge pull request #4206 from laytan/improve-linking-shared-libraries

Improve linking shared libraries
gingerBill 11 months ago
parent
commit
b442ea8601
5 changed files with 26 additions and 26 deletions
  1. 5 5
      .github/workflows/ci.yml
  2. 1 0
      src/build_settings.cpp
  3. 11 7
      src/linker.cpp
  4. 9 0
      src/main.cpp
  5. 0 14
      src/parser.cpp

+ 5 - 5
.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
         run: sudo apt-get install -y qemu-user qemu-user-static gcc-12-riscv64-linux-gnu libc6-riscv64-cross
 
 
       - name: Odin run
       - 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
       - 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
       - 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
       - 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
       - 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

+ 1 - 0
src/build_settings.cpp

@@ -411,6 +411,7 @@ struct BuildContext {
 	bool   no_dynamic_literals;
 	bool   no_dynamic_literals;
 	bool   no_output_files;
 	bool   no_output_files;
 	bool   no_crt;
 	bool   no_crt;
+	bool   no_rpath;
 	bool   no_entry_point;
 	bool   no_entry_point;
 	bool   no_thread_local;
 	bool   no_thread_local;
 	bool   use_lld;
 	bool   use_lld;

+ 11 - 7
src/linker.cpp

@@ -548,14 +548,8 @@ gb_internal i32 linker_stage(LinkerData *gen) {
 							//                available at runtime wherever the executable is run, so we make require those to be
 							//                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
 							//                local to the executable (unless the system collection is used, in which case we search
 							//                the system library paths for the library file).
 							//                the system library paths for the library file).
-							if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o"))) {
-								// static libs and object files, absolute full path relative to the file in which the lib was imported from
+							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."))) {
 								lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib));
 								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));
 							} else {
 							} else {
 								// dynamic or static system lib, just link regularly searching system library paths
 								// dynamic or static system lib, just link regularly searching system library paths
 								lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
 								lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
@@ -643,6 +637,16 @@ gb_internal i32 linker_stage(LinkerData *gen) {
 				}
 				}
 			}
 			}
 
 
+			if (!build_context.no_rpath) {
+				// Set the rpath to the $ORIGIN/@loader_path (the path of the executable),
+				// so that dynamic libraries are looked for at that path.
+				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) {
 			if (!build_context.no_crt) {
 				platform_lib_str = gb_string_appendc(platform_lib_str, "-lm ");
 				platform_lib_str = gb_string_appendc(platform_lib_str, "-lm ");
 				if (build_context.metrics.os == TargetOs_darwin) {
 				if (build_context.metrics.os == TargetOs_darwin) {

+ 9 - 0
src/main.cpp

@@ -325,6 +325,7 @@ enum BuildFlagKind {
 	BuildFlag_NoTypeAssert,
 	BuildFlag_NoTypeAssert,
 	BuildFlag_NoDynamicLiterals,
 	BuildFlag_NoDynamicLiterals,
 	BuildFlag_NoCRT,
 	BuildFlag_NoCRT,
+	BuildFlag_NoRPath,
 	BuildFlag_NoEntryPoint,
 	BuildFlag_NoEntryPoint,
 	BuildFlag_UseLLD,
 	BuildFlag_UseLLD,
 	BuildFlag_UseSeparateModules,
 	BuildFlag_UseSeparateModules,
@@ -533,6 +534,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
 	add_flag(&build_flags, BuildFlag_NoThreadLocal,           str_lit("no-thread-local"),           BuildFlagParam_None,    Command__does_check);
 	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_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_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_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_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);
 	add_flag(&build_flags, BuildFlag_UseSeparateModules,      str_lit("use-separate-modules"),      BuildFlagParam_None,    Command__does_build);
@@ -1183,6 +1185,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
 						case BuildFlag_NoCRT:
 						case BuildFlag_NoCRT:
 							build_context.no_crt = true;
 							build_context.no_crt = true;
 							break;
 							break;
+						case BuildFlag_NoRPath:
+							build_context.no_rpath = true;
+							break;
 						case BuildFlag_NoEntryPoint:
 						case BuildFlag_NoEntryPoint:
 							build_context.no_entry_point = true;
 							build_context.no_entry_point = true;
 							break;
 							break;
@@ -2315,6 +2320,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(2, "Disables automatic linking with the C Run Time.");
 		print_usage_line(0, "");
 		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(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(2, "Ignores @thread_local attribute, effectively treating the program as if it is single-threaded.");
 		print_usage_line(0, "");
 		print_usage_line(0, "");

+ 0 - 14
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));
 			do_error(node, "Unknown library collection: '%.*s'", LIT(collection_name));
 			return false;
 			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)) {
 	if (is_package_name_reserved(file_str)) {