Bläddra i källkod

Fix -build-mode:shared type table on Unix

Fixes #527.

Previously on Linux, '__$startup_runtime', the procedure that
initializes the type table for runtime typeids, was NOT called when
a shared library was loaded by the dynamic loader.

This caused the library to not have its type table populated, which
caused an assert to fail if you tried to use runtime typeids - like
core:fmt, for example.

This commit fixes this by calling ld instead of clang, when building a
shared library, so that we can pass "-init '__$startup_runtime'" to it,
when building a shared library.

Try as I might, I could not get clang to correctly pass through
the linker flags that I wanted.
Tetralux 4 år sedan
förälder
incheckning
140bb3ebfc
1 ändrade filer med 45 tillägg och 37 borttagningar
  1. 45 37
      src/main.cpp

+ 45 - 37
src/main.cpp

@@ -342,9 +342,9 @@ i32 linker_stage(lbGenerator *gen) {
 					lib_name = remove_extension_from_path(lib_name);
 					lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name));
 				} else if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o")) || string_ends_with(lib, str_lit(".dylib"))) {
-          				// For:
-          				// object 
-          				// dynamic lib
+					// For:
+					// 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));
 				} else {
@@ -382,20 +382,33 @@ i32 linker_stage(lbGenerator *gen) {
 		// Unlike the Win32 linker code, the output_ext includes the dot, because
 		// typically executable files on *NIX systems don't have extensions.
 		String output_ext = {};
-		char const *link_settings = "";
+		gbString link_settings = gb_string_make_reserve(heap_allocator(), 32);
 		char const *linker;
 		if (build_context.build_mode == BuildMode_DynamicLibrary) {
+			// NOTE(tetra, 2020-11-06): __$startup_runtime must be called at DLL load time.
+			// Clang, for some reason, won't let us pass the '-init' flag that lets us do this,
+			// so use ld instead.
+			// :UseLDForShared
+			linker = "ld";
+			link_settings = gb_string_appendc(link_settings, "-init '__$startup_runtime' ");
 			// Shared libraries are .dylib on MacOS and .so on Linux.
 			#if defined(GB_SYSTEM_OSX)
 				output_ext = STR_LIT(".dylib");
-				link_settings = "-dylib -dynamic";
+				link_settings = gb_string_appendc(link_settings, "-dylib -dynamic ");
 			#else
 				output_ext = STR_LIT(".so");
-				link_settings = "-shared";
+				link_settings = gb_string_appendc(link_settings, "-shared ");
 			#endif
 		} else {
-			// TODO: Do I need anything here?
-			link_settings = "";
+			#if defined(GB_SYSTEM_OSX)
+				linker = "ld";
+			#else
+				// TODO(zangent): Figure out how to make ld work on Linux.
+				//   It probably has to do with including the entire CRT, but
+				//   that's quite a complicated issue to solve while remaining distro-agnostic.
+				//   Clang can figure out linker flags for us, and that's good enough _for now_.
+				linker = "clang -Wno-unused-command-line-argument";
+			#endif
 		}
 
 		if (build_context.out_filepath.len > 0) {
@@ -406,16 +419,6 @@ i32 linker_stage(lbGenerator *gen) {
 			}
 		}
 
-		#if defined(GB_SYSTEM_OSX)
-			linker = "ld";
-		#else
-			// TODO(zangent): Figure out how to make ld work on Linux.
-			//   It probably has to do with including the entire CRT, but
-			//   that's quite a complicated issue to solve while remaining distro-agnostic.
-			//   Clang can figure out linker flags for us, and that's good enough _for now_.
-			linker = "clang -Wno-unused-command-line-argument";
-		#endif
-
 		exit_code = system_exec_command_line_app("ld-link",
 			"%s %s -o \"%.*s%.*s\" %s "
 			" %s "
@@ -443,7 +446,7 @@ i32 linker_stage(lbGenerator *gen) {
 		if (exit_code != 0) {
 			return exit_code;
 		}
-    
+
 	#if defined(GB_SYSTEM_OSX)
 		if (build_context.ODIN_DEBUG) {
 			// NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe
@@ -2136,11 +2139,11 @@ int main(int arg_count, char const **arg_ptr) {
 						String lib_name = lib;
 						lib_name = remove_extension_from_path(lib_name);
 						lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name));
-						
+
 				} else if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o")) || string_ends_with(lib, str_lit(".dylib"))) {
-          				// For:
-          				// object 
-          				// dynamic lib
+					// For:
+					// 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));
 				} else {
@@ -2171,22 +2174,36 @@ int main(int arg_count, char const **arg_ptr) {
 			// Unlike the Win32 linker code, the output_ext includes the dot, because
 			// typically executable files on *NIX systems don't have extensions.
 			String output_ext = {};
-			char const *link_settings = "";
+			gbString link_settings = gb_string_make_reserve(heap_allocator(), 32);
 			char const *linker;
 			if (build_context.build_mode == BuildMode_DynamicLibrary) {
+				// NOTE(tetra, 2020-11-06): __$startup_runtime must be called at DLL load time.
+				// Clang, for some reason, won't let us pass the '-init' flag that lets us do this,
+				// so use ld instead.
+				// :UseLDForShared
+				linker = "ld";
+				link_settings = gb_string_appendc(link_settings, "-init '__$startup_runtime' ");
 				// Shared libraries are .dylib on MacOS and .so on Linux.
 				#if defined(GB_SYSTEM_OSX)
 					output_ext = STR_LIT(".dylib");
-					link_settings = "-dylib -dynamic";
+					link_settings = gb_string_appendc(link_settings, "-dylib -dynamic ");
 				#else
 					output_ext = STR_LIT(".so");
-					link_settings = "-shared";
+					link_settings = gb_string_appendc(link_settings, "-shared ");
 				#endif
 			} else {
-				// TODO: Do I need anything here?
-				link_settings = "";
+				#if defined(GB_SYSTEM_OSX)
+					linker = "ld";
+				#else
+					// TODO(zangent): Figure out how to make ld work on Linux.
+					//   It probably has to do with including the entire CRT, but
+					//   that's quite a complicated issue to solve while remaining distro-agnostic.
+					//   Clang can figure out linker flags for us, and that's good enough _for now_.
+					linker = "clang -Wno-unused-command-line-argument";
+				#endif
 			}
 
+
 			if (build_context.out_filepath.len > 0) {
 				//NOTE(thebirk): We have a custom -out arguments, so we should use the extension from that
 				isize pos = string_extension_position(build_context.out_filepath);
@@ -2195,15 +2212,6 @@ int main(int arg_count, char const **arg_ptr) {
 				}
 			}
 
-			#if defined(GB_SYSTEM_OSX)
-				linker = "ld";
-			#else
-				// TODO(zangent): Figure out how to make ld work on Linux.
-				//   It probably has to do with including the entire CRT, but
-				//   that's quite a complicated issue to solve while remaining distro-agnostic.
-				//   Clang can figure out linker flags for us, and that's good enough _for now_.
-				linker = "clang -Wno-unused-command-line-argument";
-			#endif
 
 			exit_code = system_exec_command_line_app("ld-link",
 				"%s \"%.*s.o\" -o \"%.*s%.*s\" %s "