Skip to content

Commit 194747a

Browse files
committed
Add automatic setting of LD_LIBRARY_PATH for Posix
1 parent 0e32807 commit 194747a

File tree

2 files changed

+88
-3
lines changed

2 files changed

+88
-3
lines changed

changelog/shared-load-path.dd

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Automatic setting of ``LD_LIBRARY_PATH`` on Posix to executable directory.
2+
3+
When using dub to run a D program via ``run`` or ``test`` operations it will now automatically add for Posix targets except for OSX the ``LD_LIBRARY_PATH`` environment variable to the directory of the executable.
4+
5+
This enables shared library dependencies to work in these operations without setting the RPATH variable.
6+
It is however still your responsibility to set the RPATH variable when handling installation or prior to debugging.
7+
This can be done quite conveniently using the ``patchelf`` program via:
8+
9+
```sh
10+
patchelf --force-rpath --set-rpath ~/projects/myproject ./executable
11+
```
12+
13+
OSX support has been disabled, support for ``DYLD_FALLBACK_LIBRARY_PATH`` has been written, however this will need separate testing as OSX has some weird behavior surrounding these environment variables.
14+
It may not be required as OSX is supposed to look in the current working directory for shared libraries by default, similar to Windows.
15+
16+
As a consequence of this change the environment variables ``LD_LIBRARY_PATH``, ``DYLD_LIBRARY_PATH``, and ``DYLD_FALLBACK_LIBRARY_PATH`` all support appending when used as an environment variable instead of overriding.

source/dub/generators/build.d

+72-3
Original file line numberDiff line numberDiff line change
@@ -676,10 +676,79 @@ class BuildGenerator : ProjectGenerator {
676676
if (!exe_file_path.absolute) exe_file_path = cwd ~ exe_file_path;
677677
runPreRunCommands(m_project.rootPackage, m_project, settings, buildsettings);
678678
logInfo("Running", Color.green, "%s %s", exe_file_path.relativeTo(runcwd), run_args.join(" "));
679+
679680
string[string] env;
680-
foreach (aa; [buildsettings.environments, buildsettings.runEnvironments])
681-
foreach (k, v; aa)
682-
env[k] = v;
681+
682+
{
683+
// Don't forget to copy over the global environment,
684+
// otherwise it won't pass into the child process.
685+
env = environment.toAA;
686+
687+
// copy environment variables over to run with
688+
foreach (aa; [buildsettings.environments, buildsettings.runEnvironments]) {
689+
foreach (k, v; aa) {
690+
switch(k) {
691+
case "LD_LIBRARY_PATH":
692+
case "DYLD_LIBRARY_PATH":
693+
case "DYLD_FALLBACK_LIBRARY_PATH":
694+
// for these we probably want to go with an append only approach, rather than setting it
695+
696+
if (k in env) {
697+
env[k] = env[k] ~ ":" ~ v;
698+
break;
699+
} else
700+
goto default;
701+
702+
default:
703+
env[k] = v;
704+
break;
705+
}
706+
}
707+
}
708+
709+
// set the executable directory into the library search path if required
710+
string exe_directory = exe_file_path.parentPath.toNativeString;
711+
712+
version(OSX) {
713+
// We should not need to deal with OSX under the condition of when the current working directory
714+
// is the directory of the executable.
715+
// This has similar behavior to Windows.
716+
717+
// However OSX is quite weird, just having a slash in an appropriete environment variable
718+
// DYLD_FALLBACK_LIBRARY_PATH, DYLD_LIBRARY_PATH, or LD_LIBRARY_PATH will lead to different behaviors.
719+
// These behaviors are not always desirable and has lead to Homebrew community ignoring it completely.
720+
721+
// For the time being we won't support setting DYLD_FALLBACK_LIBRARY_PATH although it is implemented.
722+
// Due to being unable to test the scenario when cwd != executable directory.
723+
724+
version(none) {
725+
string previous = env.get("DYLD_FALLBACK_LIBRARY_PATH", null);
726+
727+
if (previous.length > 0) {
728+
env["DYLD_FALLBACK_LIBRARY_PATH"] = exe_directory ~ ":" ~ previous;
729+
} else
730+
env["DYLD_FALLBACK_LIBRARY_PATH"] = exe_directory;
731+
}
732+
} else version(Posix) {
733+
// When on Posix, we also want to ensure LD_LIBRARY_PATH is set to the programs directory
734+
// By setting this environment variable we ensure any shared libraries in the same directory as
735+
// our program will be found and loaded automatically.
736+
// If we don't do this, dub run and dub test may not run due to missing shared libraries being found.
737+
738+
// Alternatively you can use patchelf, set LD_LIBRARY_PATH manually or set RPATH during linking.
739+
// I.e. patchelf --force-rpath --set-rpath ~/projects/ProjectSidero/eventloop/examples/networking ./example_networking
740+
// Or: export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:~/projects/ProjectSidero/eventloop/examples/networking
741+
// For a D compiler this should work: -L-rpath=.
742+
743+
string previous = env.get("LD_LIBRARY_PATH", null);
744+
745+
if (previous.length > 0) {
746+
env["LD_LIBRARY_PATH"] = exe_directory ~ ":" ~ previous;
747+
} else
748+
env["LD_LIBRARY_PATH"] = exe_directory;
749+
}
750+
}
751+
683752
if (settings.runCallback) {
684753
auto res = execute([ exe_file_path.toNativeString() ] ~ run_args,
685754
env, Config.none, size_t.max, runcwd.toNativeString());

0 commit comments

Comments
 (0)