diff --git a/lib/spack/spack/main.py b/lib/spack/spack/main.py index 00131114f6..8d4e73bc65 100644 --- a/lib/spack/spack/main.py +++ b/lib/spack/spack/main.py @@ -855,6 +855,23 @@ def shell_set(var, value): shell_set("_sp_module_prefix", "not_installed") +def restore_macos_dyld_vars(): + """ + Spack mutates DYLD_* variables in `spack load` and `spack env activate`. + Unlike Linux, macOS SIP clears these variables in new processes, meaning + that os.environ["DYLD_*"] in our Python process is not the same as the user's + shell. Therefore, we store the user's DYLD_* variables in SPACK_DYLD_* and + restore them here. + """ + if not sys.platform == "darwin": + return + + for dyld_var in ("DYLD_LIBRARY_PATH", "DYLD_FALLBACK_LIBRARY_PATH"): + stored_var_name = f"SPACK_{dyld_var}" + if stored_var_name in os.environ: + os.environ[dyld_var] = os.environ[stored_var_name] + + def _main(argv=None): """Logic for the main entry point for the Spack command. @@ -887,18 +904,6 @@ def _main(argv=None): parser.add_argument("command", nargs=argparse.REMAINDER) args, unknown = parser.parse_known_args(argv) - # Recover stored LD_LIBRARY_PATH variables from spack shell function - # This is necessary because MacOS System Integrity Protection clears - # (DY?)LD_LIBRARY_PATH variables on process start. - # Spack clears these variables before building and installing packages, - # but needs to know the prior state for commands like `spack load` and - # `spack env activate that modify the user environment. - recovered_vars = ("LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH", "DYLD_FALLBACK_LIBRARY_PATH") - for var in recovered_vars: - stored_var_name = "SPACK_%s" % var - if stored_var_name in os.environ: - os.environ[var] = os.environ[stored_var_name] - # Just print help and exit if run with no arguments at all no_args = (len(sys.argv) == 1) if argv is None else (len(argv) == 0) if no_args: @@ -921,6 +926,9 @@ def _main(argv=None): # scopes, then environment configuration here. # ------------------------------------------------------------------------ + # Make spack load / env activate work on macOS + restore_macos_dyld_vars() + # make spack.config aware of any command line configuration scopes if args.config_scopes: spack.config.command_line_scopes = args.config_scopes diff --git a/share/spack/csh/spack.csh b/share/spack/csh/spack.csh index c9f6242a3e..e344d589f8 100644 --- a/share/spack/csh/spack.csh +++ b/share/spack/csh/spack.csh @@ -27,12 +27,9 @@ # avoids the need to come up with a user-friendly naming scheme for # spack module files. ######################################################################## -# Store LD_LIBRARY_PATH variables from spack shell function +# Store DYLD_* variables from spack shell function # This is necessary because MacOS System Integrity Protection clears # variables that affect dyld on process start. -if ( ${?LD_LIBRARY_PATH} ) then - setenv SPACK_LD_LIBRARY_PATH $LD_LIBRARY_PATH -endif if ( ${?DYLD_LIBRARY_PATH} ) then setenv SPACK_DYLD_LIBRARY_PATH $DYLD_LIBRARY_PATH endif diff --git a/share/spack/setup-env.sh b/share/spack/setup-env.sh index d3a97d9af6..7d4554359f 100755 --- a/share/spack/setup-env.sh +++ b/share/spack/setup-env.sh @@ -47,10 +47,10 @@ export _sp_initializing=true _spack_shell_wrapper() { - # Store LD_LIBRARY_PATH variables from spack shell function + # Store DYLD_* variables from spack shell function # This is necessary because MacOS System Integrity Protection clears # variables that affect dyld on process start. - for var in LD_LIBRARY_PATH DYLD_LIBRARY_PATH DYLD_FALLBACK_LIBRARY_PATH; do + for var in DYLD_LIBRARY_PATH DYLD_FALLBACK_LIBRARY_PATH; do eval "if [ -n \"\${${var}-}\" ]; then export SPACK_$var=\${${var}}; fi" done