gcc: simplify specs file, make binutils locatable (#43861)

This commit is contained in:
Harmen Stoppels 2024-04-26 09:30:51 +02:00 committed by GitHub
parent d946c37cbb
commit 2e8600bb71
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -16,7 +16,6 @@
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
from spack.package import * from spack.package import *
@ -957,76 +956,42 @@ def install_targets(self):
@property @property
def spec_dir(self): def spec_dir(self):
# e.g. lib/gcc/x86_64-unknown-linux-gnu/4.9.2 # e.g. lib/gcc/x86_64-unknown-linux-gnu/4.9.2
spec_dir = glob.glob("{0}/gcc/*/*".format(self.prefix.lib)) spec_dir = glob.glob(f"{self.prefix.lib}/gcc/*/*")
return spec_dir[0] if spec_dir else None return spec_dir[0] if spec_dir else None
@run_after("install") @run_after("install")
def write_rpath_specs(self): def write_specs_file(self):
"""Generate a spec file so the linker adds a rpath to the libs """(1) inject an rpath to its runtime library dir, (2) add a default programs search path
the compiler used to build the executable. to <binutils>/bin."""
.. 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( tty.warn(f"Could not install specs for {self.spec.format('{name}{@version}')}.")
"Could not install specs for {0}.".format(self.spec.format("{name}{@version}"))
)
return return
gcc = self.spec["gcc"].command
lines = gcc("-dumpspecs", output=str).splitlines(True)
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 # Find which directories have shared libraries
rpath_libdirs = [] for dir in ["lib64", "lib"]:
for dir in ["lib", "lib64"]:
libdir = join_path(self.prefix, dir) libdir = join_path(self.prefix, dir)
if glob.glob(join_path(libdir, "*." + dso_suffix)): if glob.glob(join_path(libdir, "libgcc_s.*")):
rpath_libdirs.append(libdir) rpath_dir = libdir
break
if not rpath_libdirs: else:
# No shared libraries
tty.warn("No dynamic libraries found in lib/lib64") tty.warn("No dynamic libraries found in lib/lib64")
return rpath_dir = None
# Overwrite the specs file specs_file = join_path(self.spec_dir, "specs")
with open(specs_file, "w") as out: with open(specs_file, "w") as f:
for line in lines: # rpath
out.write(line) if rpath_dir:
if line.startswith("*link_libgcc:"): print("*link_libgcc:", file=f)
# Insert at start of line following link_libgcc, which gets print(f"+ -rpath={rpath_dir}", file=f)
# inserted into every call to the linker print(file=f)
out.write("%(link_libgcc_rpath) ")
# Add easily-overridable rpath string at the end # programs search path
out.write("*link_libgcc_rpath:\n") if self.spec.satisfies("+binutils"):
out.write(" ".join("-rpath " + lib for lib in rpath_libdirs)) print("*self_spec:", file=f)
out.write("\n") print(f"+ -B{self.spec['binutils'].prefix.bin}", file=f)
print(file=f)
set_install_permissions(specs_file) set_install_permissions(specs_file)
tty.info("Wrote new spec file to {0}".format(specs_file)) tty.info(f"Wrote new spec file to {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