From 0b211609bb9790cf86edc08b256df42d0c480df1 Mon Sep 17 00:00:00 2001
From: Elliot Saba <staticfloat@gmail.com>
Date: Thu, 19 Jan 2023 04:25:15 +0000
Subject: [PATCH] Move `libstdc++` path into `LOADER_*_DEP_LIBS`

After adding `libstdc++` probing into the Julia loader [0], we
originally made the assumption that the `libstdc++` that is shipped with
`julia` would always be co-located with `libjulia.so` [1].  This is not
the case when building with `USE_SYSTEM_CSL=1`, however, where we
sequester system libraries in `usr/lib/julia`, even at build-time.

The path to `libstdc++.so` has already been getting altered when moving
from build-time to install time via `stringreplace` [2], but after
further thought, I decided that it would be better to just use the
pre-existing `LOADER_*_DEP_LIBS` mechanism to communicate to the loader
what the correct relative path to `libstdc++.so` is.  This also allows
the single `stringreplace` to update all of our "special" library paths.

[0] https://github.com/JuliaLang/julia/pull/46976
[1] https://github.com/JuliaLang/julia/pull/46976/files#diff-8c5c98f26f3f7aac8905a1074c5bec11a57e9b9c7c556791deac5a3b27cc096fR379
[2] https://github.com/JuliaLang/julia/blob/master/Makefile#L430
---
 Make.inc         | 21 +++++++++++---
 Makefile         |  6 ----
 cli/loader_lib.c | 72 +++++++++++++++++++++++++++++++-----------------
 3 files changed, 64 insertions(+), 35 deletions(-)

diff --git a/Make.inc b/Make.inc
index 24f5964e9dcc0..a7cd154aa347e 100644
--- a/Make.inc
+++ b/Make.inc
@@ -1512,6 +1512,19 @@ LIBGCC_BUILD_DEPLIB := $(call dep_lib_path,$(build_libdir),$(build_shlibdir)/$(L
 endif
 LIBGCC_INSTALL_DEPLIB := $(call dep_lib_path,$(libdir),$(private_shlibdir)/$(LIBGCC_NAME))
 
+# We only bother to define this on Linux, as that's the only platform that does libstdc++ probing
+# On all other platforms, the LIBSTDCXX_*_DEPLIB variables will be empty.
+ifeq ($(OS),Linux)
+LIBSTDCXX_NAME := libstdc++.so.6
+ifeq ($(USE_SYSTEM_CSL),1)
+LIBSTDCXX_BUILD_DEPLIB := $(call dep_lib_path,$(build_libdir),$(build_private_shlibdir)/$(LIBSTDCXX_NAME))
+else
+LIBSTDCXX_BUILD_DEPLIB := $(call dep_lib_path,$(build_libdir),$(build_shlibdir)/$(LIBSTDCXX_NAME))
+endif
+LIBSTDCXX_INSTALL_DEPLIB := $(call dep_lib_path,$(libdir),$(private_shlibdir)/$(LIBSTDCXX_NAME))
+endif
+
+
 # USE_SYSTEM_LIBM and USE_SYSTEM_OPENLIBM causes it to get symlinked into build_private_shlibdir
 ifeq ($(USE_SYSTEM_LIBM),1)
 LIBM_BUILD_DEPLIB := $(call dep_lib_path,$(build_libdir),$(build_private_shlibdir)/$(LIBMNAME).$(SHLIB_EXT))
@@ -1534,10 +1547,10 @@ LIBM_INSTALL_DEPLIB := $(call dep_lib_path,$(libdir),$(private_shlibdir)/$(LIBMN
 # That second point will no longer be true for most deps once they are placed within Artifacts directories.
 # Note that we prefix `libjulia-codegen` and `libjulia-internal` with `@` to signify to the loader that it
 # should not automatically dlopen() it in its loading loop.
-LOADER_BUILD_DEP_LIBS = $(LIBGCC_BUILD_DEPLIB):$(LIBM_BUILD_DEPLIB):@$(LIBJULIAINTERNAL_BUILD_DEPLIB):@$(LIBJULIACODEGEN_BUILD_DEPLIB):
-LOADER_DEBUG_BUILD_DEP_LIBS = $(LIBGCC_BUILD_DEPLIB):$(LIBM_BUILD_DEPLIB):@$(LIBJULIAINTERNAL_DEBUG_BUILD_DEPLIB):@$(LIBJULIACODEGEN_DEBUG_BUILD_DEPLIB):
-LOADER_INSTALL_DEP_LIBS = $(LIBGCC_INSTALL_DEPLIB):$(LIBM_INSTALL_DEPLIB):@$(LIBJULIAINTERNAL_INSTALL_DEPLIB):@$(LIBJULIACODEGEN_INSTALL_DEPLIB):
-LOADER_DEBUG_INSTALL_DEP_LIBS = $(LIBGCC_INSTALL_DEPLIB):$(LIBM_INSTALL_DEPLIB):@$(LIBJULIAINTERNAL_DEBUG_INSTALL_DEPLIB):@$(LIBJULIACODEGEN_DEBUG_INSTALL_DEPLIB):
+LOADER_BUILD_DEP_LIBS = $(LIBGCC_BUILD_DEPLIB):$(LIBM_BUILD_DEPLIB):@$(LIBSTDCXX_BUILD_DEPLIB):@$(LIBJULIAINTERNAL_BUILD_DEPLIB):@$(LIBJULIACODEGEN_BUILD_DEPLIB):
+LOADER_DEBUG_BUILD_DEP_LIBS = $(LIBGCC_BUILD_DEPLIB):$(LIBM_BUILD_DEPLIB):@$(LIBSTDCXX_BUILD_DEPLIB):@$(LIBJULIAINTERNAL_DEBUG_BUILD_DEPLIB):@$(LIBJULIACODEGEN_DEBUG_BUILD_DEPLIB):
+LOADER_INSTALL_DEP_LIBS = $(LIBGCC_INSTALL_DEPLIB):$(LIBM_INSTALL_DEPLIB):@$(LIBSTDCXX_INSTALL_DEPLIB):@$(LIBJULIAINTERNAL_INSTALL_DEPLIB):@$(LIBJULIACODEGEN_INSTALL_DEPLIB):
+LOADER_DEBUG_INSTALL_DEP_LIBS = $(LIBGCC_INSTALL_DEPLIB):$(LIBM_INSTALL_DEPLIB):@$(LIBSTDCXX_INSTALL_DEPLIB):@$(LIBJULIAINTERNAL_DEBUG_INSTALL_DEPLIB):@$(LIBJULIACODEGEN_DEBUG_INSTALL_DEPLIB):
 
 # Colors for make
 ifndef VERBOSE
diff --git a/Makefile b/Makefile
index c31517c4f1e3a..68185e49ba57b 100644
--- a/Makefile
+++ b/Makefile
@@ -412,12 +412,6 @@ ifeq ($(OS), Linux)
 	-$(PATCHELF) --set-rpath '$$ORIGIN' $(DESTDIR)$(private_shlibdir)/libLLVM.$(SHLIB_EXT)
 endif
 
-	# Replace libstdc++ path, which is also moving from `lib` to `../lib/julia`.
-ifeq ($(OS),Linux)
-	$(call stringreplace,$(DESTDIR)$(shlibdir)/libjulia.$(JL_MAJOR_MINOR_SHLIB_EXT),\*libstdc++\.so\.6$$,*$(call dep_lib_path,$(shlibdir),$(private_shlibdir)/libstdc++.so.6))
-endif
-
-
 ifneq ($(LOADER_BUILD_DEP_LIBS),$(LOADER_INSTALL_DEP_LIBS))
 	# Next, overwrite relative path to libjulia-internal in our loader if $$(LOADER_BUILD_DEP_LIBS) != $$(LOADER_INSTALL_DEP_LIBS)
 ifeq ($(JULIA_BUILD_MODE),release)
diff --git a/cli/loader_lib.c b/cli/loader_lib.c
index 3fed0c794a900..11448583a7992 100644
--- a/cli/loader_lib.c
+++ b/cli/loader_lib.c
@@ -366,6 +366,50 @@ __attribute__((constructor)) void jl_load_libjulia_internal(void) {
 
     void *cxx_handle;
 
+    // We keep track of "special" libraries names (ones whose name is prefixed with `@`)
+    // which are libraries that we want to load in some special, custom way.
+    // The current list is:
+    // special_library_names = {
+    //   libstdc++,
+    //   libjulia-internal,
+    //   libjulia-codegen,
+    // }
+    int special_idx = 0;
+    char * special_library_names[3] = {NULL};
+    while (1) {
+        // try to find next colon character; if we can't, break out
+        char * colon = strchr(curr_dep, ':');
+        if (colon == NULL)
+            break;
+
+        // If this library name starts with `@`, don't open it here (but mark it as special)
+        if (curr_dep[0] == '@') {
+            if (special_idx > sizeof(special_library_names)/sizeof(char *)) {
+                jl_loader_print_stderr("ERROR: Too many special library names specified, check LOADER_BUILD_DEP_LIBS and friends!\n");
+                exit(1);
+            }
+            special_library_names[special_idx] = curr_dep + 1;
+            special_idx += 1;
+
+            // Chop the string at the colon so it's a valid-ending-string
+            *colon = '\0';
+        }
+
+        // Skip to next dep
+        curr_dep = colon + 1;
+    }
+
+    // Assert that we have exactly the right number of special library names
+    if (special_idx != sizeof(special_library_names)/sizeof(char *)) {
+        jl_loader_print_stderr("ERROR: Too few special library names specified, check LOADER_BUILD_DEP_LIBS and friends!\n");
+        exit(1);
+    }
+
+    // Unpack our special library names.  This is why ordering of library names matters.
+    char * bundled_libstdcxx_path = special_library_names[0];
+    libjulia_internal = load_library(special_library_names[1], lib_dir, 1);
+    void *libjulia_codegen = load_library(special_library_names[2], lib_dir, 0);
+
 #if defined(_OS_LINUX_)
     int do_probe = 1;
     int done_probe = 0;
@@ -391,16 +435,10 @@ __attribute__((constructor)) void jl_load_libjulia_internal(void) {
         }
     }
     if (!done_probe) {
-        const static char bundled_path[256] = "\0*libstdc++.so.6";
-        load_library(&bundled_path[2], lib_dir, 1);
+        load_library(bundled_libstdcxx_path, lib_dir, 1);
     }
 #endif
 
-    // We keep track of "special" libraries names (ones whose name is prefixed with `@`)
-    // which are libraries that we want to load in some special, custom way, such as
-    // `libjulia-internal` or `libjulia-codegen`.
-    int special_idx = 0;
-    char * special_library_names[2] = {NULL};
     while (1) {
         // try to find next colon character; if we can't, break out
         char * colon = strchr(curr_dep, ':');
@@ -410,16 +448,8 @@ __attribute__((constructor)) void jl_load_libjulia_internal(void) {
         // Chop the string at the colon so it's a valid-ending-string
         *colon = '\0';
 
-        // If this library name starts with `@`, don't open it here (but mark it as special)
-        if (curr_dep[0] == '@') {
-            if (special_idx > sizeof(special_library_names)/sizeof(char *)) {
-                jl_loader_print_stderr("ERROR: Too many special library names specified, check LOADER_BUILD_DEP_LIBS and friends!\n");
-                exit(1);
-            }
-            special_library_names[special_idx] = curr_dep + 1;
-            special_idx += 1;
-        }
-        else {
+        // If this library name starts with `@`, don't open it here
+        if (curr_dep[0] != '@') {
             load_library(curr_dep, lib_dir, 1);
         }
 
@@ -427,14 +457,6 @@ __attribute__((constructor)) void jl_load_libjulia_internal(void) {
         curr_dep = colon + 1;
     }
 
-    if (special_idx != sizeof(special_library_names)/sizeof(char *)) {
-        jl_loader_print_stderr("ERROR: Too few special library names specified, check LOADER_BUILD_DEP_LIBS and friends!\n");
-        exit(1);
-    }
-
-    // Unpack our special library names.  This is why ordering of library names matters.
-    libjulia_internal = load_library(special_library_names[0], lib_dir, 1);
-    void *libjulia_codegen = load_library(special_library_names[1], lib_dir, 0);
     const char * const * codegen_func_names;
     const char *codegen_liberr;
     if (libjulia_codegen == NULL) {
