bootstrap.py: guard against GC in NixOS patching support.

This commit is contained in:
Eduard-Mihai Burtescu 2020-07-17 15:35:14 +03:00
parent c2dbebd3d4
commit d866160b85
1 changed files with 38 additions and 27 deletions

View File

@ -349,6 +349,7 @@ class RustBuild(object):
self.use_vendored_sources = ''
self.verbose = False
self.git_version = None
self.nix_deps_dir = None
def download_stage0(self):
"""Fetch the build system for Rust, written in Rust
@ -440,8 +441,7 @@ class RustBuild(object):
get("{}/{}".format(url, filename), tarball, verbose=self.verbose)
unpack(tarball, tarball_suffix, self.bin_root(), match=pattern, verbose=self.verbose)
@staticmethod
def fix_executable(fname):
def fix_executable(self, fname):
"""Modifies the interpreter section of 'fname' to fix the dynamic linker
This method is only required on NixOS and uses the PatchELF utility to
@ -472,38 +472,49 @@ class RustBuild(object):
nix_os_msg = "info: you seem to be running NixOS. Attempting to patch"
print(nix_os_msg, fname)
try:
interpreter = subprocess.check_output(
["patchelf", "--print-interpreter", fname])
interpreter = interpreter.strip().decode(default_encoding)
except subprocess.CalledProcessError as reason:
print("warning: failed to call patchelf:", reason)
return
# Only build `stage0/.nix-deps` once.
nix_deps_dir = self.nix_deps_dir
if not nix_deps_dir:
nix_deps_dir = "{}/.nix-deps".format(self.bin_root())
if not os.path.exists(nix_deps_dir):
os.makedirs(nix_deps_dir)
loader = interpreter.split("/")[-1]
nix_deps = [
# Needed for the path of `ld-linux.so` (via `nix-support/dynamic-linker`).
"stdenv.cc.bintools",
try:
ldd_output = subprocess.check_output(
['ldd', '/run/current-system/sw/bin/sh'])
ldd_output = ldd_output.strip().decode(default_encoding)
except subprocess.CalledProcessError as reason:
print("warning: unable to call ldd:", reason)
return
# Needed for patching ELF binaries (see doc comment above).
"patchelf",
]
for line in ldd_output.splitlines():
libname = line.split()[0]
if libname.endswith(loader):
loader_path = libname[:len(libname) - len(loader)]
break
else:
print("warning: unable to find the path to the dynamic linker")
return
# Run `nix-build` to "build" each dependency (which will likely reuse
# the existing `/nix/store` copy, or at most download a pre-built copy).
# Importantly, we don't rely on `nix-build` printing the `/nix/store`
# path on stdout, but use `-o` to symlink it into `stage0/.nix-deps/$dep`,
# ensuring garbage collection will never remove the `/nix/store` path
# (which would break our patched binaries that hardcode those paths).
for dep in nix_deps:
try:
subprocess.check_output([
"nix-build", "<nixpkgs>",
"-A", dep,
"-o", "{}/{}".format(nix_deps_dir, dep),
])
except subprocess.CalledProcessError as reason:
print("warning: failed to call nix-build:", reason)
return
correct_interpreter = loader_path + loader
self.nix_deps_dir = nix_deps_dir
patchelf = "{}/patchelf/bin/patchelf".format(nix_deps_dir)
bintools_dir = "{}/stdenv.cc.bintools".format(nix_deps_dir)
with open("{}/nix-support/dynamic-linker".format(bintools_dir)) as dynamic_linker:
interpreter = dynamic_linker.read().rstrip()
try:
subprocess.check_output(
["patchelf", "--set-interpreter", correct_interpreter, fname])
[patchelf, "--set-interpreter", interpreter, fname])
except subprocess.CalledProcessError as reason:
print("warning: failed to call patchelf:", reason)
return