1 | //===- DriverUtils.cpp ----------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "Config.h" |
10 | #include "Driver.h" |
11 | #include "InputFiles.h" |
12 | |
13 | #include "lld/Common/Args.h" |
14 | #include "lld/Common/CommonLinkerContext.h" |
15 | #include "lld/Common/Reproduce.h" |
16 | #include "llvm/ADT/CachedHashString.h" |
17 | #include "llvm/ADT/DenseMap.h" |
18 | #include "llvm/LTO/LTO.h" |
19 | #include "llvm/Option/Arg.h" |
20 | #include "llvm/Option/ArgList.h" |
21 | #include "llvm/Option/Option.h" |
22 | #include "llvm/Support/CommandLine.h" |
23 | #include "llvm/Support/FileSystem.h" |
24 | #include "llvm/Support/Path.h" |
25 | #include "llvm/TextAPI/InterfaceFile.h" |
26 | #include "llvm/TextAPI/TextAPIReader.h" |
27 | |
28 | using namespace llvm; |
29 | using namespace llvm::MachO; |
30 | using namespace llvm::opt; |
31 | using namespace llvm::sys; |
32 | using namespace lld; |
33 | using namespace lld::macho; |
34 | |
35 | #define OPTTABLE_STR_TABLE_CODE |
36 | #include "Options.inc" |
37 | #undef OPTTABLE_STR_TABLE_CODE |
38 | |
39 | // Create prefix string literals used in Options.td |
40 | #define OPTTABLE_PREFIXES_TABLE_CODE |
41 | #include "Options.inc" |
42 | #undef OPTTABLE_PREFIXES_TABLE_CODE |
43 | |
44 | // Create table mapping all options defined in Options.td |
45 | static constexpr OptTable::Info optInfo[] = { |
46 | #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \ |
47 | VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, \ |
48 | VALUES) \ |
49 | {PREFIX, \ |
50 | NAME, \ |
51 | HELPTEXT, \ |
52 | HELPTEXTSFORVARIANTS, \ |
53 | METAVAR, \ |
54 | OPT_##ID, \ |
55 | opt::Option::KIND##Class, \ |
56 | PARAM, \ |
57 | FLAGS, \ |
58 | VISIBILITY, \ |
59 | OPT_##GROUP, \ |
60 | OPT_##ALIAS, \ |
61 | ALIASARGS, \ |
62 | VALUES}, |
63 | #include "Options.inc" |
64 | #undef OPTION |
65 | }; |
66 | |
67 | MachOOptTable::MachOOptTable() |
68 | : GenericOptTable(OptionStrTable, OptionPrefixesTable, optInfo) {} |
69 | |
70 | // Set color diagnostics according to --color-diagnostics={auto,always,never} |
71 | // or --no-color-diagnostics flags. |
72 | static void handleColorDiagnostics(CommonLinkerContext &ctx, |
73 | InputArgList &args) { |
74 | const Arg *arg = |
75 | args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, |
76 | OPT_no_color_diagnostics); |
77 | if (!arg) |
78 | return; |
79 | auto &errs = ctx.e.errs(); |
80 | if (arg->getOption().getID() == OPT_color_diagnostics) { |
81 | errs.enable_colors(enable: true); |
82 | } else if (arg->getOption().getID() == OPT_no_color_diagnostics) { |
83 | errs.enable_colors(enable: false); |
84 | } else { |
85 | StringRef s = arg->getValue(); |
86 | if (s == "always" ) |
87 | errs.enable_colors(enable: true); |
88 | else if (s == "never" ) |
89 | errs.enable_colors(enable: false); |
90 | else if (s != "auto" ) |
91 | error(msg: "unknown option: --color-diagnostics=" + s); |
92 | } |
93 | } |
94 | |
95 | InputArgList MachOOptTable::parse(CommonLinkerContext &ctx, |
96 | ArrayRef<const char *> argv) { |
97 | // Make InputArgList from string vectors. |
98 | unsigned missingIndex; |
99 | unsigned missingCount; |
100 | SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size()); |
101 | |
102 | // Expand response files (arguments in the form of @<filename>) |
103 | // and then parse the argument again. |
104 | cl::ExpandResponseFiles(Saver&: saver(), Tokenizer: cl::TokenizeGNUCommandLine, Argv&: vec); |
105 | InputArgList args = ParseArgs(Args: vec, MissingArgIndex&: missingIndex, MissingArgCount&: missingCount); |
106 | |
107 | // Handle -fatal_warnings early since it converts missing argument warnings |
108 | // to errors. |
109 | errorHandler().fatalWarnings = args.hasArg(OPT_fatal_warnings); |
110 | errorHandler().suppressWarnings = args.hasArg(OPT_w); |
111 | |
112 | if (missingCount) |
113 | error(msg: Twine(args.getArgString(Index: missingIndex)) + ": missing argument" ); |
114 | |
115 | handleColorDiagnostics(ctx, args); |
116 | |
117 | for (const Arg *arg : args.filtered(OPT_UNKNOWN)) { |
118 | std::string nearest; |
119 | if (findNearest(arg->getAsString(args), nearest) > 1) |
120 | error("unknown argument '" + arg->getAsString(args) + "'" ); |
121 | else |
122 | error("unknown argument '" + arg->getAsString(args) + |
123 | "', did you mean '" + nearest + "'" ); |
124 | } |
125 | return args; |
126 | } |
127 | |
128 | void MachOOptTable::printHelp(CommonLinkerContext &ctx, const char *argv0, |
129 | bool showHidden) const { |
130 | auto &outs = ctx.e.outs(); |
131 | OptTable::printHelp(OS&: outs, Usage: (std::string(argv0) + " [options] file..." ).c_str(), |
132 | Title: "LLVM Linker" , ShowHidden: showHidden); |
133 | outs << '\n'; |
134 | } |
135 | |
136 | static std::string rewritePath(StringRef s) { |
137 | if (fs::exists(Path: s)) |
138 | return relativeToRoot(path: s); |
139 | return std::string(s); |
140 | } |
141 | |
142 | static std::string rewriteInputPath(StringRef s) { |
143 | // Don't bother rewriting "absolute" paths that are actually under the |
144 | // syslibroot; simply rewriting the syslibroot is sufficient. |
145 | if (rerootPath(path: s) == s && fs::exists(Path: s)) |
146 | return relativeToRoot(path: s); |
147 | return std::string(s); |
148 | } |
149 | |
150 | // Reconstructs command line arguments so that so that you can re-run |
151 | // the same command with the same inputs. This is for --reproduce. |
152 | std::string macho::createResponseFile(const InputArgList &args) { |
153 | SmallString<0> data; |
154 | raw_svector_ostream os(data); |
155 | |
156 | // Copy the command line to the output while rewriting paths. |
157 | for (const Arg *arg : args) { |
158 | switch (arg->getOption().getID()) { |
159 | case OPT_reproduce: |
160 | break; |
161 | case OPT_INPUT: |
162 | os << quote(s: rewriteInputPath(s: arg->getValue())) << "\n" ; |
163 | break; |
164 | case OPT_o: |
165 | os << "-o " << quote(s: path::filename(path: arg->getValue())) << "\n" ; |
166 | break; |
167 | case OPT_filelist: |
168 | if (std::optional<MemoryBufferRef> buffer = readFile(path: arg->getValue())) |
169 | for (StringRef path : args::getLines(mb: *buffer)) |
170 | os << quote(s: rewriteInputPath(s: path)) << "\n" ; |
171 | break; |
172 | case OPT_force_load: |
173 | case OPT_weak_library: |
174 | case OPT_load_hidden: |
175 | os << arg->getSpelling() << " " |
176 | << quote(s: rewriteInputPath(s: arg->getValue())) << "\n" ; |
177 | break; |
178 | case OPT_F: |
179 | case OPT_L: |
180 | case OPT_bundle_loader: |
181 | case OPT_exported_symbols_list: |
182 | case OPT_order_file: |
183 | case OPT_syslibroot: |
184 | case OPT_unexported_symbols_list: |
185 | os << arg->getSpelling() << " " << quote(s: rewritePath(s: arg->getValue())) |
186 | << "\n" ; |
187 | break; |
188 | case OPT_sectcreate: |
189 | os << arg->getSpelling() << " " << quote(s: arg->getValue(N: 0)) << " " |
190 | << quote(s: arg->getValue(N: 1)) << " " |
191 | << quote(s: rewritePath(s: arg->getValue(N: 2))) << "\n" ; |
192 | break; |
193 | default: |
194 | os << toString(arg: *arg) << "\n" ; |
195 | } |
196 | } |
197 | return std::string(data); |
198 | } |
199 | |
200 | static void searchedDylib(const Twine &path, bool found) { |
201 | if (config->printDylibSearch) |
202 | message(msg: "searched " + path + (found ? ", found " : ", not found" )); |
203 | if (!found) |
204 | depTracker->logFileNotFound(path); |
205 | } |
206 | |
207 | std::optional<StringRef> macho::resolveDylibPath(StringRef dylibPath) { |
208 | // TODO: if a tbd and dylib are both present, we should check to make sure |
209 | // they are consistent. |
210 | SmallString<261> tbdPath = dylibPath; |
211 | path::replace_extension(path&: tbdPath, extension: ".tbd" ); |
212 | bool tbdExists = fs::exists(Path: tbdPath); |
213 | searchedDylib(path: tbdPath, found: tbdExists); |
214 | if (tbdExists) |
215 | return saver().save(S: tbdPath.str()); |
216 | |
217 | bool dylibExists = fs::exists(Path: dylibPath); |
218 | searchedDylib(path: dylibPath, found: dylibExists); |
219 | if (dylibExists) |
220 | return saver().save(S: dylibPath); |
221 | return {}; |
222 | } |
223 | |
224 | // It's not uncommon to have multiple attempts to load a single dylib, |
225 | // especially if it's a commonly re-exported core library. |
226 | static DenseMap<CachedHashStringRef, DylibFile *> loadedDylibs; |
227 | |
228 | DylibFile *macho::loadDylib(MemoryBufferRef mbref, DylibFile *umbrella, |
229 | bool isBundleLoader, bool explicitlyLinked) { |
230 | // Frameworks can be found from different symlink paths, so resolve |
231 | // symlinks before looking up in the dylib cache. |
232 | SmallString<128> realPath; |
233 | std::error_code err = fs::real_path(path: mbref.getBufferIdentifier(), output&: realPath); |
234 | CachedHashStringRef path(!err ? uniqueSaver().save(S: StringRef(realPath)) |
235 | : mbref.getBufferIdentifier()); |
236 | DylibFile *&file = loadedDylibs[path]; |
237 | if (file) { |
238 | if (explicitlyLinked) |
239 | file->setExplicitlyLinked(); |
240 | return file; |
241 | } |
242 | |
243 | DylibFile *newFile; |
244 | file_magic magic = identify_magic(magic: mbref.getBuffer()); |
245 | if (magic == file_magic::tapi_file) { |
246 | Expected<std::unique_ptr<InterfaceFile>> result = TextAPIReader::get(InputBuffer: mbref); |
247 | if (!result) { |
248 | error(msg: "could not load TAPI file at " + mbref.getBufferIdentifier() + |
249 | ": " + toString(E: result.takeError())); |
250 | return nullptr; |
251 | } |
252 | file = |
253 | make<DylibFile>(args&: **result, args&: umbrella, args&: isBundleLoader, args&: explicitlyLinked); |
254 | |
255 | // parseReexports() can recursively call loadDylib(). That's fine since |
256 | // we wrote the DylibFile we just loaded to the loadDylib cache via the |
257 | // `file` reference. But the recursive load can grow loadDylibs, so the |
258 | // `file` reference might become invalid after parseReexports() -- so copy |
259 | // the pointer it refers to before continuing. |
260 | newFile = file; |
261 | if (newFile->exportingFile) |
262 | newFile->parseReexports(interface: **result); |
263 | } else { |
264 | assert(magic == file_magic::macho_dynamically_linked_shared_lib || |
265 | magic == file_magic::macho_dynamically_linked_shared_lib_stub || |
266 | magic == file_magic::macho_executable || |
267 | magic == file_magic::macho_bundle); |
268 | file = make<DylibFile>(args&: mbref, args&: umbrella, args&: isBundleLoader, args&: explicitlyLinked); |
269 | |
270 | // parseLoadCommands() can also recursively call loadDylib(). See comment |
271 | // in previous block for why this means we must copy `file` here. |
272 | newFile = file; |
273 | if (newFile->exportingFile) |
274 | newFile->parseLoadCommands(mb: mbref); |
275 | } |
276 | |
277 | if (explicitlyLinked && !newFile->allowableClients.empty()) { |
278 | bool allowed = |
279 | llvm::any_of(Range&: newFile->allowableClients, P: [&](StringRef allowableClient) { |
280 | // We only do a prefix match to match LD64's behaviour. |
281 | return allowableClient.starts_with(Prefix: config->clientName); |
282 | }); |
283 | |
284 | // TODO: This behaviour doesn't quite match the latest available source |
285 | // release of LD64 (ld64-951.9), which allows "parents" and "siblings" |
286 | // to link to libraries even when they're not explicitly named as |
287 | // allowable clients. However, behaviour around this seems to have |
288 | // changed in the latest release of Xcode (ld64-1115.7.3), so it's not |
289 | // clear what the correct thing to do is yet. |
290 | if (!allowed) |
291 | error(msg: "cannot link directly with '" + |
292 | sys::path::filename(path: newFile->installName) + "' because " + |
293 | config->clientName + " is not an allowed client" ); |
294 | } |
295 | return newFile; |
296 | } |
297 | |
298 | void macho::resetLoadedDylibs() { loadedDylibs.clear(); } |
299 | |
300 | std::optional<StringRef> |
301 | macho::findPathCombination(const Twine &name, |
302 | const std::vector<StringRef> &roots, |
303 | ArrayRef<StringRef> extensions) { |
304 | SmallString<261> base; |
305 | for (StringRef dir : roots) { |
306 | base = dir; |
307 | path::append(path&: base, a: name); |
308 | for (StringRef ext : extensions) { |
309 | Twine location = base + ext; |
310 | bool exists = fs::exists(Path: location); |
311 | searchedDylib(path: location, found: exists); |
312 | if (exists) |
313 | return saver().save(S: location.str()); |
314 | } |
315 | } |
316 | return {}; |
317 | } |
318 | |
319 | StringRef macho::rerootPath(StringRef path) { |
320 | if (!path::is_absolute(path, style: path::Style::posix) || path.ends_with(Suffix: ".o" )) |
321 | return path; |
322 | |
323 | if (std::optional<StringRef> rerootedPath = |
324 | findPathCombination(path, config->systemLibraryRoots)) |
325 | return *rerootedPath; |
326 | |
327 | return path; |
328 | } |
329 | |
330 | uint32_t macho::getModTime(StringRef path) { |
331 | if (config->zeroModTime) |
332 | return 0; |
333 | |
334 | fs::file_status stat; |
335 | if (!fs::status(path, result&: stat)) |
336 | if (fs::exists(status: stat)) |
337 | return toTimeT(TP: stat.getLastModificationTime()); |
338 | |
339 | warn(msg: "failed to get modification time of " + path); |
340 | return 0; |
341 | } |
342 | |
343 | void macho::printArchiveMemberLoad(StringRef reason, const InputFile *f) { |
344 | if (config->printEachFile) |
345 | message(msg: toString(file: f)); |
346 | if (config->printWhyLoad) |
347 | message(msg: reason + " forced load of " + toString(file: f)); |
348 | } |
349 | |
350 | macho::DependencyTracker::DependencyTracker(StringRef path) |
351 | : path(path), active(!path.empty()) { |
352 | if (active && fs::exists(Path: path) && !fs::can_write(Path: path)) { |
353 | warn(msg: "Ignoring dependency_info option since specified path is not " |
354 | "writeable." ); |
355 | active = false; |
356 | } |
357 | } |
358 | |
359 | void macho::DependencyTracker::write(StringRef version, |
360 | const SetVector<InputFile *> &inputs, |
361 | StringRef output) { |
362 | if (!active) |
363 | return; |
364 | |
365 | std::error_code ec; |
366 | raw_fd_ostream os(path, ec, fs::OF_None); |
367 | if (ec) { |
368 | warn(msg: "Error writing dependency info to file" ); |
369 | return; |
370 | } |
371 | |
372 | auto addDep = [&os](DepOpCode opcode, const StringRef &path) { |
373 | // XXX: Even though DepOpCode's underlying type is uint8_t, |
374 | // this cast is still needed because Clang older than 10.x has a bug, |
375 | // where it doesn't know to cast the enum to its underlying type. |
376 | // Hence `<< DepOpCode` is ambiguous to it. |
377 | os << static_cast<uint8_t>(opcode); |
378 | os << path; |
379 | os << '\0'; |
380 | }; |
381 | |
382 | addDep(DepOpCode::Version, version); |
383 | |
384 | // Sort the input by its names. |
385 | std::vector<StringRef> inputNames; |
386 | inputNames.reserve(n: inputs.size()); |
387 | for (InputFile *f : inputs) |
388 | inputNames.push_back(x: f->getName()); |
389 | llvm::sort(C&: inputNames); |
390 | |
391 | for (const StringRef &in : inputNames) |
392 | addDep(DepOpCode::Input, in); |
393 | |
394 | for (const std::string &f : notFounds) |
395 | addDep(DepOpCode::NotFound, f); |
396 | |
397 | addDep(DepOpCode::Output, output); |
398 | } |
399 | |