Skip to content

Commit 4e99860

Browse files
committed
Load special libraries in-order
The `DEPS_LIBS` RPATH-substitute mechanism contains a list of paths to load, and some of these paths are "special", in that they require more involved loading than simply `load_library()`. These libraries are thereby denoted by a `@` prefixing them. Previously, we made note of these libraries, then loaded them at the end of the loading loop, but with the addition of `libstdc++` it is now important to have the order of the libraries (including special libraries) to be obeyed by the loading loop, so I have inlined special library handling into the loading loop. In the future, we may wish to denote special libraries more explicitly than simply relying on there being exactly three libraries, with the ordering being mapped to `libstdc++`, `libjulia-internal`, and `libjulia-codegen`.
1 parent fb97c82 commit 4e99860

File tree

2 files changed

+108
-58
lines changed

2 files changed

+108
-58
lines changed

Make.inc

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,7 +1465,7 @@ JULIA_SYSIMG_release := $(build_private_libdir)/sys.$(SHLIB_EXT)
14651465
JULIA_SYSIMG := $(JULIA_SYSIMG_$(JULIA_BUILD_MODE))
14661466

14671467
define dep_lib_path
1468-
$$($(PYTHON) $(call python_cygpath,$(JULIAHOME)/contrib/relative_path.py) $(1) $(2))
1468+
$(shell $(PYTHON) $(call python_cygpath,$(JULIAHOME)/contrib/relative_path.py) $(1) $(2))
14691469
endef
14701470

14711471
LIBJULIAINTERNAL_BUILD_DEPLIB := $(call dep_lib_path,$(build_libdir),$(build_shlibdir)/libjulia-internal.$(JL_MAJOR_SHLIB_EXT))
@@ -1538,6 +1538,8 @@ LIBM_INSTALL_DEPLIB := $(call dep_lib_path,$(libdir),$(private_shlibdir)/$(LIBMN
15381538
# We list:
15391539
# * libgcc_s, because FreeBSD needs to load ours, not the system one.
15401540
# * libopenlibm, because Windows has an untrustworthy libm, and we want to use ours more than theirs
1541+
# * libstdc++, because while performing `libstdc++` probing we need to
1542+
# know the path to the bundled `libstdc++` library.
15411543
# * libjulia-internal, which must always come second-to-last.
15421544
# * libjulia-codegen, which must always come last
15431545
#
@@ -1546,11 +1548,45 @@ LIBM_INSTALL_DEPLIB := $(call dep_lib_path,$(libdir),$(private_shlibdir)/$(LIBMN
15461548
# * install time relative paths are not equal to build time relative paths (../lib vs. ../lib/julia)
15471549
# That second point will no longer be true for most deps once they are placed within Artifacts directories.
15481550
# Note that we prefix `libjulia-codegen` and `libjulia-internal` with `@` to signify to the loader that it
1549-
# should not automatically dlopen() it in its loading loop.
1550-
LOADER_BUILD_DEP_LIBS = $(LIBGCC_BUILD_DEPLIB):$(LIBM_BUILD_DEPLIB):@$(LIBSTDCXX_BUILD_DEPLIB):@$(LIBJULIAINTERNAL_BUILD_DEPLIB):@$(LIBJULIACODEGEN_BUILD_DEPLIB):
1551-
LOADER_DEBUG_BUILD_DEP_LIBS = $(LIBGCC_BUILD_DEPLIB):$(LIBM_BUILD_DEPLIB):@$(LIBSTDCXX_BUILD_DEPLIB):@$(LIBJULIAINTERNAL_DEBUG_BUILD_DEPLIB):@$(LIBJULIACODEGEN_DEBUG_BUILD_DEPLIB):
1552-
LOADER_INSTALL_DEP_LIBS = $(LIBGCC_INSTALL_DEPLIB):$(LIBM_INSTALL_DEPLIB):@$(LIBSTDCXX_INSTALL_DEPLIB):@$(LIBJULIAINTERNAL_INSTALL_DEPLIB):@$(LIBJULIACODEGEN_INSTALL_DEPLIB):
1553-
LOADER_DEBUG_INSTALL_DEP_LIBS = $(LIBGCC_INSTALL_DEPLIB):$(LIBM_INSTALL_DEPLIB):@$(LIBSTDCXX_INSTALL_DEPLIB):@$(LIBJULIAINTERNAL_DEBUG_INSTALL_DEPLIB):@$(LIBJULIACODEGEN_DEBUG_INSTALL_DEPLIB):
1551+
# should not automatically dlopen() it in its loading loop, it is "special" and should happen later.
1552+
# We do the same for `libstdc++`, and explicitly place it _after_ `libgcc_s`, and `libm` since `libstdc++`
1553+
# may depend on those libraries (e.g. when USE_SYSTEM_LIBM=1)
1554+
1555+
# Helper function to join a list with colons, then place an extra at the end.
1556+
define build_deplibs
1557+
$(subst $(SPACE),:,$(strip $(1))):
1558+
endef
1559+
1560+
LOADER_BUILD_DEP_LIBS = $(call build_deplibs, \
1561+
$(LIBGCC_BUILD_DEPLIB) \
1562+
$(LIBM_BUILD_DEPLIB) \
1563+
@$(LIBSTDCXX_BUILD_DEPLIB) \
1564+
@$(LIBJULIAINTERNAL_BUILD_DEPLIB) \
1565+
@$(LIBJULIACODEGEN_BUILD_DEPLIB) \
1566+
)
1567+
1568+
LOADER_DEBUG_BUILD_DEP_LIBS = $(call build_deplibs, \
1569+
$(LIBGCC_BUILD_DEPLIB) \
1570+
$(LIBM_BUILD_DEPLIB) \
1571+
@$(LIBSTDCXX_BUILD_DEPLIB) \
1572+
@$(LIBJULIAINTERNAL_DEBUG_BUILD_DEPLIB) \
1573+
@$(LIBJULIACODEGEN_DEBUG_BUILD_DEPLIB) \
1574+
)
1575+
1576+
LOADER_INSTALL_DEP_LIBS = $(call build_deplibs, \
1577+
$(LIBGCC_INSTALL_DEPLIB) \
1578+
$(LIBM_INSTALL_DEPLIB) \
1579+
@$(LIBSTDCXX_INSTALL_DEPLIB) \
1580+
@$(LIBJULIAINTERNAL_INSTALL_DEPLIB) \
1581+
@$(LIBJULIACODEGEN_INSTALL_DEPLIB) \
1582+
)
1583+
LOADER_DEBUG_INSTALL_DEP_LIBS = $(call build_deplibs, \
1584+
$(LIBGCC_INSTALL_DEPLIB) \
1585+
$(LIBM_INSTALL_DEPLIB) \
1586+
@$(LIBSTDCXX_INSTALL_DEPLIB) \
1587+
@$(LIBJULIAINTERNAL_DEBUG_INSTALL_DEPLIB) \
1588+
@$(LIBJULIACODEGEN_DEBUG_INSTALL_DEPLIB) \
1589+
)
15541590

15551591
# Colors for make
15561592
ifndef VERBOSE

cli/loader_lib.c

Lines changed: 66 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,8 @@ static char *libstdcxxprobe(void)
350350
}
351351
#endif
352352

353-
void * libjulia_internal = NULL;
353+
void *libjulia_internal = NULL;
354+
void *libjulia_codegen = NULL;
354355
__attribute__((constructor)) void jl_load_libjulia_internal(void) {
355356
// Only initialize this once
356357
if (libjulia_internal != NULL) {
@@ -364,18 +365,14 @@ __attribute__((constructor)) void jl_load_libjulia_internal(void) {
364365
int deps_len = strlen(&dep_libs[1]);
365366
char *curr_dep = &dep_libs[1];
366367

367-
void *cxx_handle;
368-
369368
// We keep track of "special" libraries names (ones whose name is prefixed with `@`)
370369
// which are libraries that we want to load in some special, custom way.
371370
// The current list is:
372-
// special_library_names = {
373-
// libstdc++,
374-
// libjulia-internal,
375-
// libjulia-codegen,
376-
// }
371+
// libstdc++
372+
// libjulia-internal
373+
// libjulia-codegen
374+
const int NUM_SPECIAL_LIBRARIES = 3;
377375
int special_idx = 0;
378-
char * special_library_names[3] = {NULL};
379376
while (1) {
380377
// try to find next colon character; if we can't, break out
381378
char * colon = strchr(curr_dep, ':');
@@ -384,61 +381,30 @@ __attribute__((constructor)) void jl_load_libjulia_internal(void) {
384381

385382
// If this library name starts with `@`, don't open it here (but mark it as special)
386383
if (curr_dep[0] == '@') {
387-
if (special_idx > sizeof(special_library_names)/sizeof(char *)) {
384+
special_idx += 1;
385+
if (special_idx > NUM_SPECIAL_LIBRARIES) {
388386
jl_loader_print_stderr("ERROR: Too many special library names specified, check LOADER_BUILD_DEP_LIBS and friends!\n");
389387
exit(1);
390388
}
391-
special_library_names[special_idx] = curr_dep + 1;
392-
special_idx += 1;
393-
394-
// Chop the string at the colon so it's a valid-ending-string
395-
*colon = '\0';
396389
}
397390

398391
// Skip to next dep
399392
curr_dep = colon + 1;
400393
}
401394

402395
// Assert that we have exactly the right number of special library names
403-
if (special_idx != sizeof(special_library_names)/sizeof(char *)) {
396+
if (special_idx != NUM_SPECIAL_LIBRARIES) {
404397
jl_loader_print_stderr("ERROR: Too few special library names specified, check LOADER_BUILD_DEP_LIBS and friends!\n");
405398
exit(1);
406399
}
407400

408-
// Unpack our special library names. This is why ordering of library names matters.
409-
char * bundled_libstdcxx_path = special_library_names[0];
410-
libjulia_internal = load_library(special_library_names[1], lib_dir, 1);
411-
void *libjulia_codegen = load_library(special_library_names[2], lib_dir, 0);
412-
413-
#if defined(_OS_LINUX_)
414-
int do_probe = 1;
415-
int done_probe = 0;
416-
char *probevar = getenv("JULIA_PROBE_LIBSTDCXX");
417-
if (probevar) {
418-
if (strcmp(probevar, "1") == 0 || strcmp(probevar, "yes") == 0)
419-
do_probe = 1;
420-
else if (strcmp(probevar, "0") == 0 || strcmp(probevar, "no") == 0)
421-
do_probe = 0;
422-
}
423-
if (do_probe) {
424-
char *cxxpath = libstdcxxprobe();
425-
if (cxxpath) {
426-
cxx_handle = dlopen(cxxpath, RTLD_LAZY);
427-
char *dlr = dlerror();
428-
if (dlr) {
429-
jl_loader_print_stderr("ERROR: Unable to dlopen(cxxpath) in parent!\n");
430-
jl_loader_print_stderr3("Message: ", dlr, "\n");
431-
exit(1);
432-
}
433-
free(cxxpath);
434-
done_probe = 1;
435-
}
436-
}
437-
if (!done_probe) {
438-
load_library(bundled_libstdcxx_path, lib_dir, 1);
439-
}
440-
#endif
441-
401+
// Now that we've asserted that we have the right number of special
402+
// libraries, actually run a loop over the deps loading them in-order.
403+
// If it's a special library, we do slightly different things, especially
404+
// for libstdc++, where we actually probe for a system libstdc++ and
405+
// load that if it's newer.
406+
special_idx = 0;
407+
curr_dep = &dep_libs[1];
442408
while (1) {
443409
// try to find next colon character; if we can't, break out
444410
char * colon = strchr(curr_dep, ':');
@@ -448,8 +414,56 @@ __attribute__((constructor)) void jl_load_libjulia_internal(void) {
448414
// Chop the string at the colon so it's a valid-ending-string
449415
*colon = '\0';
450416

451-
// If this library name starts with `@`, don't open it here
452-
if (curr_dep[0] != '@') {
417+
// If this library name starts with `@`, it's a special library
418+
// and requires special handling:
419+
if (curr_dep[0] == '@') {
420+
// Skip the `@` for future function calls.
421+
curr_dep += 1;
422+
423+
// First special library to be loaded is `libstdc++`; perform probing here.
424+
if (special_idx == 0) {
425+
#if defined(_OS_LINUX_)
426+
int do_probe = 1;
427+
int probe_successful = 0;
428+
429+
// Check to see if the user has disabled libstdc++ probing
430+
char *probevar = getenv("JULIA_PROBE_LIBSTDCXX");
431+
if (probevar) {
432+
if (strcmp(probevar, "1") == 0 || strcmp(probevar, "yes") == 0)
433+
do_probe = 1;
434+
else if (strcmp(probevar, "0") == 0 || strcmp(probevar, "no") == 0)
435+
do_probe = 0;
436+
}
437+
if (do_probe) {
438+
char *cxxpath = libstdcxxprobe();
439+
if (cxxpath) {
440+
void *cxx_handle = dlopen(cxxpath, RTLD_LAZY);
441+
const char *dlr = dlerror();
442+
if (dlr) {
443+
jl_loader_print_stderr("ERROR: Unable to dlopen(cxxpath) in parent!\n");
444+
jl_loader_print_stderr3("Message: ", dlr, "\n");
445+
exit(1);
446+
}
447+
free(cxxpath);
448+
probe_successful = 1;
449+
}
450+
}
451+
// If the probe rejected the system libstdc++ (or didn't find one!)
452+
// just load our bundled libstdc++ as identified by curr_dep;
453+
if (!probe_successful) {
454+
load_library(curr_dep, lib_dir, 1);
455+
}
456+
#endif
457+
} else if (special_idx == 1) {
458+
// This special library is `libjulia-internal`
459+
libjulia_internal = load_library(curr_dep, lib_dir, 1);
460+
} else if (special_idx == 2) {
461+
// This special library is `libjulia-codegen`
462+
libjulia_codegen = load_library(curr_dep, lib_dir, 0);
463+
}
464+
special_idx++;
465+
} else {
466+
// Otherwise, just load it as "normal"
453467
load_library(curr_dep, lib_dir, 1);
454468
}
455469

0 commit comments

Comments
 (0)