Skip to content

Commit ea1252e

Browse files
committed
Auto merge of #84071 - nagisa:nixos-patching-fix, r=Mark-Simulacrum
Fix NixOS patching Moving the `.nix-deps` has resulted in rpath links being broken and therefore bootstrap on NixOS broken entirely. This PR still produces a `.nix-deps` but only for the purposes of producing a gc root. We rpath a symlink-resolved result instead. For purposes of simplicity we also use joinSymlink to produce a single merged output directory so that we don't need to update multiple locations every time we add a library or something. Fixes a regression from #82739.
2 parents ef38b45 + 3dabab1 commit ea1252e

File tree

1 file changed

+41
-48
lines changed

1 file changed

+41
-48
lines changed

src/bootstrap/bootstrap.py

+41-48
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ def download_toolchain(self, stage0=True, rustc_channel=None):
429429
lib_dir = "{}/lib".format(bin_root)
430430
for lib in os.listdir(lib_dir):
431431
if lib.endswith(".so"):
432-
self.fix_bin_or_dylib(os.path.join(lib_dir, lib), rpath_libz=True)
432+
self.fix_bin_or_dylib(os.path.join(lib_dir, lib))
433433
with output(self.rustc_stamp(stage0)) as rust_stamp:
434434
rust_stamp.write(key)
435435

@@ -477,10 +477,10 @@ def download_toolchain(self, stage0=True, rustc_channel=None):
477477
if self.program_out_of_date(self.llvm_stamp(), llvm_sha + str(llvm_assertions)):
478478
self._download_ci_llvm(llvm_sha, llvm_assertions)
479479
for binary in ["llvm-config", "FileCheck"]:
480-
self.fix_bin_or_dylib(os.path.join(llvm_root, "bin", binary), rpath_libz=True)
480+
self.fix_bin_or_dylib(os.path.join(llvm_root, "bin", binary))
481481
for lib in os.listdir(llvm_lib):
482482
if lib.endswith(".so"):
483-
self.fix_bin_or_dylib(os.path.join(llvm_lib, lib), rpath_libz=True)
483+
self.fix_bin_or_dylib(os.path.join(llvm_lib, lib))
484484
with output(self.llvm_stamp()) as llvm_stamp:
485485
llvm_stamp.write(llvm_sha + str(llvm_assertions))
486486

@@ -548,7 +548,7 @@ def _download_ci_llvm(self, llvm_sha, llvm_assertions):
548548
match="rust-dev",
549549
verbose=self.verbose)
550550

551-
def fix_bin_or_dylib(self, fname, rpath_libz=False):
551+
def fix_bin_or_dylib(self, fname):
552552
"""Modifies the interpreter section of 'fname' to fix the dynamic linker,
553553
or the RPATH section, to fix the dynamic library search path
554554
@@ -583,56 +583,49 @@ def fix_bin_or_dylib(self, fname, rpath_libz=False):
583583
# Only build `.nix-deps` once.
584584
nix_deps_dir = self.nix_deps_dir
585585
if not nix_deps_dir:
586-
nix_deps_dir = ".nix-deps"
587-
if not os.path.exists(nix_deps_dir):
588-
os.makedirs(nix_deps_dir)
589-
590-
nix_deps = [
591-
# Needed for the path of `ld-linux.so` (via `nix-support/dynamic-linker`).
592-
"stdenv.cc.bintools",
593-
594-
# Needed as a system dependency of `libLLVM-*.so`.
595-
"zlib",
596-
597-
# Needed for patching ELF binaries (see doc comment above).
598-
"patchelf",
599-
]
600-
601586
# Run `nix-build` to "build" each dependency (which will likely reuse
602587
# the existing `/nix/store` copy, or at most download a pre-built copy).
603-
# Importantly, we don't rely on `nix-build` printing the `/nix/store`
604-
# path on stdout, but use `-o` to symlink it into `stage0/.nix-deps/$dep`,
605-
# ensuring garbage collection will never remove the `/nix/store` path
606-
# (which would break our patched binaries that hardcode those paths).
607-
for dep in nix_deps:
608-
try:
609-
subprocess.check_output([
610-
"nix-build", "<nixpkgs>",
611-
"-A", dep,
612-
"-o", "{}/{}".format(nix_deps_dir, dep),
613-
])
614-
except subprocess.CalledProcessError as reason:
615-
print("warning: failed to call nix-build:", reason)
616-
return
617-
588+
#
589+
# Importantly, we create a gc-root called `.nix-deps` in the `build/`
590+
# directory, but still reference the actual `/nix/store` path in the rpath
591+
# as it makes it significantly more robust against changes to the location of
592+
# the `.nix-deps` location.
593+
#
594+
# bintools: Needed for the path of `ld-linux.so` (via `nix-support/dynamic-linker`).
595+
# zlib: Needed as a system dependency of `libLLVM-*.so`.
596+
# patchelf: Needed for patching ELF binaries (see doc comment above).
597+
nix_deps_dir = "{}/{}".format(self.build_dir, ".nix-deps")
598+
nix_expr = '''
599+
with (import <nixpkgs> {});
600+
symlinkJoin {
601+
name = "rust-stage0-dependencies";
602+
paths = [
603+
zlib
604+
patchelf
605+
stdenv.cc.bintools
606+
];
607+
}
608+
'''
609+
try:
610+
subprocess.check_output([
611+
"nix-build", "-E", nix_expr, "-o", nix_deps_dir,
612+
])
613+
except subprocess.CalledProcessError as reason:
614+
print("warning: failed to call nix-build:", reason)
615+
return
618616
self.nix_deps_dir = nix_deps_dir
619617

620-
patchelf = "{}/patchelf/bin/patchelf".format(nix_deps_dir)
621-
patchelf_args = []
622-
623-
if rpath_libz:
624-
# Patch RPATH to add `zlib` dependency that stems from LLVM
625-
dylib_deps = ["zlib"]
626-
rpath_entries = [
627-
# Relative default, all binary and dynamic libraries we ship
628-
# appear to have this (even when `../lib` is redundant).
629-
"$ORIGIN/../lib",
630-
] + ["{}/{}/lib".format(nix_deps_dir, dep) for dep in dylib_deps]
631-
patchelf_args += ["--set-rpath", ":".join(rpath_entries)]
618+
patchelf = "{}/bin/patchelf".format(nix_deps_dir)
619+
rpath_entries = [
620+
# Relative default, all binary and dynamic libraries we ship
621+
# appear to have this (even when `../lib` is redundant).
622+
"$ORIGIN/../lib",
623+
os.path.join(os.path.realpath(nix_deps_dir), "lib")
624+
]
625+
patchelf_args = ["--set-rpath", ":".join(rpath_entries)]
632626
if not fname.endswith(".so"):
633627
# Finally, set the corret .interp for binaries
634-
bintools_dir = "{}/stdenv.cc.bintools".format(nix_deps_dir)
635-
with open("{}/nix-support/dynamic-linker".format(bintools_dir)) as dynamic_linker:
628+
with open("{}/nix-support/dynamic-linker".format(nix_deps_dir)) as dynamic_linker:
636629
patchelf_args += ["--set-interpreter", dynamic_linker.read().rstrip()]
637630

638631
try:

0 commit comments

Comments
 (0)