Skip to content

Commit

Permalink
Teach jl_load_dynamic_library() about @executable_path on all pla…
Browse files Browse the repository at this point in the history
…tforms

It is useful for us to be able to hard-code a dynamic library's location
relative to that of the julia executable.  We repurpose the
`@executable_path` component from MacOS, allowing all platforms to
perform executable-relative binary loading (I'm looking at you, Windows).
  • Loading branch information
staticfloat committed May 14, 2020
1 parent 08861c7 commit 00abaf8
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 6 deletions.
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ Compiler/Runtime improvements
-----------------------------


* All platforms can now use `@executable_path` within `jl_load_dynamic_library()`.
This allows executable-relative paths to be embedded within executables on all
platforms, not just MacOS, which the syntax is borrowed from. ([#35627])

Command-line option changes
---------------------------

Expand Down
21 changes: 15 additions & 6 deletions src/dlload.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ static int endswith_extension(const char *path)

#define PATHBUF 4096

extern char *julia_bindir;

#define JL_RTLD(flags, FLAG) (flags & JL_RTLD_ ## FLAG ? RTLD_ ## FLAG : 0)

#ifdef _OS_WINDOWS_
Expand Down Expand Up @@ -136,7 +134,7 @@ JL_DLLEXPORT int jl_dlclose(void *handle)

JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags, int throw_err)
{
char path[PATHBUF];
char path[PATHBUF], relocated[PATHBUF];
int i;
#ifdef _OS_WINDOWS_
int err;
Expand Down Expand Up @@ -173,6 +171,9 @@ JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags,
this branch permutes all base paths in DL_LOAD_PATH with all extensions
note: skip when !jl_base_module to avoid UndefVarError(:DL_LOAD_PATH),
and also skip for absolute paths
We also do simple string replacement here for elements starting with `@executable_path/`.
While these exist as OS concepts on Darwin, we want to use them on other platforms
such as Windows, so we emulate them here.
*/
if (!abspath && jl_base_module != NULL) {
jl_array_t *DL_LOAD_PATH = (jl_array_t*)jl_get_global(jl_base_module, jl_symbol("DL_LOAD_PATH"));
Expand All @@ -183,13 +184,21 @@ JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags,
size_t len = strlen(dl_path);
if (len == 0)
continue;

// Is this entry supposed to be relative to the bindir?
if (len >= 16 && strncmp(dl_path, "@executable_path", 16) == 0) {
snprintf(relocated, PATHBUF, "%s%s", jl_options.julia_bindir, dl_path + 16);
len = len - 16 + strlen(jl_options.julia_bindir);
} else {
strncpy(relocated, dl_path, len);
}
for (i = 0; i < n_extensions; i++) {
const char *ext = extensions[i];
path[0] = '\0';
if (dl_path[len-1] == PATHSEPSTRING[0])
snprintf(path, PATHBUF, "%s%s%s", dl_path, modname, ext);
if (relocated[len-1] == PATHSEPSTRING[0])
snprintf(path, PATHBUF, "%s%s%s", relocated, modname, ext);
else
snprintf(path, PATHBUF, "%s" PATHSEPSTRING "%s%s", dl_path, modname, ext);
snprintf(path, PATHBUF, "%s" PATHSEPSTRING "%s%s", relocated, modname, ext);
#ifdef _OS_WINDOWS_
if (i == 0) { // LoadLibrary already tested the extensions, we just need to check the `stat` result
#endif
Expand Down
5 changes: 5 additions & 0 deletions stdlib/Libdl/src/Libdl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ between shared libraries.
If the library cannot be found, this method throws an error, unless the keyword argument
`throw_error` is set to `false`, in which case this method returns `nothing`.
!!! note
From Julia 1.6 on, this method replaces paths starting with `@executable_path/` with
the path to the Julia executable, allowing for relocatable relative-path loads. In
Julia 1.5 and earlier, this only worked on macOS.
"""
function dlopen end

Expand Down

0 comments on commit 00abaf8

Please sign in to comment.