Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make macOS installed libraries more relocatable #26608

Merged
merged 10 commits into from
Oct 18, 2021

Conversation

sethrj
Copy link
Contributor

@sethrj sethrj commented Oct 8, 2021

Fixes #26544 and #26552 by adding a post-install step on macOS for autotools-based and package-based packages. The fixup will:

  • Replace hard-coded $prefix/foo.dylib paths with @rpath/foo.dylib if and only if $prefix is in the library's list of rpaths
  • Replace $spack_root/$other/bar.dylib with @rpath/bar.dylib and add $spack_root/$other to the rpath list
  • Remove duplicate rpath entries due to duplication between libtool and spack's compiler wrapper

I used the following script to successfully fix up a number of affected (already installed) libraries:

#!/usr/bin/env spack-python

import spack.store
from spack.relocate import fixup_macos_rpaths

def needs_fixup(spec):
    if spec.external or spec.virtual:
        return False
    return True

def fixup(specs):
    for spec in specs:
        fixup_macos_rpaths(spec)
        break

def main():
    specs = [s for s in spack.store.db.query() if needs_fixup(s)]
    fixup(specs)

if __name__ == '__main__':
    main()

Of course, libraries that link against the previously broken ones are unaffected since they may still contain hard-coded library IDs. But newly installed binaries from here out will not.

Multiple times on my mac, trying to install in parallel led to failures
from multiple tasks trying to simultaneously create `$PREFIX/lib`.
Copy link
Member

@gartung gartung left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as is passes spack unit-test -k bindist I am OK with the changes.

@spackbot-app spackbot-app bot added the tests General test capability(ies) label Oct 8, 2021
@sethrj sethrj changed the title Make macOS installed libraries more relocatable. Make macOS installed libraries more relocatable Oct 8, 2021
@sethrj
Copy link
Contributor Author

sethrj commented Oct 9, 2021

@gartung @alalazo Please take a look at this when you have a minute. With this change, making build caches on macOS should be much easier and it should be easier for external tools to relocate spack libraries: in both cases, the only change to be made to shared libraries will be to update their rpaths.

I've tested this out on my macOS and it correctly patches my entire toolchain so far (including perl, pcre, gcc, zstd, zlib, glib, etc.), but I'll update when I can confirm that our downstream tools (and CMake's install(RUNTIME_DEPENDENCY_SET tool) is able to relocate the files.

packages) that do not install relocatable libraries by default.
"""
if 'platform=darwin' not in self.spec:
return
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it would be a good idea to add a config option to control the automatic behavior? That way we could turn it off by default if we're worried about side effects or longer build+install times.

@@ -82,7 +84,7 @@ def _patchelf():
Return None on Darwin or if patchelf cannot be found.
"""
# Check if patchelf is already in the PATH
patchelf = spack.util.executable.which('patchelf')
patchelf = executable.which('patchelf')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alalazo Was this working before?

@sethrj
Copy link
Contributor Author

sethrj commented Oct 9, 2021

Found one issue due to this change: the relocatable code change the absolute path of libgfortran to an rpath, but this exposes a bug related to my other lovely walk through RPATH hell, #26582 !!

Without the library fixup, code compiled/linked with gfortran links to the hard-coded absolute path to libgfortran.dylib. Thanks to Spack's extra modifications to the GCC specs file, it also gets an additional -rpath $GCC/lib:$GCC/lib64. This rpath command is not valid on macOS! The rpaths on mac are not colon-separated: they must be provided as separate commands.

Linking against libgfortran with the fixup exposes this, since for some reason the RPATH entries for libgfortran are not propagated into the downstream fortran executable. Instead, the fortran code gets linked against @rpath/libgfortran.dylib (which is what we want) but it has an invalid colon-separate rpath.

So I will update #26590 to use the correct rpath command on macOS, which should be merged before this PR.

gartung
gartung previously approved these changes Oct 10, 2021
@sethrj
Copy link
Contributor Author

sethrj commented Oct 10, 2021

I'm going to examine this a bit more. It has consequences when using spack GCC Fortran as part of a mixed toolchain on macOS.

This restores the hardcoded library path for GCC.
@sethrj
Copy link
Contributor Author

sethrj commented Oct 11, 2021

OK, this should be much more reliable. I'm testing this (as well as #26590) on my mac now.

@sethrj sethrj requested a review from gartung October 11, 2021 16:34
@sethrj sethrj merged commit c48b733 into spack:develop Oct 18, 2021
@sethrj sethrj deleted the relocatable-libs branch October 18, 2021 17:37
sethrj added a commit to sethrj/spack that referenced this pull request Oct 27, 2021
After spack#26608 I got a report about missing rpaths when building a
downstream package independently using a spack-installed toolchain
(@tmdelellis). This occurred because the spack-installed libraries were
being linked into the downstream app, but the rpaths were not being
manually added. Prior to spack#26608 autotools-installed libs would retain
their hard-coded path and would thus propagate their link information
into the downstream library on mac.

We could solve this problem *if* the mac linker (ld) respected
`LD_RUN_PATH` like it does on GNU systems, i.e. adding `rpath` entries
to each item in the environment variable. However on mac we would have
to manually add rpaths either using spack's compiler wrapper scripts or
manually (e.g. using `CMAKE_BUILD_RPATH` and pointing to the libraries of
all the autotools-installed spack libraries).

The easier and safer thing to do for now is to simply stop changing the
dylib IDs.
alalazo pushed a commit that referenced this pull request Nov 2, 2021
…27139)

After #26608 I got a report about missing rpaths when building a
downstream package independently using a spack-installed toolchain
(@tmdelellis). This occurred because the spack-installed libraries were
being linked into the downstream app, but the rpaths were not being
manually added. Prior to #26608 autotools-installed libs would retain
their hard-coded path and would thus propagate their link information
into the downstream library on mac.

We could solve this problem *if* the mac linker (ld) respected
`LD_RUN_PATH` like it does on GNU systems, i.e. adding `rpath` entries
to each item in the environment variable. However on mac we would have
to manually add rpaths either using spack's compiler wrapper scripts or
manually (e.g. using `CMAKE_BUILD_RPATH` and pointing to the libraries of
all the autotools-installed spack libraries).

The easier and safer thing to do for now is to simply stop changing the
dylib IDs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Duplicate rpaths in some autotools packages
2 participants