1#[path = "support/objects.rs"]
16mod objects;
17
18use std::sync::mpsc;
19use std::time::{Duration, Instant};
20
21use qld::args::{CancelToken, InputAttrs, InputKind, LinkOptions, OutputBuffer, OutputKind};
22use qld::diag::Stderr;
23
24fn link_with_deadline(mut options: LinkOptions, limit: Duration) -> qld::Result<()> {
27 let token = CancelToken::new();
28 options.cancel = Some(token.clone());
29 let (done, finished) = mpsc::channel::<()>();
30 let watchdog = std::thread::spawn(move || {
31 if finished.recv_timeout(limit) == Err(mpsc::RecvTimeoutError::Timeout) {
33 token.cancel();
34 }
35 });
36 let result = qld::link(&options, &Stderr::new(qld::PROGRAM_NAME));
37 drop(done);
38 let _ = watchdog.join();
39 result
40}
41
42fn main() -> qld::Result<()> {
43 let mut args = std::env::args().skip(1);
44 if let Some(limit) = args.next() {
45 let limit = Duration::from_millis(limit.parse().unwrap_or(1000));
46 let argv: Vec<String> = std::iter::once("ld".to_string()).chain(args).collect();
47 let qld::ParseOutcome::Link(options) = qld::parse_gnu(&argv)? else {
48 return Ok(());
49 };
50 let start = Instant::now();
51 let result = link_with_deadline(*options, limit);
52 match &result {
53 Ok(()) => eprintln!("linked in {:?}", start.elapsed()),
54 Err(error) if CancelToken::is_cancellation(error) => {
55 eprintln!("{error} after {:?}", start.elapsed());
56 }
57 Err(_) => {}
58 }
59 return result;
60 }
61
62 let mut options = LinkOptions::new();
65 options.kind = OutputKind::StaticExecutable;
66 options.push_input(
67 InputKind::bytes("main.o", objects::main_object()),
68 InputAttrs::default(),
69 );
70 options.push_input(
71 InputKind::bytes("answer.o", objects::answer_object(42)),
72 InputAttrs::default(),
73 );
74 let buffer = OutputBuffer::new();
75 options.output_buffer = Some(buffer.clone());
76
77 link_with_deadline(options.clone(), Duration::from_secs(10))?;
78 println!(
79 "with a 10 s deadline: linked {} bytes",
80 buffer.take().map_or(0, |b| b.len())
81 );
82
83 let token = CancelToken::new();
84 token.cancel();
85 options.cancel = Some(token);
86 match qld::link(&options, &Stderr::new(qld::PROGRAM_NAME)) {
87 Err(error) if CancelToken::is_cancellation(&error) => {
88 println!(
89 "cancelled before it started: {error}; output empty: {}",
90 !buffer.is_filled()
91 );
92 }
93 other => println!("unexpected: {other:?}"),
94 }
95 Ok(())
96}