#[path = "support/objects.rs"]
mod objects;
use std::sync::Arc;
use qld::args::{InputAttrs, InputKind, LinkOptions, OutputBuffer, OutputKind};
use qld::diag::Collect;
use qld::input::MemoryFiles;
fn main() -> qld::Result<()> {
let main_o = objects::main_object();
let answer_o = objects::answer_object(42);
let mut options = LinkOptions::new();
options.kind = OutputKind::StaticExecutable;
options.push_input(
InputKind::bytes("main.o", main_o.clone()),
InputAttrs::default(),
);
options.push_input(
InputKind::bytes("answer.o", answer_o.clone()),
InputAttrs::default(),
);
let buffer = OutputBuffer::new();
options.output_buffer = Some(buffer.clone());
let diagnostics = Collect::new();
qld::link(&options, &diagnostics)?;
let first = buffer.take().expect("a successful link fills the buffer");
report("buffers", &first);
let library = objects::archive(&[("answer.o", &answer_o, &["answer"])]);
let files = MemoryFiles::new()
.with("main.o", main_o)
.with("/virtual/lib/libanswer.a", library);
let argv = ["ld", "-static", "-L/virtual/lib", "main.o", "-lanswer"];
let qld::ParseOutcome::Link(options) = qld::parse_gnu(&argv)? else {
unreachable!("a link command line");
};
let mut options = *options;
options.input_provider = Some(Arc::new(files));
let buffer = OutputBuffer::new();
options.output_buffer = Some(buffer.clone());
qld::link(&options, &diagnostics)?;
let second = buffer.take().expect("a successful link fills the buffer");
report("memory files", &second);
assert_eq!(first, second, "same program either way");
for diagnostic in diagnostics.take_sorted() {
eprintln!("{}: {}", diagnostic.severity, diagnostic.message);
}
if let Some(path) = std::env::args_os().nth(1) {
std::fs::write(&path, &first).map_err(|error| qld::Error::io(&path, error))?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o755))
.map_err(|error| qld::Error::io(&path, error))?;
}
println!("wrote {} (it exits with status 42)", path.to_string_lossy());
}
Ok(())
}
fn report(how: &str, image: &[u8]) {
let entry = objects::entry_point(image).unwrap_or(0);
println!(
"{how}: {} byte x86-64 executable, entry point {entry:#x}",
image.len()
);
}