Something went wrong. Try again.
What happens if I push all of nixpkgs
Something went wrong. Try again.
6.4 kB · 189 lines
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190diff --git a/src/dist/component/package.rs b/src/dist/component/package.rsindex dfccc661..85233f3b 100644--- a/src/dist/component/package.rs+++ b/src/dist/component/package.rs@@ -113,6 +113,7 @@ impl Package for DirectoryPackage { } else { builder.move_file(path.clone(), &src_path)? }+ nix_patchelf_if_needed(&target.prefix().path().join(path.clone())) } "dir" => { if self.copy {@@ -135,6 +136,176 @@ impl Package for DirectoryPackage { } } +fn nix_wrap_lld(dest_lld_path: &Path) -> Result<()> {+ use std::fs;+ use std::io::Write;+ use std::os::unix::fs::PermissionsExt;++ let path = dest_lld_path.parent().unwrap();+ let mut unwrapped_name = path.file_name().unwrap().to_string_lossy().to_string();+ unwrapped_name.push_str("-unwrapped");+ let unwrapped_dir = path.with_file_name(unwrapped_name);+ fs::create_dir_all(&unwrapped_dir).context("failed to create unwrapped directory")?;+ let mut unwrapped_lld = unwrapped_dir;+ unwrapped_lld.push(dest_lld_path.file_name().unwrap());+ fs::rename(dest_lld_path, &unwrapped_lld).context("failed to move file")?;+ let mut ld_wrapper_path = std::env::current_exe()?+ .parent()+ .ok_or(anyhow!("failed to get parent directory"))?+ .with_file_name("nix-support");+ let mut file = std::fs::File::create(dest_lld_path)?;+ ld_wrapper_path.push("ld-wrapper.sh");++ let wrapped_script = format!(+ "#!/usr/bin/env bash+set -eu -o pipefail +o posix+shopt -s nullglob+export PROG=\"{}\"+\"{}\" $@",+ unwrapped_lld.to_string_lossy().to_string(),+ ld_wrapper_path.to_string_lossy().to_string(),+ );+ file.write_all(wrapped_script.as_bytes())?;+ let mut permissions = file.metadata()?.permissions();+ permissions.set_mode(0o755);+ file.set_permissions(permissions)?;+ Ok(())+}++fn nix_patchelf_if_needed(dest_path: &Path) {+ use std::fs::File;+ use std::os::unix::fs::FileExt;+ use tracing::{debug, warn};++ struct ELFReader<'a> {+ file: &'a mut File,+ is_32bit: bool,+ is_little_end: bool,+ }++ impl<'a> ELFReader<'a> {+ const MAGIC_NUMBER: &'static [u8] = &[0x7F, 0x45, 0x4c, 0x46];+ const ET_EXEC: u16 = 0x2;+ const ET_DYN: u16 = 0x3;+ const PT_INTERP: u32 = 0x3;++ fn new(file: &'a mut File) -> Option<Self> {+ let mut magic_number = [0; 4];+ file.read_exact(&mut magic_number).ok()?;+ if Self::MAGIC_NUMBER != magic_number {+ return None;+ }+ let mut ei_class = [0; 1];+ file.read_exact_at(&mut ei_class, 0x4).ok()?;+ let is_32bit = ei_class[0] == 1;+ let mut ei_data = [0; 1];+ file.read_exact_at(&mut ei_data, 0x5).ok()?;+ let is_little_end = ei_data[0] == 1;+ Some(Self {+ file,+ is_32bit,+ is_little_end,+ })+ }++ fn is_exec_or_dyn(&self) -> bool {+ let e_type = self.read_u16_at(0x10);+ e_type == Self::ET_EXEC || e_type == Self::ET_DYN+ }++ fn e_phoff(&self) -> u64 {+ if self.is_32bit {+ self.read_u32_at(0x1C) as u64+ } else {+ self.read_u64_at(0x20)+ }+ }++ fn e_phentsize(&self) -> u64 {+ let offset = if self.is_32bit { 0x2A } else { 0x36 };+ self.read_u16_at(offset) as u64+ }++ fn e_phnum(&self) -> u64 {+ let offset = if self.is_32bit { 0x2C } else { 0x38 };+ self.read_u16_at(offset) as u64+ }++ fn has_interp(&self) -> bool {+ let e_phoff = self.e_phoff();+ let e_phentsize = self.e_phentsize();+ let e_phnum = self.e_phnum();+ for i in 0..e_phnum {+ let p_type = self.read_u32_at(e_phoff + i * e_phentsize);+ if p_type == Self::PT_INTERP {+ return true;+ }+ }+ false+ }++ fn read_u16_at(&self, offset: u64) -> u16 {+ let mut data = [0; 2];+ self.file.read_exact_at(&mut data, offset).unwrap();+ if self.is_little_end {+ u16::from_le_bytes(data)+ } else {+ u16::from_be_bytes(data)+ }+ }++ fn read_u32_at(&self, offset: u64) -> u32 {+ let mut data = [0; 4];+ self.file.read_exact_at(&mut data, offset).unwrap();+ if self.is_little_end {+ u32::from_le_bytes(data)+ } else {+ u32::from_be_bytes(data)+ }+ }++ fn read_u64_at(&self, offset: u64) -> u64 {+ let mut data = [0; 8];+ self.file.read_exact_at(&mut data, offset).unwrap();+ if self.is_little_end {+ u64::from_le_bytes(data)+ } else {+ u64::from_be_bytes(data)+ }+ }+ }++ let Some(mut dest_file) = File::open(dest_path).ok() else {+ return;+ };+ let Some(elf) = ELFReader::new(&mut dest_file) else {+ return;+ };+ if !elf.is_exec_or_dyn() {+ return;+ }+ let mut patch_command = std::process::Command::new("@patchelf@/bin/patchelf");+ if elf.has_interp() {+ patch_command+ .arg("--set-interpreter")+ .arg("@dynamicLinker@");+ }+ if Some(std::ffi::OsStr::new("rust-lld")) == dest_path.file_name() || !elf.has_interp() {+ patch_command.arg("--add-rpath").arg("@libPath@");+ }++ debug!("patching {dest_path:?} using patchelf");+ if let Err(err) = patch_command.arg(dest_path).output() {+ warn!("failed to execute patchelf: {err:?}");+ }++ if Some(std::ffi::OsStr::new("ld.lld")) == dest_path.file_name() {+ if let Err(err) = nix_wrap_lld(dest_path) {+ warn!("failed to wrap `ld.lld`: {err:?}");+ }+ }+}+ #[derive(Debug)] pub(crate) struct TarPackage<'a>(DirectoryPackage, temp::Dir<'a>);