Skip to main content

parse_gnu

Function parse_gnu 

Source
pub fn parse_gnu<S: AsRef<OsStr>>(args: &[S]) -> Result<ParseOutcome>
Expand description

Parses a GNU ld / gold / lld / mold command line.

args includes argv[0], which also selects the flavor when it is a name such as ld64.qld (see select_flavor). Response files are read with std::fs::read; use parse_gnu_with to supply them another way.

The options describe a link run the way the qld binary runs one: LinkOptions::use_process_defaults is applied, so the link map goes to standard output and LD_LIBRARY_PATH and the other variables GNU ld reads are taken from the environment. parse_gnu_with parses the same command line into a hermetic, silent link.

Warnings found while parsing, such as unknown -z keywords, are returned in LinkOptions::warnings for the caller to report.

ยงErrors

Returns Error::Option for an unknown, unsupported or malformed option, Error::Io for an unreadable response file, and Error::Unimplemented for a flavor qld does not parse yet.

Examples found in repository?
examples/link_argv.rs (line 35)
34fn link(args: &[std::ffi::OsString], diagnostics: &dyn DiagnosticSink) -> qld::Result<()> {
35    let options = match qld::parse_gnu(args)? {
36        ParseOutcome::Link(options) => options,
37        ParseOutcome::Help => {
38            print!("{}", qld::args::usage());
39            return Ok(());
40        }
41        ParseOutcome::Version => {
42            println!("{}", qld::version_line());
43            return Ok(());
44        }
45    };
46    // Parsing does no reporting: warnings such as an unknown `-z` keyword
47    // come back in the options, for the caller to emit.
48    if !options.no_warnings {
49        for warning in &options.warnings {
50            diagnostics.emit(Diagnostic::warning(warning.clone()));
51        }
52    }
53    if options.fatal_warnings && !options.warnings.is_empty() {
54        return Err(qld::Error::Reported {
55            errors: options.warnings.len(),
56        });
57    }
58    qld::link(&options, diagnostics)
59}
More examples
Hide additional examples
examples/cancel.rs (line 47)
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    // Without arguments: link the in-memory demo program twice, once with
63    // plenty of time and once cancelled before it starts.
64    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}
examples/in_memory.rs (line 55)
25fn main() -> qld::Result<()> {
26    // Object code from a compiler or JIT in the same process.
27    let main_o = objects::main_object();
28    let answer_o = objects::answer_object(42);
29
30    // 1. Buffers as inputs, the output into a buffer.
31    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    // 2. A command line whose files live in memory: `main.o`, and
49    //    `libanswer.a` in a search directory that does not exist on disk.
50    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}