gcc: support alternate mechanism for providing GCC rpaths (#26590)
* gcc: support runtime ability to not install spack rpaths Fixes #26582 . * gcc: Fix malformed specs file and add docs The updated docs point out that the spack-modified GCC does *not* follow the usual behavior of LD_RUN_PATH! * gcc: fix bad rpath on macOS This bug has been around since the beginning of the GCC package file: the rpath command it generates for macOS writes a single (invalid) rpath entry. * gcc: only write rpaths for directories with shared libraries The original lib64+lib was just a hack for "in case either has one" but it's easy to tell whether either has libraries that can be directly referenced.
This commit is contained in:
parent
5a38165674
commit
c255e91bba
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
import spack.platforms
|
import spack.platforms
|
||||||
import spack.util.executable
|
import spack.util.executable
|
||||||
|
from spack.build_environment import dso_suffix
|
||||||
from spack.operating_systems.mac_os import macos_sdk_path, macos_version
|
from spack.operating_systems.mac_os import macos_sdk_path, macos_version
|
||||||
|
|
||||||
|
|
||||||
@ -647,22 +648,74 @@ def spec_dir(self):
|
|||||||
@run_after('install')
|
@run_after('install')
|
||||||
def write_rpath_specs(self):
|
def write_rpath_specs(self):
|
||||||
"""Generate a spec file so the linker adds a rpath to the libs
|
"""Generate a spec file so the linker adds a rpath to the libs
|
||||||
the compiler used to build the executable."""
|
the compiler used to build the executable.
|
||||||
|
|
||||||
|
.. caution::
|
||||||
|
|
||||||
|
The custom spec file by default with *always* pass ``-Wl,-rpath
|
||||||
|
...`` to the linker, which will cause the linker to *ignore* the
|
||||||
|
value of ``LD_RUN_PATH``, which otherwise would be saved to the
|
||||||
|
binary as the default rpath. See the mitigation below for how to
|
||||||
|
temporarily disable this behavior.
|
||||||
|
|
||||||
|
Structure the specs file so that users can define a custom spec file
|
||||||
|
to suppress the spack-linked rpaths to facilitate rpath adjustment
|
||||||
|
for relocatable binaries. The custom spec file
|
||||||
|
:file:`{norpath}.spec` will have a single
|
||||||
|
line followed by two blanks lines::
|
||||||
|
|
||||||
|
*link_libgcc_rpath:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
It can be passed to the GCC linker using the argument
|
||||||
|
``--specs=norpath.spec`` to disable the automatic rpath and restore
|
||||||
|
the behavior of ``LD_RUN_PATH``."""
|
||||||
if not self.spec_dir:
|
if not self.spec_dir:
|
||||||
tty.warn('Could not install specs for {0}.'.format(
|
tty.warn('Could not install specs for {0}.'.format(
|
||||||
self.spec.format('{name}{@version}')))
|
self.spec.format('{name}{@version}')))
|
||||||
return
|
return
|
||||||
|
|
||||||
gcc = self.spec['gcc'].command
|
gcc = self.spec['gcc'].command
|
||||||
lines = gcc('-dumpspecs', output=str).strip().split('\n')
|
lines = gcc('-dumpspecs', output=str).splitlines(True)
|
||||||
specs_file = join_path(self.spec_dir, 'specs')
|
specs_file = join_path(self.spec_dir, 'specs')
|
||||||
|
|
||||||
|
# Save a backup
|
||||||
|
with open(specs_file + '.orig', 'w') as out:
|
||||||
|
out.writelines(lines)
|
||||||
|
|
||||||
|
# Find which directories have shared libraries
|
||||||
|
rpath_libdirs = []
|
||||||
|
for dir in ['lib', 'lib64']:
|
||||||
|
libdir = join_path(self.prefix, dir)
|
||||||
|
if glob.glob(join_path(libdir, "*." + dso_suffix)):
|
||||||
|
rpath_libdirs.append(libdir)
|
||||||
|
|
||||||
|
if not rpath_libdirs:
|
||||||
|
# No shared libraries
|
||||||
|
tty.warn('No dynamic libraries found in lib/lib64')
|
||||||
|
return
|
||||||
|
|
||||||
|
# Overwrite the specs file
|
||||||
with open(specs_file, 'w') as out:
|
with open(specs_file, 'w') as out:
|
||||||
for line in lines:
|
for line in lines:
|
||||||
out.write(line + '\n')
|
out.write(line)
|
||||||
if line.startswith('*link:'):
|
if line.startswith('*link_libgcc:'):
|
||||||
out.write('-rpath {0}:{1} '.format(
|
# Insert at start of line following link_libgcc, which gets
|
||||||
self.prefix.lib, self.prefix.lib64))
|
# inserted into every call to the linker
|
||||||
|
out.write('%(link_libgcc_rpath) ')
|
||||||
|
|
||||||
|
# Add easily-overridable rpath string at the end
|
||||||
|
out.write('*link_libgcc_rpath:\n')
|
||||||
|
if 'platform=darwin' in self.spec:
|
||||||
|
# macOS linker requires separate rpath commands
|
||||||
|
out.write(' '.join('-rpath ' + lib for lib in rpath_libdirs))
|
||||||
|
else:
|
||||||
|
# linux linker uses colon-separated rpath
|
||||||
|
out.write('-rpath ' + ':'.join(rpath_libdirs))
|
||||||
|
out.write('\n')
|
||||||
set_install_permissions(specs_file)
|
set_install_permissions(specs_file)
|
||||||
|
tty.info('Wrote new spec file to {0}'.format(specs_file))
|
||||||
|
|
||||||
def setup_run_environment(self, env):
|
def setup_run_environment(self, env):
|
||||||
# Search prefix directory for possibly modified compiler names
|
# Search prefix directory for possibly modified compiler names
|
||||||
|
Loading…
Reference in New Issue
Block a user