Rust · 5222 bytes Raw Blame History
1 use std::process::ExitCode;
2
3 use afs_ld::{args, diag, dump, LinkError, Linker};
4
5 fn usage() -> &'static str {
6 "\
7 Usage: afs-ld [options] <inputs...>
8
9 Options:
10 -o <path> Write output to <path>
11 -dylib Emit a dylib instead of an executable
12 -e <symbol> Set the entry symbol
13 -arch arm64 Select the arm64 target
14 -map <path> Emit text link map
15 -why_live <symbol> Print a reachability chain for <symbol>
16 -l<name> / -l <name> Search for library
17 -L <dir> Add library search path
18 -framework <name> Link framework
19 -weak_framework <name> Link weak framework
20 -ObjC Objective-C archive loading mode (currently a no-op warning)
21 -syslibroot <path> Prefix SDK search roots
22 -platform_version macos <min> <sdk>
23 Set LC_BUILD_VERSION payload
24 -r Relocatable output (deferred; errors)
25 -bundle Bundle output (deferred; errors)
26 -undefined <error|warning|suppress|dynamic_lookup>
27 Control unresolved-symbol treatment
28 -rpath <path> Add LC_RPATH
29 -install_name <path> Override dylib install name
30 -current_version <v> Override dylib current version
31 -compatibility_version <v> Override dylib compatibility version
32 -exported_symbols_list <file> Export only symbols matching file patterns
33 -unexported_symbols_list <file> Hide symbols matching file patterns
34 -exported_symbol <sym> Export one symbol/pattern
35 -unexported_symbol <sym> Hide one symbol/pattern
36 -x Strip local symbols
37 -S Strip debug symbols (currently a no-op warning)
38 -no_uuid Omit LC_UUID
39 -no_loh Accepted for compatibility (currently warns; no effect)
40 -thunks=<none|safe|all> Configure branch thunks
41 -dead_strip Dead-strip unreferenced code/data
42 -icf=safe | -icf=none | -icf=all
43 Configure identical code folding (`all` currently errors)
44 -fixup_chains | -no_fixup_chains
45 Select chained fixups vs classic dyld info
46 -all_load Force-load every archive member
47 -force_load <archive> Force-load one archive
48 -j <jobs> Limit parallel worker jobs (`1` disables parallelism)
49 -Wl,<arg,arg,...> Normalize comma-separated driver flags
50 --dump <path> Dump a Mach-O file summary
51 --dump-archive <path> Dump an archive summary
52 --dump-dylib <path> Dump a dylib summary
53 --dump-tbd <path> Dump a TBD summary
54 -t, -trace Print input paths as they are loaded
55 -h, --help Show this help
56 -v, --version Show afs-ld version
57 "
58 }
59
60 fn main() -> ExitCode {
61 let argv: Vec<String> = std::env::args().collect();
62
63 let opts = match args::parse(&argv[1..]) {
64 Ok(opts) => opts,
65 Err(e) => {
66 diag::error(&e.to_string());
67 return ExitCode::from(2);
68 }
69 };
70
71 if opts.show_help {
72 print!("{}", usage());
73 return ExitCode::SUCCESS;
74 }
75
76 if opts.show_version {
77 println!("afs-ld {}", env!("CARGO_PKG_VERSION"));
78 return ExitCode::SUCCESS;
79 }
80
81 if let Some(path) = &opts.dump {
82 return match dump::dump_file(path) {
83 Ok(()) => ExitCode::SUCCESS,
84 Err(e) => {
85 diag::error(&format!("{}: {}", path.display(), e));
86 ExitCode::from(1)
87 }
88 };
89 }
90
91 if let Some(path) = &opts.dump_archive {
92 return match dump::dump_archive_file(path) {
93 Ok(()) => ExitCode::SUCCESS,
94 Err(e) => {
95 diag::error(&format!("{}: {}", path.display(), e));
96 ExitCode::from(1)
97 }
98 };
99 }
100
101 if let Some(path) = &opts.dump_dylib {
102 return match dump::dump_dylib_file(path) {
103 Ok(()) => ExitCode::SUCCESS,
104 Err(e) => {
105 diag::error(&format!("{}: {}", path.display(), e));
106 ExitCode::from(1)
107 }
108 };
109 }
110
111 if let Some(path) = &opts.dump_tbd {
112 return match dump::dump_tbd_file(path) {
113 Ok(()) => ExitCode::SUCCESS,
114 Err(e) => {
115 diag::error(&format!("{}: {}", path.display(), e));
116 ExitCode::from(1)
117 }
118 };
119 }
120
121 match Linker::run(&opts) {
122 Ok(()) => ExitCode::SUCCESS,
123 Err(LinkError::NoInputs) => {
124 diag::error("no input files");
125 ExitCode::from(2)
126 }
127 Err(LinkError::DuplicateSymbols(msg)) | Err(LinkError::UndefinedSymbols(msg)) => {
128 diag::error_verbatim(&msg);
129 ExitCode::from(1)
130 }
131 Err(e) => {
132 diag::error(&e.to_string());
133 ExitCode::from(1)
134 }
135 }
136 }
137