From f584ec97d09789853f8c7df3dccfa7768223ae24 Mon Sep 17 00:00:00 2001 From: Alexey Matveichev <> Date: Wed, 14 Jun 2023 10:45:45 +0200 Subject: [PATCH] ENH: reimplement Foam::dlOpen() for macOS (#2801) - The Apple SIP (System Integrity Protection) clears environment variables, which affects the behaviour of dynamic library loading (the DYLD_LIBRARY_PATH env variable). OpenFOAM shadows this variable as FOAM_LD_LIBRARY_PATH, which has been used to restore DYLD_LIBRARY_PATH (eg, in RunFunctions script). However, this solution is not quite complete, as it (a) requires sourcing of RunFunctions file, (b) additional errors appear depending on a user workflow. This changeset alleviates the problem by also iterating through paths stored in the shadow variable when loading dynamic libraries (if the DYLD_LIBRARY_PATH is empty). --- bin/foamJob | 7 ---- bin/tools/RunFunctions | 7 ---- src/OSspecific/POSIX/POSIX.C | 67 +++++++++++++++++++++++++++++------- 3 files changed, 54 insertions(+), 27 deletions(-) diff --git a/bin/foamJob b/bin/foamJob index 75a963e93c..6221eb67df 100755 --- a/bin/foamJob +++ b/bin/foamJob @@ -23,13 +23,6 @@ # If dispatching via foamExec foamExec="$WM_PROJECT_DIR/bin/tools/foamExec" -# Darwin workaround - SIP clearing DYLD_LIBRARY_PATH variable -if [ -n "$FOAM_LD_LIBRARY_PATH" ] && [ -z "$DYLD_LIBRARY_PATH" ] -then - export DYLD_LIBRARY_PATH="$FOAM_LD_LIBRARY_PATH" -fi - - #------------------------------------------------------------------------------ usage() { diff --git a/bin/tools/RunFunctions b/bin/tools/RunFunctions index f8482f63f2..68364b7738 100644 --- a/bin/tools/RunFunctions +++ b/bin/tools/RunFunctions @@ -25,13 +25,6 @@ # Basic sanity checks [ -d "$FOAM_TUTORIALS" ] || echo "No OpenFOAM tutorials? : $FOAM_TUTORIALS" 1>&2 -# Darwin workaround - SIP clearing DYLD_LIBRARY_PATH variable -if [ -n "$FOAM_LD_LIBRARY_PATH" ] && [ -z "$DYLD_LIBRARY_PATH" ] -then - export DYLD_LIBRARY_PATH="$FOAM_LD_LIBRARY_PATH" -fi - - #------------------------------------------------------------------------------ # diff --git a/src/OSspecific/POSIX/POSIX.C b/src/OSspecific/POSIX/POSIX.C index 826ac47021..dffd5e0a54 100644 --- a/src/OSspecific/POSIX/POSIX.C +++ b/src/OSspecific/POSIX/POSIX.C @@ -41,6 +41,7 @@ Description #include "timer.H" #include "DynamicList.H" #include "CStringList.H" +#include "stringOps.H" #include "IOstreams.H" #include "Pstream.H" @@ -108,6 +109,52 @@ static inline void redirects(const bool bg) } +// Library loading is normally simply via dlopen(), +// but SIP (System Integrity Protection) on Apple will generally +// clear out the DYLD_LIBRARY_PATH set from shell scripts. +// We thus have FOAM_LD_LIBRARY_PATH as a shadow parameter and use +// that to attempt loading ourselves +static inline void* loadLibrary(const Foam::fileName& libName) +{ + constexpr int ldflags = (RTLD_LAZY|RTLD_GLOBAL); + +#ifdef __APPLE__ + const char* normal = nullptr; + const char* shadow = nullptr; + + if + ( + !libName.isAbsolute() + && ((normal = ::getenv("DYLD_LIBRARY_PATH")) == nullptr || !*normal) + && ((shadow = ::getenv("FOAM_LD_LIBRARY_PATH")) != nullptr && *shadow) + ) + { + // SIP appears to have cleared DYLD_LIBRARY_PATH but the + // shadow parameter is available + + const Foam::string ldPaths(shadow); + const auto paths = Foam::stringOps::split(ldPaths, ':'); + + for (const auto& p : paths) + { + if (p.length()) // Split removes empty, but be paranoid + { + const Foam::fileName fullPath(p.str()/libName); + void* handle = ::dlopen(fullPath.c_str(), ldflags); + if (handle) + { + return handle; + } + } + } + } +#endif + + // Regular loading + return ::dlopen(libName.c_str(), ldflags); +} + + // * * * * * * * * * * * * * * * * Local Classes * * * * * * * * * * * * * * // namespace Foam @@ -1752,16 +1799,13 @@ int Foam::system(const Foam::UList& command, const bool bg) void* Foam::dlOpen(const fileName& libName, const bool check) { - constexpr int ldflags = (RTLD_LAZY|RTLD_GLOBAL); - if (POSIX::debug) { std::cout - << "dlOpen(const fileName&)" - << " : dlopen of " << libName << std::endl; + << "dlopen() of " << libName << std::endl; } - void* handle = ::dlopen(libName.c_str(), ldflags); + void* handle = loadLibrary(libName); if (!handle) { @@ -1771,13 +1815,12 @@ void* Foam::dlOpen(const fileName& libName, const bool check) { // Try with 'lib' prefix libso = "lib" + libName; - handle = ::dlopen(libso.c_str(), ldflags); + handle = loadLibrary(libso); if (POSIX::debug) { std::cout - << "dlOpen(const fileName&)" - << " : dlopen of " << libso << std::endl; + << " dlopen() as " << libso << std::endl; } } else @@ -1790,13 +1833,12 @@ void* Foam::dlOpen(const fileName& libName, const bool check) if (!handle && !libso.has_ext(EXT_SO)) { libso.replace_ext(EXT_SO); - handle = ::dlopen(libso.c_str(), ldflags); + handle = loadLibrary(libso); if (POSIX::debug) { std::cout - << "dlOpen(const fileName&)" - << " : dlopen of " << libso << std::endl; + << " dlopen() as " << libso << std::endl; } } } @@ -1810,8 +1852,7 @@ void* Foam::dlOpen(const fileName& libName, const bool check) if (POSIX::debug) { std::cout - << "dlOpen(const fileName&)" - << " : dlopen of " << libName + << "dlopen() of " << libName << " handle " << handle << std::endl; }