#[non_exhaustive]pub struct LinkOptions {Show 152 fields
pub flavor: Flavor,
pub target: Option<Target>,
pub endian: Option<Endianness>,
pub output: Option<PathBuf>,
pub output_format: Option<OutputFormat>,
pub kind: OutputKind,
pub inputs: Vec<InputSpec>,
pub search_paths: Vec<PathBuf>,
pub nostdlib: bool,
pub sysroot: Option<PathBuf>,
pub default_script: Option<PathBuf>,
pub entry: Option<String>,
pub soname: Option<String>,
pub dynamic_linker: Option<PathBuf>,
pub no_dynamic_linker: bool,
pub rpaths: Vec<PathBuf>,
pub rpath_links: Vec<PathBuf>,
pub new_dtags: Option<bool>,
pub undefined: Vec<String>,
pub undefined_glob: Vec<String>,
pub require_defined: Vec<String>,
pub defsym: Vec<(String, String)>,
pub wrap: Vec<String>,
pub init: Option<String>,
pub fini: Option<String>,
pub auxiliary: Vec<String>,
pub filter: Vec<String>,
pub gc_sections: bool,
pub print_gc_sections: bool,
pub gc_keep_exported: bool,
pub why_live: Vec<String>,
pub icf: IcfMode,
pub print_icf_sections: bool,
pub keep_unique: Vec<String>,
pub ignore_data_address_equality: bool,
pub ignore_function_address_equality: bool,
pub strip: StripMode,
pub discard: DiscardMode,
pub retain_symbols_file: Option<PathBuf>,
pub build_id: BuildId,
pub hash_style: HashStyle,
pub eh_frame_hdr: bool,
pub export_dynamic: bool,
pub export_dynamic_symbols: Vec<String>,
pub export_dynamic_symbol_lists: Vec<PathBuf>,
pub dynamic_lists: Vec<PathBuf>,
pub dynamic_list_data: bool,
pub dynamic_list_cpp_new: bool,
pub dynamic_list_cpp_typeinfo: bool,
pub exclude_libs: Vec<String>,
pub version_scripts: Vec<PathBuf>,
pub undefined_version: Option<bool>,
pub default_symver: bool,
pub symbolic: SymbolicMode,
pub no_undefined: Option<bool>,
pub allow_shlib_undefined: Option<bool>,
pub unresolved_symbols: Option<UnresolvedSymbols>,
pub warn_unresolved_symbols: bool,
pub ignore_unresolved_symbols: Vec<String>,
pub allow_multiple_definition: bool,
pub warn_common: bool,
pub warn_backrefs: bool,
pub warn_backrefs_exclude: Vec<String>,
pub warn_textrel: bool,
pub error_textrel: bool,
pub bind_now: bool,
pub relro: bool,
pub separate_code: Option<SeparateCode>,
pub rosegment: Option<bool>,
pub exec_stack: ExecStack,
pub gnu_stack: bool,
pub stack_size: Option<u64>,
pub max_page_size: Option<u64>,
pub common_page_size: Option<u64>,
pub copy_relocs: bool,
pub combine_relocs: bool,
pub pack_relative_relocs: bool,
pub gnu_tls_tag: bool,
pub gnu2_tls_tag: bool,
pub apply_dynamic_relocs: bool,
pub dynamic_flags: DynamicFlags,
pub start_stop_gc: Option<bool>,
pub start_stop_visibility: Option<Visibility>,
pub keep_text_section_prefix: bool,
pub dynamic_undefined_weak: Option<bool>,
pub extern_protected_data: bool,
pub mark_plt: bool,
pub section_header: bool,
pub memory_seal: bool,
pub dead_reloc_in_nonalloc: Vec<(String, u64)>,
pub x86: X86Features,
pub fix_cortex_a53_843419: bool,
pub aarch64: Aarch64Features,
pub spare_dynamic_tags: Option<u64>,
pub emit_relocs: bool,
pub define_common: bool,
pub magic: MagicMode,
pub relax: bool,
pub merge_exidx_entries: bool,
pub relax_gp: bool,
pub image_base: Option<u64>,
pub section_starts: Vec<(String, u64)>,
pub text_segment: Option<u64>,
pub rodata_segment: Option<u64>,
pub ldata_segment: Option<u64>,
pub orphan_handling: OrphanHandling,
pub sort_section: SortSection,
pub compress_debug_sections: DebugCompression,
pub package_metadata: Option<String>,
pub symbol_ordering_file: Option<PathBuf>,
pub no_warn_symbol_ordering: bool,
pub call_graph_profile_sort: Option<CallGraphSort>,
pub call_graph_ordering_file: Option<PathBuf>,
pub print_symbol_order: Option<PathBuf>,
pub gdb_index: bool,
pub s390_pgste: bool,
pub debug_names: bool,
pub separate_debug_file: Option<Option<PathBuf>>,
pub dependency_file: Option<PathBuf>,
pub dependent_libraries: bool,
pub optimize: u8,
pub threads: Option<usize>,
pub map_file: Option<PathBuf>,
pub print_map: bool,
pub cref: bool,
pub trace: bool,
pub trace_symbols: Vec<String>,
pub verbose: bool,
pub demangle: bool,
pub fatal_warnings: bool,
pub no_warnings: bool,
pub error_limit: Option<u64>,
pub color: ColorChoice,
pub noinhibit_exec: bool,
pub pe: PeArgs,
pub darwin: DarwinArgs,
pub plugins: Vec<(PathBuf, Vec<String>)>,
pub plugin_save_temps: bool,
pub exit_on_plugin_fatal: bool,
pub fork: bool,
pub on_output_complete: Option<OutputCompleteHook>,
pub input_provider: Option<Arc<dyn InputProvider>>,
pub output_buffer: Option<OutputBuffer>,
pub cancel: Option<CancelToken>,
pub map_output: Option<TextOutput>,
pub timing: Option<TextOutput>,
pub env_run_path: Vec<PathBuf>,
pub env_library_path: Vec<PathBuf>,
pub zero_ar_date: bool,
pub output_backing: Option<OutputBacking>,
pub ignored: Vec<OsString>,
pub warnings: Vec<String>,
}Expand description
Everything a link is configured by.
Construct one with LinkOptions::new and the builder methods, or parse
argv with crate::args::parse_gnu.
Fields typed Option<bool> distinguish “not given” (None, meaning the
target’s or output kind’s default applies) from an explicit choice.
LinkOptions::default is LinkOptions::new: both describe the link
GNU ld performs when the command line says nothing, so the ten options
GNU ld has on by default (-z relro, --demangle, --relax, …) are on
in both.
The struct is #[non_exhaustive]: qld adds fields as it implements more
options, so build one with LinkOptions::new and assign the fields you
need.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.flavor: FlavorCommand-line dialect this was parsed from.
target: Option<Target>Target, when it was given explicitly (-m). Otherwise it is inferred
from the first object input.
endian: Option<Endianness>Endianness forced with -EB / -EL.
output: Option<PathBuf>Output path (-o). None means the flavor’s default (a.out).
output_format: Option<OutputFormat>Output format (--oformat), such as binary or elf64-x86-64.
kind: OutputKindWhat kind of output to produce.
inputs: Vec<InputSpec>Inputs, in command-line order.
search_paths: Vec<PathBuf>Library search paths (-L), in order.
nostdlib: bool-nostdlib: ignore SEARCH_DIR commands in linker scripts.
sysroot: Option<PathBuf>--sysroot.
default_script: Option<PathBuf>--default-script / -dT: used when no -T script is given.
entry: Option<String>Entry point (-e).
soname: Option<String>-soname / -install_name.
dynamic_linker: Option<PathBuf>Program interpreter (--dynamic-linker).
no_dynamic_linker: bool--no-dynamic-linker: omit PT_INTERP (used for static PIE).
rpaths: Vec<PathBuf>-rpath entries, in order.
rpath_links: Vec<PathBuf>-rpath-link entries, in order.
--enable-new-dtags (Some(true), DT_RUNPATH) or
--disable-new-dtags (Some(false), DT_RPATH).
undefined: Vec<String>Symbols required to be defined (-u, --undefined).
undefined_glob: Vec<String>--undefined-glob patterns.
require_defined: Vec<String>--require-defined symbols: like -u, but an error if undefined.
defsym: Vec<(String, String)>--defsym assignments, in order.
wrap: Vec<String>--wrap symbols.
init: Option<String>-init symbol (DT_INIT).
fini: Option<String>-fini symbol (DT_FINI).
auxiliary: Vec<String>-f / --auxiliary names (DT_AUXILIARY).
filter: Vec<String>-F / --filter names (DT_FILTER).
gc_sections: boolRemove unreferenced sections (--gc-sections).
print_gc_sections: bool--print-gc-sections.
gc_keep_exported: bool--gc-keep-exported: exported symbols are GC roots.
why_live: Vec<String>--why-live symbol patterns.
icf: IcfModeIdentical code folding (--icf).
print_icf_sections: bool--print-icf-sections.
keep_unique: Vec<String>--keep-unique symbols, never folded by ICF.
ignore_data_address_equality: bool--ignore-data-address-equality.
ignore_function_address_equality: bool--ignore-function-address-equality.
strip: StripModeStrip level.
discard: DiscardModeLocal symbol discarding (-x, -X, --discard-none).
retain_symbols_file: Option<PathBuf>--retain-symbols-file.
build_id: BuildIdBuild ID generation.
hash_style: HashStyleDynamic symbol hash tables to emit.
eh_frame_hdr: bool--eh-frame-hdr: create .eh_frame_hdr and PT_GNU_EH_FRAME.
export_dynamic: boolExport all symbols from an executable (--export-dynamic).
export_dynamic_symbols: Vec<String>--export-dynamic-symbol patterns.
export_dynamic_symbol_lists: Vec<PathBuf>--export-dynamic-symbol-list files.
dynamic_lists: Vec<PathBuf>--dynamic-list files.
dynamic_list_data: bool--dynamic-list-data: add every defined data symbol to the dynamic
list.
dynamic_list_cpp_new: bool--dynamic-list-cpp-new: add operator new and operator delete
to the dynamic list.
dynamic_list_cpp_typeinfo: bool--dynamic-list-cpp-typeinfo: add the C++ type information symbols
to the dynamic list.
exclude_libs: Vec<String>--exclude-libs archive names (ALL is kept as a name).
version_scripts: Vec<PathBuf>--version-script files.
undefined_version: Option<bool>--undefined-version (Some(true)) or --no-undefined-version
(Some(false)).
default_symver: bool--default-symver: version exported symbols with the soname.
symbolic: SymbolicMode-Bsymbolic and variants.
no_undefined: Option<bool>--no-undefined / -z defs (Some(true)) or -z undefs
(Some(false)): whether undefined symbols in regular objects are
errors even for shared output.
allow_shlib_undefined: Option<bool>--allow-shlib-undefined (Some(true)) or
--no-allow-shlib-undefined (Some(false)).
unresolved_symbols: Option<UnresolvedSymbols>--unresolved-symbols=.
warn_unresolved_symbols: bool--warn-unresolved-symbols: report unresolved symbols as warnings.
ignore_unresolved_symbols: Vec<String>--ignore-unresolved-symbol names.
allow_multiple_definition: bool--allow-multiple-definition / -z muldefs.
warn_common: bool--warn-common.
warn_backrefs: bool--warn-backrefs.
warn_backrefs_exclude: Vec<String>--warn-backrefs-exclude patterns.
warn_textrel: bool--warn-textrel: warn when the output needs DT_TEXTREL.
error_textrel: bool-z text: make DT_TEXTREL an error.
bind_now: boolResolve all dynamic symbols at load time (-z now).
relro: bool-z relro (default) / -z norelro.
separate_code: Option<SeparateCode>-z separate-code and friends. None means the target default.
rosegment: Option<bool>--rosegment (Some(true)) / --no-rosegment (Some(false)).
exec_stack: ExecStack-z execstack / -z noexecstack.
gnu_stack: bool-z nognustack clears this: omit PT_GNU_STACK.
stack_size: Option<u64>-z stack-size=: the PT_GNU_STACK size.
max_page_size: Option<u64>-z max-page-size=.
common_page_size: Option<u64>-z common-page-size=.
copy_relocs: bool-z copyreloc (default) / -z nocopyreloc.
combine_relocs: bool-z combreloc (default) / -z nocombreloc.
pack_relative_relocs: bool-z pack-relative-relocs or --pack-dyn-relocs=relr: emit DT_RELR.
gnu_tls_tag: bool--gnu-tls-tag (default) / --no-gnu-tls-tag: add the
GLIBC_ABI_GNU_TLS version dependency to an output that keeps GNU
general-dynamic or local-dynamic TLS, when a needed library defines
that version.
gnu2_tls_tag: bool--gnu2-tls-tag (default) / --no-gnu2-tls-tag: the same for
GLIBC_ABI_GNU2_TLS and TLS descriptors.
apply_dynamic_relocs: bool--apply-dynamic-relocs: also write addends into the output.
dynamic_flags: DynamicFlagsDT_FLAGS / DT_FLAGS_1 bits from -z keywords.
start_stop_gc: Option<bool>-z start-stop-gc (Some(true)) / -z nostart-stop-gc.
start_stop_visibility: Option<Visibility>-z start-stop-visibility=. None when the keyword was not given,
which leaves the linker’s own default.
keep_text_section_prefix: bool-z keep-text-section-prefix.
dynamic_undefined_weak: Option<bool>-z dynamic-undefined-weak (Some(true)) /
-z nodynamic-undefined-weak.
extern_protected_data: bool-z noextern-protected-data clears this.
mark_plt: bool-z mark-plt.
section_header: bool-z sectionheader (default) / -z nosectionheader.
memory_seal: bool-z memory-seal.
dead_reloc_in_nonalloc: Vec<(String, u64)>-z dead-reloc-in-nonalloc=<glob>=<value> rules, in command-line
order: the value written for a relocation in a non-allocated section
whose name matches the glob, when its target section was discarded.
Later rules take precedence.
x86: X86Featuresx86 CET and ISA-level options.
fix_cortex_a53_843419: bool--fix-cortex-a53-843419.
aarch64: Aarch64FeaturesAArch64 BTI, PAC and erratum options.
--spare-dynamic-tags.
emit_relocs: bool-q / --emit-relocs: keep relocations in the output.
define_common: bool-d, -dc, -dp: allocate common symbols even for -r.
magic: MagicMode-n / -N.
relax: bool--relax (default) / --no-relax.
merge_exidx_entries: boolArm --merge-exidx-entries (default) / --no-merge-exidx-entries:
drop .ARM.exidx entries that repeat the one before.
relax_gp: boolRISC-V --relax-gp: relax absolute accesses within 2 KiB of
__global_pointer$ to gp-relative ones (off by default, as in
lld).
image_base: Option<u64>--image-base.
section_starts: Vec<(String, u64)>--section-start, -Ttext, -Tdata, -Tbss: section addresses, in
order.
text_segment: Option<u64>-Ttext-segment.
rodata_segment: Option<u64>-Trodata-segment.
ldata_segment: Option<u64>-Tldata-segment.
orphan_handling: OrphanHandling--orphan-handling=.
sort_section: SortSection--sort-section=.
compress_debug_sections: DebugCompression--compress-debug-sections=.
package_metadata: Option<String>--package-metadata=: contents of .note.package.
symbol_ordering_file: Option<PathBuf>--symbol-ordering-file: order input sections by the symbols listed
in this file (lld).
no_warn_symbol_ordering: bool--no-warn-symbol-ordering: do not warn about symbols of the
ordering file that cannot be ordered.
call_graph_profile_sort: Option<CallGraphSort>--call-graph-profile-sort=: how to order sections by call graph
profile. None when not given: qld then orders only with
--call-graph-ordering-file (lld also sorts by default when an
input has a .llvm.call-graph-profile section).
call_graph_ordering_file: Option<PathBuf>--call-graph-ordering-file: call graph edges (from to weight).
print_symbol_order: Option<PathBuf>--print-symbol-order=: write the symbol order the call graph sort
chose to this file.
gdb_index: bool--gdb-index: write a .gdb_index section.
s390_pgste: bool--s390-pgste: add an empty PT_S390_PGSTE segment, which tells
the Linux kernel to allocate page tables with the guest storage
extension (s390x only).
debug_names: bool--debug-names: write a merged .debug_names section.
separate_debug_file: Option<Option<PathBuf>>--separate-debug-file[=FILE]: write the debug sections to FILE
(Some(None): the output path plus .dbg) and link it from the
output with .gnu_debuglink, as mold does.
dependency_file: Option<PathBuf>--dependency-file.
dependent_libraries: bool--dependent-libraries (default) / --no-dependent-libraries.
optimize: u8Optimization level (-O).
threads: Option<usize>Thread count (--threads). Some(n) runs the link in a pool of
n threads that crate::link creates for it.
None, the default, leaves the choice to the format driver: the ELF
driver sizes a pool from the input (small links run faster on few
threads), at most 16 threads and at most the available parallelism.
Called inside a rayon pool of your own
(rayon::ThreadPool::install), a link with None runs in that
pool and creates none, however large it is.
map_file: Option<PathBuf>Write a link map to this path (-Map).
print_map: bool-M / --print-map: write the link map to stdout.
cref: bool--cref: add a cross-reference table to the map.
trace: bool-t / --trace: print each input file as it is processed.
trace_symbols: Vec<String>-y / --trace-symbol names.
verbose: bool--verbose.
demangle: boolDemangle symbol names in diagnostics (--demangle, on by default).
fatal_warnings: bool--fatal-warnings.
no_warnings: bool-w / --no-warnings.
error_limit: Option<u64>--error-limit. Some(0) means no limit.
color: ColorChoice--color-diagnostics.
noinhibit_exec: bool--noinhibit-exec: write the output even after errors.
pe: PeArgsThe PE/COFF options of GNU ld’s MinGW emulations. Only PE links read them.
darwin: DarwinArgsThe Apple ld64 options that have no GNU equivalent. Only Mach-O links read them.
plugins: Vec<(PathBuf, Vec<String>)>LTO plugin paths (-plugin) and their options (-plugin-opt).
plugin_save_temps: bool-plugin-save-temps: keep the files an LTO plugin generates.
exit_on_plugin_fatal: boolExit the process when an LTO plugin reports a fatal error, as GNU ld
does. The qld binary sets this; library callers get an error
instead, and accept that a plugin may not expect to be called again.
fork: bool--fork (the default) / --no-fork: whether the qld binary runs
the link in a child process and returns as soon as the output is
complete, leaving the child to free memory and unmap the inputs.
Only the binary reads it (on Unix); the library never forks.
on_output_complete: Option<OutputCompleteHook>Called once when a successful link’s output is complete; see
OutputCompleteHook. None by default. The qld binary sets it
in the child process of --fork to let its parent exit early.
input_provider: Option<Arc<dyn InputProvider>>Files that exist only in memory, looked up by path before the file
system: inputs named by path, -l libraries found in the search
directories, INPUT/GROUP entries of input scripts, and thin
archive members. None by default (only the file system). See
MemoryFiles and
InputProvider.
The ELF driver uses it. Files read outside the input list (-T
scripts, version scripts, dynamic lists) still come from the file
system; so do all inputs of PE and Mach-O links.
output_buffer: Option<OutputBuffer>Hand the output image to this buffer instead of writing the output
file; see OutputBuffer. None by default.
cancel: Option<CancelToken>Stop the link with an error once this token is cancelled; see
CancelToken. None by default.
map_output: Option<TextOutput>Receives the link map of -M / --print-map, and the --cref
table when no -Map file was named. None by default, which drops
that text: a library link writes nothing to the process’s standard
output. See LinkOptions::use_process_defaults.
timing: Option<TextOutput>Receives one line per pipeline stage with the time it took, the way
QLD_TIMING asks the qld binary for. None by default, which
measures nothing. See LinkOptions::use_process_defaults.
env_run_path: Vec<PathBuf>LD_RUN_PATH, split into directories: searched for the dependencies
of shared libraries when no -rpath was given, as GNU ld does.
Empty by default; a library link reads no environment of its own.
See LinkOptions::use_process_defaults.
env_library_path: Vec<PathBuf>LD_LIBRARY_PATH, split into directories: searched for the
dependencies of shared libraries, as GNU ld does. Empty by default.
See LinkOptions::use_process_defaults.
zero_ar_date: boolRecord zero modification times in a Mach-O debug map, for
reproducible output; ZERO_AR_DATE in the environment asks ld64,
lld and the qld binary for it. Off by default. See
LinkOptions::use_process_defaults.
output_backing: Option<OutputBacking>How the output image is held while it is written. None, the
default, leaves the choice to the writer; QLD_OUTPUT_BACKING sets
it for the qld binary. See LinkOptions::use_process_defaults.
ignored: Vec<OsString>Options that were recognized but have no effect yet, kept so that
--verbose and tests can report them.
warnings: Vec<String>Warnings produced while parsing the command line (for example an
unknown -z keyword), in command-line order. The driver emits them to
its diagnostic sink.
Implementations§
Source§impl LinkOptions
impl LinkOptions
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates the options of a link whose command line said nothing: every field at the default GNU ld uses.
Examples found in repository?
22fn link(value: u8) -> qld::Result<Vec<u8>> {
23 let mut options = LinkOptions::new();
24 options.kind = OutputKind::StaticExecutable;
25 options.push_input(
26 InputKind::bytes("main.o", objects::main_object()),
27 InputAttrs::default(),
28 );
29 options.push_input(
30 InputKind::bytes("answer.o", objects::answer_object(value)),
31 InputAttrs::default(),
32 );
33 let buffer = OutputBuffer::new();
34 options.output_buffer = Some(buffer.clone());
35 qld::link(&options, &Collect::new())?;
36 buffer
37 .take()
38 .ok_or_else(|| qld::Error::Internal("no output".into()))
39}More examples
89fn main() {
90 // `main.o` calls `answer`, which nothing defines.
91 let mut options = LinkOptions::new();
92 options.kind = OutputKind::StaticExecutable;
93 options.output_buffer = Some(OutputBuffer::new());
94 options.push_input(
95 InputKind::bytes("main.o", objects::main_object()),
96 InputAttrs::default(),
97 );
98
99 let sink = JsonLines::default();
100 let result = qld::link(&options, &sink);
101 print!("{}", sink.render());
102 match result {
103 Ok(()) => println!("linked"),
104 Err(qld::Error::Reported { errors }) => {
105 println!("the link failed with {errors} error(s) reported above");
106 }
107 Err(error) => println!("the link failed: {error}"),
108 }
109}23fn main() -> qld::Result<()> {
24 let mut options = LinkOptions::new();
25 options.kind = OutputKind::StaticExecutable;
26 options.push_input(
27 InputKind::bytes("main.o", objects::main_object()),
28 InputAttrs::default(),
29 );
30 options.push_input(
31 InputKind::bytes("answer.o", objects::answer_object(42)),
32 InputAttrs::default(),
33 );
34
35 // `-M` and `--cref`, into a string instead of standard output.
36 options.print_map = true;
37 options.cref = true;
38 let map = Arc::new(Mutex::new(String::new()));
39 let collected = Arc::clone(&map);
40 options.map_output = Some(TextOutput::new(move |text| {
41 collected.lock().unwrap().push_str(text);
42 }));
43
44 let image = qld::link_to_memory(&options, &Collect::new())?;
45 let map = map.lock().unwrap();
46 println!("linked {} bytes, {} of map", image.len(), map.len());
47 for line in map.lines().take(8) {
48 println!(" {line}");
49 }
50
51 // What the same options would take from the process, if asked.
52 let mut as_the_binary = options.clone();
53 as_the_binary.use_process_defaults();
54 println!(
55 "\nhermetic: map_output {}, LD_LIBRARY_PATH {} entries, timing {}",
56 if options.map_output.is_some() {
57 "set by this program"
58 } else {
59 "unset"
60 },
61 options.env_library_path.len(),
62 if options.timing.is_some() {
63 "on"
64 } else {
65 "off"
66 },
67 );
68 println!(
69 "as the binary: LD_LIBRARY_PATH {} entries, timing {}",
70 as_the_binary.env_library_path.len(),
71 if as_the_binary.timing.is_some() {
72 "on"
73 } else {
74 "off"
75 },
76 );
77 Ok(())
78}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}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}Sourcepub fn use_process_defaults(&mut self)
pub fn use_process_defaults(&mut self)
Makes these options describe a link run the way the qld binary
runs one, by taking from the process what a library link must be
told explicitly.
Nothing else in qld reads the environment or writes to standard
output or standard error, so a LinkOptions that never went through
this method describes a hermetic, silent link. parse_gnu and
parse_darwin call it, because they parse a command line the way
the binary does; parse_gnu_with, parse_darwin_with and
LinkOptions::new do not.
It sets:
map_outputto standard output, where GNU ld writes the map of-Mand a--creftable with no-Mapfile;timingto standard error whenQLD_TIMINGis set in the environment;env_run_pathfromLD_RUN_PATHandenv_library_pathfromLD_LIBRARY_PATH, which GNU ld also searches;zero_ar_datefromZERO_AR_DATE, which ld64 and lld also read;output_backingfromQLD_OUTPUT_BACKING, a benchmarking knob.
Examples found in repository?
23fn main() -> qld::Result<()> {
24 let mut options = LinkOptions::new();
25 options.kind = OutputKind::StaticExecutable;
26 options.push_input(
27 InputKind::bytes("main.o", objects::main_object()),
28 InputAttrs::default(),
29 );
30 options.push_input(
31 InputKind::bytes("answer.o", objects::answer_object(42)),
32 InputAttrs::default(),
33 );
34
35 // `-M` and `--cref`, into a string instead of standard output.
36 options.print_map = true;
37 options.cref = true;
38 let map = Arc::new(Mutex::new(String::new()));
39 let collected = Arc::clone(&map);
40 options.map_output = Some(TextOutput::new(move |text| {
41 collected.lock().unwrap().push_str(text);
42 }));
43
44 let image = qld::link_to_memory(&options, &Collect::new())?;
45 let map = map.lock().unwrap();
46 println!("linked {} bytes, {} of map", image.len(), map.len());
47 for line in map.lines().take(8) {
48 println!(" {line}");
49 }
50
51 // What the same options would take from the process, if asked.
52 let mut as_the_binary = options.clone();
53 as_the_binary.use_process_defaults();
54 println!(
55 "\nhermetic: map_output {}, LD_LIBRARY_PATH {} entries, timing {}",
56 if options.map_output.is_some() {
57 "set by this program"
58 } else {
59 "unset"
60 },
61 options.env_library_path.len(),
62 if options.timing.is_some() {
63 "on"
64 } else {
65 "off"
66 },
67 );
68 println!(
69 "as the binary: LD_LIBRARY_PATH {} entries, timing {}",
70 as_the_binary.env_library_path.len(),
71 if as_the_binary.timing.is_some() {
72 "on"
73 } else {
74 "off"
75 },
76 );
77 Ok(())
78}Sourcepub fn output_complete(&self)
pub fn output_complete(&self)
Runs the on_output_complete hook, if
there is one and it has not run yet.
Link drivers call this once the output of a successful link is
complete, and crate::link calls it before returning Ok for
drivers that did not.
Sourcepub fn check_cancelled(&self) -> Result<()>
pub fn check_cancelled(&self) -> Result<()>
Returns an error if the link was cancelled through
LinkOptions::cancel. Link drivers call this between stages.
§Errors
CancelToken::error once the token is cancelled.
Sourcepub fn output_path(&self) -> PathBuf
pub fn output_path(&self) -> PathBuf
Returns the output path, or the flavor’s default.
Sourcepub fn is_dynamic(&self) -> bool
pub fn is_dynamic(&self) -> bool
Whether the output links against shared libraries at run time.
Sourcepub fn push_input(&mut self, kind: InputKind, attrs: InputAttrs)
pub fn push_input(&mut self, kind: InputKind, attrs: InputAttrs)
Appends an input with the given attributes.
Examples found in repository?
22fn link(value: u8) -> qld::Result<Vec<u8>> {
23 let mut options = LinkOptions::new();
24 options.kind = OutputKind::StaticExecutable;
25 options.push_input(
26 InputKind::bytes("main.o", objects::main_object()),
27 InputAttrs::default(),
28 );
29 options.push_input(
30 InputKind::bytes("answer.o", objects::answer_object(value)),
31 InputAttrs::default(),
32 );
33 let buffer = OutputBuffer::new();
34 options.output_buffer = Some(buffer.clone());
35 qld::link(&options, &Collect::new())?;
36 buffer
37 .take()
38 .ok_or_else(|| qld::Error::Internal("no output".into()))
39}More examples
89fn main() {
90 // `main.o` calls `answer`, which nothing defines.
91 let mut options = LinkOptions::new();
92 options.kind = OutputKind::StaticExecutable;
93 options.output_buffer = Some(OutputBuffer::new());
94 options.push_input(
95 InputKind::bytes("main.o", objects::main_object()),
96 InputAttrs::default(),
97 );
98
99 let sink = JsonLines::default();
100 let result = qld::link(&options, &sink);
101 print!("{}", sink.render());
102 match result {
103 Ok(()) => println!("linked"),
104 Err(qld::Error::Reported { errors }) => {
105 println!("the link failed with {errors} error(s) reported above");
106 }
107 Err(error) => println!("the link failed: {error}"),
108 }
109}23fn main() -> qld::Result<()> {
24 let mut options = LinkOptions::new();
25 options.kind = OutputKind::StaticExecutable;
26 options.push_input(
27 InputKind::bytes("main.o", objects::main_object()),
28 InputAttrs::default(),
29 );
30 options.push_input(
31 InputKind::bytes("answer.o", objects::answer_object(42)),
32 InputAttrs::default(),
33 );
34
35 // `-M` and `--cref`, into a string instead of standard output.
36 options.print_map = true;
37 options.cref = true;
38 let map = Arc::new(Mutex::new(String::new()));
39 let collected = Arc::clone(&map);
40 options.map_output = Some(TextOutput::new(move |text| {
41 collected.lock().unwrap().push_str(text);
42 }));
43
44 let image = qld::link_to_memory(&options, &Collect::new())?;
45 let map = map.lock().unwrap();
46 println!("linked {} bytes, {} of map", image.len(), map.len());
47 for line in map.lines().take(8) {
48 println!(" {line}");
49 }
50
51 // What the same options would take from the process, if asked.
52 let mut as_the_binary = options.clone();
53 as_the_binary.use_process_defaults();
54 println!(
55 "\nhermetic: map_output {}, LD_LIBRARY_PATH {} entries, timing {}",
56 if options.map_output.is_some() {
57 "set by this program"
58 } else {
59 "unset"
60 },
61 options.env_library_path.len(),
62 if options.timing.is_some() {
63 "on"
64 } else {
65 "off"
66 },
67 );
68 println!(
69 "as the binary: LD_LIBRARY_PATH {} entries, timing {}",
70 as_the_binary.env_library_path.len(),
71 if as_the_binary.timing.is_some() {
72 "on"
73 } else {
74 "off"
75 },
76 );
77 Ok(())
78}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}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}Sourcepub fn resolve_sysroot(&self, path: &Path) -> PathBuf
pub fn resolve_sysroot(&self, path: &Path) -> PathBuf
Resolves a path that may start with = or $SYSROOT against
LinkOptions::sysroot, as GNU ld does for -L, -T, -rpath-link
and script INPUTs.
Paths without the prefix are returned unchanged. When there is no sysroot the prefix is simply removed. This is a pure string operation; it does not touch the file system.
Trait Implementations§
Source§impl Clone for LinkOptions
impl Clone for LinkOptions
Source§impl Debug for LinkOptions
impl Debug for LinkOptions
Source§impl Default for LinkOptions
impl Default for LinkOptions
Source§fn default() -> Self
fn default() -> Self
Identical to LinkOptions::new.
Auto Trait Implementations§
impl !RefUnwindSafe for LinkOptions
impl !UnwindSafe for LinkOptions
impl Freeze for LinkOptions
impl Send for LinkOptions
impl Sync for LinkOptions
impl Unpin for LinkOptions
impl UnsafeUnpin for LinkOptions
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more