Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Teach jl_load_dynamic_library() about @executable_path on all platforms #35627

Merged
merged 1 commit into from
May 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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