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 4, 2020
1 parent 84d7e67 commit 599af83
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 6 deletions.
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ Compiler/Runtime improvements
interoperability with C or other languages) might need to be updated; for
example any object that needs a stable address should be a `mutable struct`.

* 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

0 comments on commit 599af83

Please sign in to comment.