Skip to content

Commit 536a900

Browse files
committed
Auto merge of #39578 - canndrew:nixos-bootstrap-fix, r=alexcrichton
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.
2 parents dc0bb3f + 5e324bd commit 536a900

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

src/bootstrap/bootstrap.py

+56
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ def download_stage0(self):
173173
if not os.path.exists(tarball):
174174
get("{}/{}".format(url, filename), tarball, verbose=self.verbose)
175175
unpack(tarball, self.bin_root(), match="rustc", verbose=self.verbose)
176+
self.fix_executable(self.bin_root() + "/bin/rustc")
177+
self.fix_executable(self.bin_root() + "/bin/rustdoc")
176178
with open(self.rustc_stamp(), 'w') as f:
177179
f.write(self.stage0_rustc_date())
178180

@@ -185,9 +187,63 @@ def download_stage0(self):
185187
if not os.path.exists(tarball):
186188
get("{}/{}".format(url, filename), tarball, verbose=self.verbose)
187189
unpack(tarball, self.bin_root(), match="cargo", verbose=self.verbose)
190+
self.fix_executable(self.bin_root() + "/bin/cargo")
188191
with open(self.cargo_stamp(), 'w') as f:
189192
f.write(self.stage0_cargo_rev())
190193

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

0 commit comments

Comments
 (0)