Skip to content

Commit 64c1ac8

Browse files
committed
Fix for bootstrapping on NixOS
NixOS puts Linux's dynamic loader in wierd place. Detect when we're on NixOS and patch the downloaded bootstrap executables appropriately.
1 parent a3da24b commit 64c1ac8

File tree

1 file changed

+56
-1
lines changed

1 file changed

+56
-1
lines changed

src/bootstrap/bootstrap.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ def verify(path, sha_path, verbose):
8989
" expected: {}".format(found, expected))
9090
return verified
9191

92-
9392
def unpack(tarball, dst, verbose=False, match=None):
9493
print("extracting " + tarball)
9594
fname = os.path.basename(tarball).replace(".tar.gz", "")
@@ -173,6 +172,8 @@ def download_stage0(self):
173172
if not os.path.exists(tarball):
174173
get("{}/{}".format(url, filename), tarball, verbose=self.verbose)
175174
unpack(tarball, self.bin_root(), match="rustc", verbose=self.verbose)
175+
self.fix_executable(self.bin_root() + "/bin/rustc")
176+
self.fix_executable(self.bin_root() + "/bin/rustdoc")
176177
with open(self.rustc_stamp(), 'w') as f:
177178
f.write(self.stage0_rustc_date())
178179

@@ -185,9 +186,63 @@ def download_stage0(self):
185186
if not os.path.exists(tarball):
186187
get("{}/{}".format(url, filename), tarball, verbose=self.verbose)
187188
unpack(tarball, self.bin_root(), match="cargo", verbose=self.verbose)
189+
self.fix_executable(self.bin_root() + "/bin/cargo")
188190
with open(self.cargo_stamp(), 'w') as f:
189191
f.write(self.stage0_cargo_rev())
190192

193+
def fix_executable(self, fname):
194+
# If we're on NixOS we need to change the path to the dynamic loader
195+
196+
default_encoding = sys.getdefaultencoding()
197+
try:
198+
ostype = subprocess.check_output(['uname', '-s']).strip().decode(default_encoding)
199+
except (subprocess.CalledProcessError, WindowsError):
200+
return
201+
202+
if ostype != "Linux":
203+
return
204+
205+
if not os.path.exists("/nix/store"):
206+
return
207+
if os.path.exists("/lib"):
208+
return
209+
210+
# At this point we're pretty sure the user is running NixOS
211+
print("Info: you seem to be running NixOS. Attempting to patch " + fname)
212+
213+
try:
214+
interpreter = subprocess.check_output(["patchelf", "--print-interpreter", fname])
215+
interpreter = interpreter.strip().decode(default_encoding)
216+
except subprocess.CalledProcessError as e:
217+
print("Warning: failed to call patchelf: %s" % e)
218+
return
219+
220+
loader = interpreter.split("/")[-1]
221+
222+
try:
223+
ldd_output = subprocess.check_output(['ldd', '/run/current-system/sw/bin/sh'])
224+
ldd_output = ldd_output.strip().decode(default_encoding)
225+
except subprocess.CalledProcessError as e:
226+
print("Warning: unable to call ldd: %s" % e)
227+
return
228+
229+
for line in ldd_output.splitlines():
230+
libname = line.split()[0]
231+
if libname.endswith(loader):
232+
loader_path = libname[:len(libname) - len(loader)]
233+
break
234+
else:
235+
print("Warning: unable to find the path to the dynamic linker")
236+
return
237+
238+
correct_interpreter = loader_path + loader
239+
240+
try:
241+
subprocess.check_output(["patchelf", "--set-interpreter", correct_interpreter, fname])
242+
except subprocess.CalledProcessError as e:
243+
print("Warning: failed to call patchelf: %s" % e)
244+
return
245+
191246
def stage0_cargo_rev(self):
192247
return self._cargo_rev
193248

0 commit comments

Comments
 (0)