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

Add automatic setting of LD_LIBRARY_PATH for Posix #2718

Open
wants to merge 1 commit into
base: stable
Choose a base branch
from
Open
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
16 changes: 16 additions & 0 deletions changelog/shared-load-path.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Automatic setting of ``LD_LIBRARY_PATH`` on Posix to executable directory.

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.

This enables shared library dependencies to work in these operations without setting the RPATH variable.
It is however still your responsibility to set the RPATH variable when handling installation or prior to debugging.
This can be done quite conveniently using the ``patchelf`` program via:

```sh
patchelf --force-rpath --set-rpath ~/projects/myproject ./executable
```

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.
It may not be required as OSX is supposed to look in the current working directory for shared libraries by default, similar to Windows.

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.
80 changes: 75 additions & 5 deletions source/dub/generators/build.d
Original file line number Diff line number Diff line change
Expand Up @@ -676,19 +676,89 @@ class BuildGenerator : ProjectGenerator {
if (!exe_file_path.absolute) exe_file_path = cwd ~ exe_file_path;
runPreRunCommands(m_project.rootPackage, m_project, settings, buildsettings);
logInfo("Running", Color.green, "%s %s", exe_file_path.relativeTo(runcwd), run_args.join(" "));

string[string] env;
foreach (aa; [buildsettings.environments, buildsettings.runEnvironments])
foreach (k, v; aa)
env[k] = v;

{
// When providing an AA to std.process it'll ignore the parent environment if Config.newEnv is set,
// so don't forget to copy over the global environment, otherwise it won't pass it into the child process.
// We'll do this because we want full control over the variables as we're overriding and appending to some.
env = environment.toAA;

// copy environment variables over to run with
foreach (aa; [buildsettings.environments, buildsettings.runEnvironments]) {
foreach (k, v; aa) {
switch(k) {
case "LD_LIBRARY_PATH":
case "DYLD_LIBRARY_PATH":
case "DYLD_FALLBACK_LIBRARY_PATH":
// for these we probably want to go with an append only approach, rather than setting it

if (k in env) {
env[k] = env[k] ~ ":" ~ v;
break;
} else
goto default;

default:
env[k] = v;
break;
}
}
}

// set the executable directory into the library search path if required
string exe_directory = exe_file_path.parentPath.toNativeString;

version(OSX) {
// We should not need to deal with OSX under the condition of when the current working directory
// is the directory of the executable.
// This has similar behavior to Windows.

// However OSX is quite weird, just having a slash in an appropriete environment variable
// DYLD_FALLBACK_LIBRARY_PATH, DYLD_LIBRARY_PATH, or LD_LIBRARY_PATH will lead to different behaviors.
// These behaviors are not always desirable and has lead to Homebrew community ignoring it completely.

// For the time being we won't support setting DYLD_FALLBACK_LIBRARY_PATH although it is implemented.
// Due to being unable to test the scenario when cwd != executable directory.

version(none) {
string previous = env.get("DYLD_FALLBACK_LIBRARY_PATH", null);

if (previous.length > 0) {
env["DYLD_FALLBACK_LIBRARY_PATH"] = exe_directory ~ ":" ~ previous;
} else
env["DYLD_FALLBACK_LIBRARY_PATH"] = exe_directory;
}
} else version(Posix) {
// When on Posix, we also want to ensure LD_LIBRARY_PATH is set to the programs directory
// By setting this environment variable we ensure any shared libraries in the same directory as
// our program will be found and loaded automatically.
// If we don't do this, dub run and dub test may not run due to missing shared libraries being found.

// Alternatively you can use patchelf, set LD_LIBRARY_PATH manually or set RPATH during linking.
// I.e. patchelf --force-rpath --set-rpath ~/projects/ProjectSidero/eventloop/examples/networking ./example_networking
// Or: export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:~/projects/ProjectSidero/eventloop/examples/networking
// For a D compiler this should work: -L-rpath=.

string previous = env.get("LD_LIBRARY_PATH", null);

if (previous.length > 0) {
env["LD_LIBRARY_PATH"] = exe_directory ~ ":" ~ previous;
} else
env["LD_LIBRARY_PATH"] = exe_directory;
}
}

if (settings.runCallback) {
auto res = execute([ exe_file_path.toNativeString() ] ~ run_args,
env, Config.none, size_t.max, runcwd.toNativeString());
env, Config.newEnv, size_t.max, runcwd.toNativeString());
WebFreak001 marked this conversation as resolved.
Show resolved Hide resolved
settings.runCallback(res.status, res.output);
settings.targetExitStatus = res.status;
runPostRunCommands(m_project.rootPackage, m_project, settings, buildsettings);
} else {
auto prg_pid = spawnProcess([ exe_file_path.toNativeString() ] ~ run_args,
env, Config.none, runcwd.toNativeString());
env, Config.newEnv, runcwd.toNativeString());
auto result = prg_pid.wait();
settings.targetExitStatus = result;
runPostRunCommands(m_project.rootPackage, m_project, settings, buildsettings);
Expand Down
Loading