From fb2b3a6fd609f01c46f5fe0dd22a8b0cf09f07d3 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 env variable, a number of
  workarounds have been used to provide shadow values.

  However, for a more robust installation using the -rpath at
  compilation time appears to be the best solution.

  Add MacOS-specific rpath handling (@loader_path, @executable_path)
  to the wmake rules.

  Library paths handled:
    - FOAM_USER_LIBBIN
    - FOAM_SITE_LIBBIN
    - FOAM_FOAM_EXT_LIBBIN, FOAM_EXT_LIBBIN/FOAM_MPI
    - FOAM_LIBBIN (implicitly)

  The executable rpaths are handled assuming a structure of
     install-path/bin
     install-path/lib

- no rpath added for c-only compilations since there are currently
  no c-only libraries or executables with dynamic loading

  The current default for MacOS is the link with rpath information.
  This can be disabled by including `~rpath` in the WM_COMPILE_CONTROL
---
 wmake/rules/darwin64Clang/c++            | 12 +++++++---
 wmake/rules/darwin64Clang/link-c++       |  9 +++++++
 wmake/rules/darwin64Clang/link-rpath-c++ | 15 ++++++++++++
 wmake/rules/darwin64Clang/rpath          | 30 ++++++++++++++++++++++++
 4 files changed, 63 insertions(+), 3 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/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..cc0b460b9ad
--- /dev/null
+++ b/wmake/rules/darwin64Clang/rpath
@@ -0,0 +1,30 @@
+#------------------------------------------------------------------------------
+
+# Compile-time rpath information:
+
+PROJECT_RPATH :=
+
+ifneq (,$(strip $(FOAM_USER_LIBBIN)))
+    PROJECT_RPATH += -rpath $(FOAM_USER_LIBBIN)
+endif
+ifneq (,$(strip $(FOAM_SITE_LIBBIN)))
+    PROJECT_RPATH += -rpath $(FOAM_SITE_LIBBIN)
+endif
+ifneq (,$(strip $(FOAM_EXT_LIBBIN)))
+    PROJECT_RPATH += -rpath $(FOAM_EXT_LIBBIN)
+    ifneq (,$(strip $(FOAM_MPI)))
+        PROJECT_RPATH += -rpath $(FOAM_EXT_LIBBIN)/$(FOAM_MPI)
+    endif
+endif
+
+# MacOS relative rpath:
+# Encode as @loader_path and recompose as @executable_path as needed
+
+PROJECT_RPATH += -rpath @loader_path
+ifneq (,$(strip $(FOAM_MPI)))
+    PROJECT_RPATH += -rpath @loader_path/$(FOAM_MPI)
+endif
+# Fallback for stubs (eg, missing MPI)
+PROJECT_RPATH += -rpath @loader_path/dummy
+
+#------------------------------------------------------------------------------
-- 
GitLab