From e4f2efec18571e1dfd7833724587e1c7a66f9be7 Mon Sep 17 00:00:00 2001
From: Alexey Matveichev <>
Date: Wed, 26 Jul 2023 18:06:24 +0200
Subject: [PATCH] COMP: add rpath information to MacOS compilation rules
 (#2948)

- since the Apple SIP (System Integrity Protection) clears environment
  variables such as DYLD_LIBRARY_PATH, a number of workarounds have
  been used to provide shadow values. However, for a more robust
  installation using -rpath at compilation time appears to be the
  better solution.

  In addition to the usual -rpath specification with absolute file
  paths, MacOS supports (@loader_path, @executable_path) as well.
  Now default to link with rpath information for MacOS, which can be
  disabled by adding `~rpath` in WM_COMPILE_CONTROL

  Explicit library paths handled:
    - FOAM_FOAM_EXT_LIBBIN, FOAM_EXT_LIBBIN/FOAM_MPI

  The executable rpaths are handled assuming a structure of
     install-path/bin
     install-path/lib/$(FOAM_MPI)
     install-path/lib

  Absolute compile-time paths for FOAM_USER_LIBBIN, FOAM_SITE_LIBBIN
  and FOAM_LIBBIN are not handled since these are either too fragile
  (FOAM_USER_LIBBIN and FOAM_SITE_LIBBIN values) or covered via
  @loader_path anyhow (FOAM_LIBBIN).

  Since the value of FOAM_MPI is a compile-time value, this rpath
  treatment makes the installation less suitable for runtime changes
  to the MPI vendor/version.

  Note: no rpath added for c-only compilations since there are
  currently no c-only libraries or executables with dynamic loading
---
 etc/bashrc                               |  3 ++-
 etc/cshrc                                |  3 ++-
 wmake/rules/darwin64Clang/c++            | 12 +++++++---
 wmake/rules/darwin64Clang/link-c++       |  9 +++++++
 wmake/rules/darwin64Clang/link-rpath-c++ | 15 ++++++++++++
 wmake/rules/darwin64Clang/rpath          | 30 ++++++++++++++++++++++++
 6 files changed, 67 insertions(+), 5 deletions(-)
 create mode 100644 wmake/rules/darwin64Clang/link-c++
 create mode 100644 wmake/rules/darwin64Clang/link-rpath-c++
 create mode 100644 wmake/rules/darwin64Clang/rpath

diff --git a/etc/bashrc b/etc/bashrc
index 02d084f0607..2e157923b74 100644
--- a/etc/bashrc
+++ b/etc/bashrc
@@ -6,7 +6,7 @@
 #    \\/     M anipulation  |
 #------------------------------------------------------------------------------
 #     Copyright (C) 2011-2016 OpenFOAM Foundation
-#     Copyright (C) 2016-2022 OpenCFD Ltd.
+#     Copyright (C) 2016-2023 OpenCFD Ltd.
 #------------------------------------------------------------------------------
 # License
 #     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@@ -87,6 +87,7 @@ export WM_COMPILE_OPTION=Opt
 #   +lld    : with  lld linker (with clang)
 #   +mold   : with mold linker (with clang)
 #   ~libz   : without libz compression
+#   ~rpath  : without rpath handling [MacOS]
 #   +openmp : with openmp
 #   ~openmp : without openmp
 #   +ccache : use ccache
diff --git a/etc/cshrc b/etc/cshrc
index 7f19beec7b9..5a42602f505 100644
--- a/etc/cshrc
+++ b/etc/cshrc
@@ -6,7 +6,7 @@
 #    \\/     M anipulation  |
 #------------------------------------------------------------------------------
 #     Copyright (C) 2011-2016 OpenFOAM Foundation
-#     Copyright (C) 2016-2022 OpenCFD Ltd.
+#     Copyright (C) 2016-2023 OpenCFD Ltd.
 #------------------------------------------------------------------------------
 # License
 #     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@@ -87,6 +87,7 @@ setenv WM_COMPILE_OPTION Opt
 #   +lld    : with  lld linker (with clang)
 #   +mold   : with mold linker (with clang)
 #   ~libz   : without libz compression
+#   ~rpath  : without rpath handling [MacOS]
 #   +openmp : with openmp
 #   ~openmp : without openmp
 #   +ccache : use ccache
diff --git a/wmake/rules/darwin64Clang/c++ b/wmake/rules/darwin64Clang/c++
index 7547b28d537..a9e092144ad 100644
--- a/wmake/rules/darwin64Clang/c++
+++ b/wmake/rules/darwin64Clang/c++
@@ -16,10 +16,16 @@ cctoo       = $(Ctoo)
 cpptoo      = $(Ctoo)
 cxxtoo      = $(Ctoo)
 
-LINK_LIBS   = $(c++DBUG)
 
-LINKLIBSO   = $(CC) $(c++FLAGS) -Wl,-dylib,-undefined,dynamic_lookup
+# Linking:
+# with or without rpath components on MacOS
+# - current default is with rpath unless explicitly disabled
 
-LINKEXE     = $(CC) $(c++FLAGS) -Wl,-execute,-undefined,dynamic_lookup
+ifneq (,$(findstring ~rpath,$(WM_COMPILE_CONTROL)))
+    include $(DEFAULT_RULES)/link-c++
+
+else
+    include $(DEFAULT_RULES)/link-rpath-c++
+endif
 
 #------------------------------------------------------------------------------
diff --git a/wmake/rules/darwin64Clang/link-c++ b/wmake/rules/darwin64Clang/link-c++
new file mode 100644
index 00000000000..d1c1f6e6a70
--- /dev/null
+++ b/wmake/rules/darwin64Clang/link-c++
@@ -0,0 +1,9 @@
+#------------------------------------------------------------------------------
+
+LINK_LIBS   = $(c++DBUG)
+
+LINKLIBSO   = $(CC) $(c++FLAGS) -Wl,-dylib,-undefined,dynamic_lookup
+
+LINKEXE     = $(CC) $(c++FLAGS) -Wl,-execute,-undefined,dynamic_lookup
+
+#------------------------------------------------------------------------------
diff --git a/wmake/rules/darwin64Clang/link-rpath-c++ b/wmake/rules/darwin64Clang/link-rpath-c++
new file mode 100644
index 00000000000..f7a7cd60018
--- /dev/null
+++ b/wmake/rules/darwin64Clang/link-rpath-c++
@@ -0,0 +1,15 @@
+#------------------------------------------------------------------------------
+include $(DEFAULT_RULES)/rpath
+
+LINK_LIBS   = $(c++DBUG)
+
+LINKLIBSO   = $(CC) $(c++FLAGS) \
+    $(PROJECT_RPATH) -dynamiclib \
+    -install_name @rpath/$(notdir $(LIB)$(EXT_SO)) \
+    -Wl,-dylib,-undefined,dynamic_lookup
+
+LINKEXE     = $(CC) $(c++FLAGS) \
+    $(subst @loader_path,@executable_path/../lib,$(PROJECT_RPATH)) \
+    -Wl,-execute,-undefined,dynamic_lookup
+
+#------------------------------------------------------------------------------
diff --git a/wmake/rules/darwin64Clang/rpath b/wmake/rules/darwin64Clang/rpath
new file mode 100644
index 00000000000..834b8f16934
--- /dev/null
+++ b/wmake/rules/darwin64Clang/rpath
@@ -0,0 +1,30 @@
+#------------------------------------------------------------------------------
+
+# Compile-time rpath information:
+
+FOAM_MPI ?= dummy
+ifeq (,$(strip $(FOAM_MPI)))
+    FOAM_MPI = dummy
+endif
+
+PROJECT_RPATH :=
+
+# ThirdParty libraries (FOAM_EXT_LIBBIN) : mpi-specific and serial
+ifneq (,$(strip $(FOAM_EXT_LIBBIN)))
+    ifneq (dummy,$(strip $(FOAM_MPI)))
+        PROJECT_RPATH += -rpath $(FOAM_EXT_LIBBIN)/$(FOAM_MPI)
+    endif
+    PROJECT_RPATH += -rpath $(FOAM_EXT_LIBBIN)
+endif
+
+# project libraries (FOAM_LIBBIN) : mpi-specific and serial
+# encode as @loader_path and recompose as @executable_path as needed
+ifneq (dummy,$(strip $(FOAM_MPI)))
+    PROJECT_RPATH += -rpath @loader_path/$(FOAM_MPI)
+endif
+PROJECT_RPATH += -rpath @loader_path
+
+# Fallback for stubs libraries (largely for missing MPI) - to be found last
+PROJECT_RPATH += -rpath @loader_path/dummy
+
+#------------------------------------------------------------------------------
-- 
GitLab