1#[path = "support/objects.rs"]
17mod objects;
18
19use std::sync::Arc;
20
21use qld::args::{InputAttrs, InputKind, LinkOptions, OutputBuffer, OutputKind};
22use qld::diag::Collect;
23use qld::input::MemoryFiles;
24
25fn main() -> qld::Result<()> {
26 let main_o = objects::main_object();
28 let answer_o = objects::answer_object(42);
29
30 let mut options = LinkOptions::new();
32 options.kind = OutputKind::StaticExecutable;
33 options.push_input(
34 InputKind::bytes("main.o", main_o.clone()),
35 InputAttrs::default(),
36 );
37 options.push_input(
38 InputKind::bytes("answer.o", answer_o.clone()),
39 InputAttrs::default(),
40 );
41 let buffer = OutputBuffer::new();
42 options.output_buffer = Some(buffer.clone());
43 let diagnostics = Collect::new();
44 qld::link(&options, &diagnostics)?;
45 let first = buffer.take().expect("a successful link fills the buffer");
46 report("buffers", &first);
47
48 let library = objects::archive(&[("answer.o", &answer_o, &["answer"])]);
51 let files = MemoryFiles::new()
52 .with("main.o", main_o)
53 .with("/virtual/lib/libanswer.a", library);
54 let argv = ["ld", "-static", "-L/virtual/lib", "main.o", "-lanswer"];
55 let qld::ParseOutcome::Link(options) = qld::parse_gnu(&argv)? else {
56 unreachable!("a link command line");
57 };
58 let mut options = *options;
59 options.input_provider = Some(Arc::new(files));
60 let buffer = OutputBuffer::new();
61 options.output_buffer = Some(buffer.clone());
62 qld::link(&options, &diagnostics)?;
63 let second = buffer.take().expect("a successful link fills the buffer");
64 report("memory files", &second);
65 assert_eq!(first, second, "same program either way");
66
67 for diagnostic in diagnostics.take_sorted() {
68 eprintln!("{}: {}", diagnostic.severity, diagnostic.message);
69 }
70 if let Some(path) = std::env::args_os().nth(1) {
71 std::fs::write(&path, &first).map_err(|error| qld::Error::io(&path, error))?;
72 #[cfg(unix)]
73 {
74 use std::os::unix::fs::PermissionsExt;
75 std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o755))
76 .map_err(|error| qld::Error::io(&path, error))?;
77 }
78 println!("wrote {} (it exits with status 42)", path.to_string_lossy());
79 }
80 Ok(())
81}
82
83fn report(how: &str, image: &[u8]) {
84 let entry = objects::entry_point(image).unwrap_or(0);
85 println!(
86 "{how}: {} byte x86-64 executable, entry point {entry:#x}",
87 image.len()
88 );
89}