Skip to content

Commit

Permalink
Implement sysroot handling
Browse files Browse the repository at this point in the history
  • Loading branch information
mati865 committed Feb 18, 2025
1 parent ef6ea12 commit 17dcdad
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 7 deletions.
28 changes: 24 additions & 4 deletions libwild/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::alignment::Alignment;
use crate::arch::Architecture;
use crate::error::Result;
use crate::input_data::FileId;
use crate::linker_script::maybe_forced_sysroot;
use crate::save_dir::SaveDir;
use anyhow::bail;
use anyhow::ensure;
Expand Down Expand Up @@ -56,6 +57,7 @@ pub(crate) struct Args {
pub(crate) file_write_mode: FileWriteMode,
pub(crate) no_undefined: bool,
pub(crate) allow_copy_relocations: bool,
pub(crate) sysroot: Option<Box<Path>>,

/// If set, GC stats will be written to the specified filename.
pub(crate) write_gc_stats: Option<PathBuf>,
Expand Down Expand Up @@ -240,6 +242,7 @@ impl Default for Args {
files_per_group: None,
no_undefined: false,
should_print_version: false,
sysroot: None,
}
}
}
Expand Down Expand Up @@ -302,13 +305,19 @@ pub(crate) fn parse<S: AsRef<str>, I: Iterator<Item = S>>(mut input: I) -> Resul
};

if let Some(rest) = arg.strip_prefix("-L") {
let handle_sysroot = |path| {
args.sysroot
.as_ref()
.and_then(|sysroot| maybe_forced_sysroot(path, sysroot))
.unwrap_or_else(|| Box::from(path))
};
if rest.is_empty() {
if let Some(next) = input.next() {
args.lib_search_path
.push(Box::from(Path::new(next.as_ref())));
.push(handle_sysroot(Path::new(next.as_ref())));
}
} else {
args.lib_search_path.push(Box::from(Path::new(rest)));
args.lib_search_path.push(handle_sysroot(Path::new(rest)));
}
} else if let Some(rest) = arg.strip_prefix("-l") {
args.inputs.push(Input {
Expand Down Expand Up @@ -507,8 +516,14 @@ pub(crate) fn parse<S: AsRef<str>, I: Iterator<Item = S>>(mut input: I) -> Resul
} else if strip_option(arg)
.is_some_and(|stripped_arg| SILENTLY_IGNORED_FLAGS.contains(&stripped_arg))
{
} else if long_arg_split_prefix("sysroot=").is_some() {
warn_unsupported("--sysroot")?;
} else if let Some(sysroot) = long_arg_split_prefix("sysroot=") {
let sysroot = Path::new(sysroot);
args.sysroot = Some(Box::from(sysroot));
for path in &mut args.lib_search_path {
if let Some(new_path) = maybe_forced_sysroot(path, sysroot) {
*path = new_path;
}
}
} else if arg.starts_with('-') {
unrecognised.push(format!("`{arg}`"));
} else {
Expand Down Expand Up @@ -889,6 +904,7 @@ mod tests {
"-X",
"-EL",
"-v",
"--sysroot=/usr/aarch64-linux-gnu",
];

#[track_caller]
Expand Down Expand Up @@ -923,6 +939,10 @@ mod tests {
assert_eq!(args.soname, Some("bar".to_owned()));
assert_eq!(args.num_threads, NonZeroUsize::new(1).unwrap());
assert!(args.should_print_version);
assert_eq!(
args.sysroot,
Some(Box::from(Path::new("/usr/aarch64-linux-gnu")))
);
}

#[test]
Expand Down
7 changes: 4 additions & 3 deletions libwild/src/input_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ impl<'config> InputData<'config> {
};

for input in &config.inputs {
input_data.register_input(input)?;
input_data.register_input(input, config.sysroot.as_deref())?;
}

// Our last "file", similar to the prelude is responsible for internal stuff, but this time
Expand All @@ -114,7 +114,7 @@ impl<'config> InputData<'config> {
Ok(input_data)
}

fn register_input(&mut self, input: &Input) -> Result {
fn register_input(&mut self, input: &Input, sysroot: Option<&Path>) -> Result {
let paths = input.path(self.config)?;
let absolute_path = &paths.absolute;
if !self.filenames.insert(absolute_path.clone()) {
Expand Down Expand Up @@ -154,8 +154,9 @@ impl<'config> InputData<'config> {
&bytes,
absolute_path,
input.modifiers,
sysroot,
)? {
self.register_input(&input)?;
self.register_input(&input, sysroot)?;
}
return Ok(());
}
Expand Down
70 changes: 70 additions & 0 deletions libwild/src/linker_script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub(crate) fn linker_script_to_inputs(
bytes: &[u8],
path: &Path,
modifiers: Modifiers,
sysroot: Option<&Path>,
) -> Result<Vec<Input>> {
let text = std::str::from_utf8(bytes)?;
let directory = path
Expand All @@ -33,11 +34,36 @@ pub(crate) fn linker_script_to_inputs(
.into_iter()
.map(|mut input| {
input.search_first = Some(directory.to_owned());
if let (Some(sysroot), InputSpec::File(file)) = (sysroot, &mut input.spec) {
if let Some(new_file) = maybe_apply_sysroot(path, file, sysroot) {
*file = new_file;
}
}

input
})
.collect())
}

fn maybe_apply_sysroot(
linker_script_path: &Path,
input_path: &Path,
sysroot: &Path,
) -> Option<Box<Path>> {
if matches!(linker_script_path.canonicalize(), Ok(p) if p.starts_with(sysroot)) {
Some(Box::from(sysroot.join(input_path.strip_prefix("/").ok()?)))
} else {
maybe_forced_sysroot(input_path, sysroot)
}
}

pub(crate) fn maybe_forced_sysroot(path: &Path, sysroot: &Path) -> Option<Box<Path>> {
path.strip_prefix("=")
.or_else(|_| path.strip_prefix("$SYSROOT"))
.ok()
.map(|stripped| Box::from(sysroot.join(stripped)))
}

/// A version script. See https://sourceware.org/binutils/docs/ld/VERSION.html
#[derive(Default)]
pub(crate) struct VersionScript<'data> {
Expand Down Expand Up @@ -461,4 +487,48 @@ mod tests {
);
assert!(version.locals.matches_all);
}

#[test]
fn test_sysroot_application() {
// Use real paths because of canonicalization
let fake_sysroot = Path::new(env!("CARGO_MANIFEST_DIR"));
let fake_linker_script_inside_sysroot = fake_sysroot.join("Cargo.toml");
let fake_linker_script_outside_sysroot = Path::new("/Cargo.toml");
// Linker script is located in the sysroot
assert_equal(
maybe_apply_sysroot(
&fake_linker_script_inside_sysroot,
Path::new("/lib/libc.so.6"),
fake_sysroot,
),
Some(Box::from(fake_sysroot.join("lib/libc.so.6"))),
);
// Linker script is not located in the sysroot
assert_equal(
maybe_apply_sysroot(
fake_linker_script_outside_sysroot,
Path::new("/lib/libc.so.6"),
fake_sysroot,
),
None,
);
// Sysroot enforced by `=`
assert_equal(
maybe_apply_sysroot(
fake_linker_script_outside_sysroot,
Path::new("=/lib/libc.so.6"),
fake_sysroot,
),
Some(Box::from(fake_sysroot.join("lib/libc.so.6"))),
);
// Sysroot enforced by `$SYSROOT`
assert_equal(
maybe_apply_sysroot(
fake_linker_script_outside_sysroot,
Path::new("$SYSROOT/lib/libc.so.6"),
fake_sysroot,
),
Some(Box::from(fake_sysroot.join("lib/libc.so.6"))),
);
}
}

0 comments on commit 17dcdad

Please sign in to comment.