Skip to content

Commit fb986a0

Browse files
authored
Merge pull request #35627 from JuliaLang/sf/executable_path
2 parents 97f3571 + 00abaf8 commit fb986a0

File tree

3 files changed

+24
-6
lines changed

3 files changed

+24
-6
lines changed

NEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ Compiler/Runtime improvements
1515
-----------------------------
1616

1717

18+
* All platforms can now use `@executable_path` within `jl_load_dynamic_library()`.
19+
This allows executable-relative paths to be embedded within executables on all
20+
platforms, not just MacOS, which the syntax is borrowed from. ([#35627])
21+
1822
Command-line option changes
1923
---------------------------
2024

src/dlload.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,6 @@ static int endswith_extension(const char *path)
5959

6060
#define PATHBUF 4096
6161

62-
extern char *julia_bindir;
63-
6462
#define JL_RTLD(flags, FLAG) (flags & JL_RTLD_ ## FLAG ? RTLD_ ## FLAG : 0)
6563

6664
#ifdef _OS_WINDOWS_
@@ -136,7 +134,7 @@ JL_DLLEXPORT int jl_dlclose(void *handle)
136134

137135
JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags, int throw_err)
138136
{
139-
char path[PATHBUF];
137+
char path[PATHBUF], relocated[PATHBUF];
140138
int i;
141139
#ifdef _OS_WINDOWS_
142140
int err;
@@ -173,6 +171,9 @@ JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags,
173171
this branch permutes all base paths in DL_LOAD_PATH with all extensions
174172
note: skip when !jl_base_module to avoid UndefVarError(:DL_LOAD_PATH),
175173
and also skip for absolute paths
174+
We also do simple string replacement here for elements starting with `@executable_path/`.
175+
While these exist as OS concepts on Darwin, we want to use them on other platforms
176+
such as Windows, so we emulate them here.
176177
*/
177178
if (!abspath && jl_base_module != NULL) {
178179
jl_array_t *DL_LOAD_PATH = (jl_array_t*)jl_get_global(jl_base_module, jl_symbol("DL_LOAD_PATH"));
@@ -183,13 +184,21 @@ JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags,
183184
size_t len = strlen(dl_path);
184185
if (len == 0)
185186
continue;
187+
188+
// Is this entry supposed to be relative to the bindir?
189+
if (len >= 16 && strncmp(dl_path, "@executable_path", 16) == 0) {
190+
snprintf(relocated, PATHBUF, "%s%s", jl_options.julia_bindir, dl_path + 16);
191+
len = len - 16 + strlen(jl_options.julia_bindir);
192+
} else {
193+
strncpy(relocated, dl_path, len);
194+
}
186195
for (i = 0; i < n_extensions; i++) {
187196
const char *ext = extensions[i];
188197
path[0] = '\0';
189-
if (dl_path[len-1] == PATHSEPSTRING[0])
190-
snprintf(path, PATHBUF, "%s%s%s", dl_path, modname, ext);
198+
if (relocated[len-1] == PATHSEPSTRING[0])
199+
snprintf(path, PATHBUF, "%s%s%s", relocated, modname, ext);
191200
else
192-
snprintf(path, PATHBUF, "%s" PATHSEPSTRING "%s%s", dl_path, modname, ext);
201+
snprintf(path, PATHBUF, "%s" PATHSEPSTRING "%s%s", relocated, modname, ext);
193202
#ifdef _OS_WINDOWS_
194203
if (i == 0) { // LoadLibrary already tested the extensions, we just need to check the `stat` result
195204
#endif

stdlib/Libdl/src/Libdl.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ between shared libraries.
9999
100100
If the library cannot be found, this method throws an error, unless the keyword argument
101101
`throw_error` is set to `false`, in which case this method returns `nothing`.
102+
103+
!!! note
104+
From Julia 1.6 on, this method replaces paths starting with `@executable_path/` with
105+
the path to the Julia executable, allowing for relocatable relative-path loads. In
106+
Julia 1.5 and earlier, this only worked on macOS.
102107
"""
103108
function dlopen end
104109

0 commit comments

Comments
 (0)