Repository: spack/spack

Issue:
macOS Sierra load commands size limit due to extra unused LC_RPATH in a big DAG
i recently hit an error when trying to run my application linked against `deal.II` built by `Spack`:

```
36: dyld: Library not loaded: /dealii-develop-cymbkwb6lxj7ttkk3vfdfuua3oto5tlv/lib/libdeal_II.8.5.0-pre.dylib
36:   Referenced from: /blabla/executable.release
36:   Reason: no suitable image found.  Did find:
36:     /dealii-develop-cymbkwb6lxj7ttkk3vfdfuua3oto5tlv/lib/libdeal_II.8.5.0-pre.dylib: malformed mach-o: load commands size (34832) > 32768
```

Similar issues are mentioned here http://stackoverflow.com/questions/39646221/stack-gives-dyld-malformed-mach-o . 

From https://github.com/commercialhaskell/stack/issues/2577#issuecomment-247859070

> Sierra has a new limit on the "load commands size" of a shared library (that you can see mentioned in the error message) which includes the paths to its dependencies, and Stack's many dependencies and long directory paths exceed this limit.

By comparing `otool -l libdeal_II.8.5.0-pre.dylib` for Spack's build of deal.II and the manual build with `filesystem views` with all dependencies build by Spack, i found out that the number of load commands is significantly different: 149 (manual build) vs 196 (Spack's build). More precisely, Spack's build contain a lot of **non-needed LC_RPATH load commands for the whole DAG**:

```
Load command 147
          cmd LC_RPATH
      cmdsize 144
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/dealii-develop-t4bhfdej7uvwxtptd7aqiwbt2vy5s4vg/lib64 (offset 12)
Load command 148
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/matio-1.5.2-qhiecti6wjjyhpvxu6arihvtjg64vbjp/lib (offset 12)
Load command 149
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/glm-0.9.7.1-cho3xqsfqgjqgeixk3dm4wsu6zvybd3d/lib (offset 12)
Load command 150
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/trilinos-12.8.1-wysvnbzxvfs4d7w7ykf5tnn7abn3o54y/lib (offset 12)
Load command 151
          cmd LC_RPATH
      cmdsize 144
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/suite-sparse-4.5.3-puw3cvbgsogepjhte6rxbv2kllpfqw3l/lib (offset 12)
Load command 152
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/slepc-3.7.1-i4ohv53ekcjvk6xf757sjzk7v57fd7ff/lib (offset 12)
Load command 153
          cmd LC_RPATH
      cmdsize 144
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/superlu-dist-5.0.0-drwk4u6f45fbsg7t56whtwb7zjiwgbjt/lib (offset 12)
Load command 154
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/parmetis-4.0.3-dzk264ptt7botxjxsk5k76y3s4gbb6tl/lib (offset 12)
Load command 155
          cmd LC_RPATH
      cmdsize 144
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/netlib-scalapack-2.0.2-doua7ojkqkesi7jct6wlur53r4uw7lkw/lib (offset 12)
Load command 156
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/mumps-5.0.1-6646z4abavd4lxrhjb3wxe2r3eyyaxwy/lib (offset 12)
Load command 157
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/hypre-2.10.1-yhulamj2l3tddpijnn3opxzu6gyx2lso/lib (offset 12)
Load command 158
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/petsc-3.7.2-tyvehbbwmne2e65rhc62vgnk2toybcvw/lib (offset 12)
Load command 159
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/lua-5.3.2-gskrogb6mzyq6ji2am6j5gpsdpzeclcn/lib (offset 12)
Load command 160
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/p4est-1.1-a3bmrr2m3m7yngrjpxlo7gmy53k3u7d3/lib (offset 12)
Load command 161
          cmd LC_RPATH
      cmdsize 144
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/gettext-0.19.8.1-7pquryskg4iowtdu2qvjhgftsr2ndohj/lib (offset 12)
Load command 162
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/netcdf-cxx-4.2-hs3x65yhlbc4j6uhwwee4rj2jpbk7anb/lib (offset 12)
Load command 163
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/netcdf-4.4.1-g7xfv2hylaxbkfsdm5a3bsxadnzenr76/lib (offset 12)
Load command 164
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/muparser-2.2.5-amdu7v5ogbithg7kj4iaefox5zmrshjr/lib (offset 12)
Load command 165
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/metis-5.1.0-d5se4hgztkzjueyr55sl4tthuxhrfysg/lib (offset 12)
Load command 166
          cmd LC_RPATH
      cmdsize 144
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/hdf5-1.10.0-patch1-gjsz6n5uxyzxrtzr5vcefrdmga5hpqas/lib (offset 12)
Load command 167
          cmd LC_RPATH
      cmdsize 128
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/gsl-2.1-2aofnwvdsvvvm63qfeafems2udotouzt/lib (offset 12)
Load command 168
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/sqlite-3.8.5-wbrfqaigms2fpt36rijhfh3xvmjcptu6/lib (offset 12)
Load command 169
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/readline-6.3-o7fyvnwa3cyg3ndcg4nwwvvcivwf5qhh/lib (offset 12)
Load command 170
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/python-2.7.12-rol3whbb472kx3xpjtiog7s2575lihqd/lib (offset 12)
Load command 171
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/boost-1.61.0-nud3yn3vs7smers3owoaeh5toma7u5ae/lib (offset 12)
Load command 172
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/libtool-2.4.6-7x6h7cfe5k3bi56k2jnecqkpa7dtp6w7/lib (offset 12)
Load command 173
          cmd LC_RPATH
      cmdsize 144
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/libpciaccess-0.13.4-4wd7llktkvcziobu72c7zaevnojssvbh/lib (offset 12)
Load command 174
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/hwloc-1.11.4-6m3qkszjq2vtfrdo23hauwpza4tpybmb/lib (offset 12)
Load command 175
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/openmpi-2.0.1-ee4uix6ycr3lpermorwskgr7y6w4kayl/lib (offset 12)
Load command 176
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/openblas-0.2.19-7qdxwznmqzlbqtusssagtxkypivod6ct/lib (offset 12)
Load command 177
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/ncurses-6.0-sflzz4eoc2zxhxje5z3rtcbylrujuu4h/lib (offset 12)
Load command 178
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/libsigsegv-2.10-cotbexnf4mm6u2eueit5uorf3xtvxbpw/lib (offset 12)
Load command 179
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/gmp-6.1.1-vj3e2ygpbbbo2mmyomdzuizeboramub7/lib (offset 12)
Load command 180
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/nettle-3.2-fioxw3hgk3gp57os6sxqfvmmlijad6al/lib (offset 12)
Load command 181
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/lzo-2.09-2dk4mx6m2kg65y34ndw6t3eh2iq7glkx/lib (offset 12)
Load command 182
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/lzma-4.32.7-2ka7vkselplzy5hj3iyvquej7frhidjk/lib (offset 12)
Load command 183
          cmd LC_RPATH
      cmdsize 128
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/lz4-131-e6cru3imydxci7aaskrssjo6vjya55qy/lib (offset 12)
Load command 184
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/xz-5.2.2-l3ntfowzw5tk2zbs3bmuy2nei4i3rqzc/lib (offset 12)
Load command 185
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/libxml2-2.9.4-id5me6ic2r5eqcozfuhfg2pbyx4txgd6/lib (offset 12)
Load command 186
          cmd LC_RPATH
      cmdsize 144
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/libarchive-3.2.1-a6vndqjqcae2rtj7tk4qcvqoaiin3nfr/lib (offset 12)
Load command 187
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/expat-2.2.0-lmk3zwfdwzemdjrrkrehldzjpuvmkbxe/lib (offset 12)
Load command 188
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/zlib-1.2.8-yefo4t2eiiwps7wrbvvgauo2z4ozxlyg/lib (offset 12)
Load command 189
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/openssl-1.0.2j-k6g3fa3rrglj5wenvowtaruuvb6nmn6t/lib (offset 12)
Load command 190
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/curl-7.50.3-ktu7vhoi6p4fmbldeapjqzvkvct6z6dk/lib (offset 12)
Load command 191
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/arpack-ng-3.4.0-pu5wkjbz4hbozonicrjrys4dwjkkdciv/lib (offset 12)
Load command 192
          cmd LC_RPATH
      cmdsize 136
         path /Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple/tbb-4.4.4-s7sej2p65l4a5jzdmp5hwm6bn4pwzf35/lib (offset 12)
```

Note that many of those are coming from dependencies of dependencies like `libpciaccess` or `libtool` or `lua` etc.

At this point my best bet is that it is related to compiler wrappers. The quick solution would be to have a global flag which can be used to control whether those things are added or not by Spack. In case of deal.II which configures with `cmake`, those `LC_RPATH` are not needed and make the build broken on macOS Sierra (and potentially on any other OS with similar limits).

p.s. attached is the output of `otool -l` for Spack's build deal.II and manually built one.
[dealii_manual.txt](https://github.com/LLNL/spack/files/499953/dealii_manual.txt)
[dealii_spack.txt](https://github.com/LLNL/spack/files/499954/dealii_spack.txt)

p.p.s. useful info https://www.reinterpretcast.com/hello-world-mach-o



Discussion:
relevant discussion is https://ghc.haskell.org/trac/ghc/ticket/12479

> We did some investigation last night in IRC and came to the conclusion that the runtime loader in Sierra has a new limit on the sizeofcmds field which is the total size of all the load commands in the dynamic library.

Additionally one can use `@rpath` to reduce the size of paths as `/Users/davydden/spack/opt/spack/darwin-sierra-x86_64/clang-8.0.0-apple` is always the same in this case, see https://ghc.haskell.org/trac/ghc/ticket/12479#comment:16

The Spack `RPATH` currently scales with the size of the full DAG but probably doesn't need to.  We could change this in `build_environment.py` to only use immediate dependencies, not transitive ones.  I have not sat down and thought about it really hard, but I believe that should work fine with `RPATH` without any ([additional](http://blog.qt.io/blog/2011/10/28/rpath-and-runpath/)) negative consequences for people who might want to use `RUNPATH` on Linux.

> The Spack RPATH currently scales with the size of the full DAG but probably doesn't need to. We could change this in build_environment.py to only use immediate dependencies, not transitive ones.

yes, i think this would already remove a lot of unneeded load commands.

@tgamblin i presume you mean `get_rpaths` function? Looking at [spack.spec module](http://spack.readthedocs.io/en/latest/spack.html#module-spack.spec), i don't see how would one force to return only immediate dependencies.

@mathstuf: i think you would also have an opinion on this discussion related to unused `LC_RPATH`.

How about this for an "ultimate" solution... when you install a Spack-built package, create a directory in the install tree that symlinks to its required dependencies.  Any library you want to RPATH to, you symlink to it instead.  Then put just that single directory in your executables.

To be specific, suppose I've installed myproj.  Then the install tree would look something like:

```
spack/.../myproj-jf23jf8394jf
    bin/
       myexe      [RPATH: spack/.../myproj-jfklsjfej/spacklibs
    spacklibs/
        libncurses.so -> /spack/..../ncurses..../lib/libncurses.so
        libnetcdf.so -> /spack/......
```

@citibeth: 

> How about this for an "ultimate" solution...

AFAICT this alone won't work as when I build `deal.II` manually with Spack's `filesystem views` the resulting library has full paths for its dependencies (i.e. `spack/../ncurses-blabla-hashahs/...`). Thats because `install_name` (or `soname`) of libraries is set. Have a look at the two attached files in the OP to see what i mean.


Resolving patch:
diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -77,6 +77,8 @@
 #
 SPACK_ENV_PATH = 'SPACK_ENV_PATH'
 SPACK_DEPENDENCIES = 'SPACK_DEPENDENCIES'
+SPACK_RPATH_DEPS = 'SPACK_RPATH_DEPS'
+SPACK_LINK_DEPS = 'SPACK_LINK_DEPS'
 SPACK_PREFIX = 'SPACK_PREFIX'
 SPACK_INSTALL = 'SPACK_INSTALL'
 SPACK_DEBUG = 'SPACK_DEBUG'
@@ -254,9 +256,15 @@ def set_build_environment_variables(pkg, env, dirty=False):
     env.set_path(SPACK_ENV_PATH, env_paths)
 
     # Prefixes of all of the package's dependencies go in SPACK_DEPENDENCIES
-    dep_prefixes = [d.prefix
-                    for d in pkg.spec.traverse(root=False, deptype='build')]
+    dep_prefixes = [d.prefix for d in
+                    pkg.spec.traverse(root=False, deptype=('build', 'link'))]
     env.set_path(SPACK_DEPENDENCIES, dep_prefixes)
+
+    # These variables control compiler wrapper behavior
+    env.set_path(SPACK_RPATH_DEPS, [d.prefix for d in get_rpath_deps(pkg)])
+    env.set_path(SPACK_LINK_DEPS, [
+        d.prefix for d in pkg.spec.traverse(root=False, deptype=('link'))])
+
     # Add dependencies to CMAKE_PREFIX_PATH
     env.set_path('CMAKE_PREFIX_PATH', dep_prefixes)
 
@@ -288,8 +296,8 @@ def set_build_environment_variables(pkg, env, dirty=False):
                 env.remove_path('PATH', p)
 
     # Add bin directories from dependencies to the PATH for the build.
-    bin_dirs = reversed(
-        filter(os.path.isdir, ['%s/bin' % prefix for prefix in dep_prefixes]))
+    bin_dirs = reversed(filter(os.path.isdir, [
+        '%s/bin' % d.prefix for d in pkg.spec.dependencies(deptype='build')]))
     for item in bin_dirs:
         env.prepend_path('PATH', item)
 
@@ -382,10 +390,15 @@ def set_module_variables_for_package(pkg, module):
     m.dso_suffix = dso_suffix
 
 
+def get_rpath_deps(pkg):
+    """We only need to RPATH immediate dependencies."""
+    return pkg.spec.dependencies(deptype='link')
+
+
 def get_rpaths(pkg):
     """Get a list of all the rpaths for a package."""
     rpaths = [pkg.prefix.lib, pkg.prefix.lib64]
-    deps = pkg.spec.dependencies(deptype='link')
+    deps = get_rpath_deps(pkg)
     rpaths.extend(d.prefix.lib for d in deps
                   if os.path.isdir(d.prefix.lib))
     rpaths.extend(d.prefix.lib64 for d in deps


Test patch:
diff --git a/lib/spack/spack/test/cc.py b/lib/spack/spack/test/cc.py
--- a/lib/spack/spack/test/cc.py
+++ b/lib/spack/spack/test/cc.py
@@ -223,6 +223,8 @@ def test_dep_rpath(self):
     def test_dep_include(self):
         """Ensure a single dependency include directory is added."""
         os.environ['SPACK_DEPENDENCIES'] = self.dep4
+        os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
+        os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
         self.check_cc('dump-args', test_command,
                       self.realcc + ' ' +
                       '-Wl,-rpath,' + self.prefix + '/lib ' +
@@ -233,6 +235,8 @@ def test_dep_include(self):
     def test_dep_lib(self):
         """Ensure a single dependency RPATH is added."""
         os.environ['SPACK_DEPENDENCIES'] = self.dep2
+        os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
+        os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
         self.check_cc('dump-args', test_command,
                       self.realcc + ' ' +
                       '-Wl,-rpath,' + self.prefix + '/lib ' +
@@ -241,10 +245,34 @@ def test_dep_lib(self):
                       '-Wl,-rpath,' + self.dep2 + '/lib64 ' +
                       ' '.join(test_command))
 
+    def test_dep_lib_no_rpath(self):
+        """Ensure a single dependency link flag is added with no dep RPATH."""
+        os.environ['SPACK_DEPENDENCIES'] = self.dep2
+        os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
+        self.check_cc('dump-args', test_command,
+                      self.realcc + ' ' +
+                      '-Wl,-rpath,' + self.prefix + '/lib ' +
+                      '-Wl,-rpath,' + self.prefix + '/lib64 ' +
+                      '-L' + self.dep2 + '/lib64 ' +
+                      ' '.join(test_command))
+
+    def test_dep_lib_no_lib(self):
+        """Ensure a single dependency RPATH is added with no -L."""
+        os.environ['SPACK_DEPENDENCIES'] = self.dep2
+        os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
+        self.check_cc('dump-args', test_command,
+                      self.realcc + ' ' +
+                      '-Wl,-rpath,' + self.prefix + '/lib ' +
+                      '-Wl,-rpath,' + self.prefix + '/lib64 ' +
+                      '-Wl,-rpath,' + self.dep2 + '/lib64 ' +
+                      ' '.join(test_command))
+
     def test_all_deps(self):
         """Ensure includes and RPATHs for all deps are added. """
         os.environ['SPACK_DEPENDENCIES'] = ':'.join([
             self.dep1, self.dep2, self.dep3, self.dep4])
+        os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
+        os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
 
         # This is probably more constrained than it needs to be; it
         # checks order within prepended args and doesn't strictly have
@@ -273,6 +301,8 @@ def test_ld_deps(self):
         """Ensure no (extra) -I args or -Wl, are passed in ld mode."""
         os.environ['SPACK_DEPENDENCIES'] = ':'.join([
             self.dep1, self.dep2, self.dep3, self.dep4])
+        os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
+        os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
 
         self.check_ld('dump-args', test_command,
                       'ld ' +
@@ -290,10 +320,46 @@ def test_ld_deps(self):
 
                       ' '.join(test_command))
 
+    def test_ld_deps_no_rpath(self):
+        """Ensure SPACK_RPATH_DEPS controls RPATHs for ld."""
+        os.environ['SPACK_DEPENDENCIES'] = ':'.join([
+            self.dep1, self.dep2, self.dep3, self.dep4])
+        os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
+
+        self.check_ld('dump-args', test_command,
+                      'ld ' +
+                      '-rpath ' + self.prefix + '/lib ' +
+                      '-rpath ' + self.prefix + '/lib64 ' +
+
+                      '-L' + self.dep3 + '/lib64 ' +
+                      '-L' + self.dep2 + '/lib64 ' +
+                      '-L' + self.dep1 + '/lib ' +
+
+                      ' '.join(test_command))
+
+    def test_ld_deps_no_link(self):
+        """Ensure SPACK_LINK_DEPS controls -L for ld."""
+        os.environ['SPACK_DEPENDENCIES'] = ':'.join([
+            self.dep1, self.dep2, self.dep3, self.dep4])
+        os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
+
+        self.check_ld('dump-args', test_command,
+                      'ld ' +
+                      '-rpath ' + self.prefix + '/lib ' +
+                      '-rpath ' + self.prefix + '/lib64 ' +
+
+                      '-rpath ' + self.dep3 + '/lib64 ' +
+                      '-rpath ' + self.dep2 + '/lib64 ' +
+                      '-rpath ' + self.dep1 + '/lib ' +
+
+                      ' '.join(test_command))
+
     def test_ld_deps_reentrant(self):
         """Make sure ld -r is handled correctly on OS's where it doesn't
            support rpaths."""
         os.environ['SPACK_DEPENDENCIES'] = ':'.join([self.dep1])
+        os.environ['SPACK_RPATH_DEPS'] = os.environ['SPACK_DEPENDENCIES']
+        os.environ['SPACK_LINK_DEPS'] = os.environ['SPACK_DEPENDENCIES']
 
         os.environ['SPACK_SHORT_SPEC'] = "foo@1.2=linux-x86_64"
         reentrant_test_command = ['-r'] + test_command