Mercurial > hg > CbC > CbC_llvm
comparison lld/MachO/DriverUtils.cpp @ 207:2e18cbf3894f
LLVM12
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 08 Jun 2021 06:07:14 +0900 |
parents | |
children | 5f17cb93ff66 |
comparison
equal
deleted
inserted
replaced
173:0572611fdcc8 | 207:2e18cbf3894f |
---|---|
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 #include "ObjC.h" | |
13 #include "Target.h" | |
14 | |
15 #include "lld/Common/Args.h" | |
16 #include "lld/Common/ErrorHandler.h" | |
17 #include "lld/Common/Memory.h" | |
18 #include "lld/Common/Reproduce.h" | |
19 #include "llvm/ADT/CachedHashString.h" | |
20 #include "llvm/ADT/DenseMap.h" | |
21 #include "llvm/Bitcode/BitcodeReader.h" | |
22 #include "llvm/LTO/LTO.h" | |
23 #include "llvm/Option/Arg.h" | |
24 #include "llvm/Option/ArgList.h" | |
25 #include "llvm/Option/Option.h" | |
26 #include "llvm/Support/CommandLine.h" | |
27 #include "llvm/Support/FileSystem.h" | |
28 #include "llvm/Support/Path.h" | |
29 #include "llvm/TextAPI/InterfaceFile.h" | |
30 #include "llvm/TextAPI/TextAPIReader.h" | |
31 | |
32 using namespace llvm; | |
33 using namespace llvm::MachO; | |
34 using namespace llvm::opt; | |
35 using namespace llvm::sys; | |
36 using namespace lld; | |
37 using namespace lld::macho; | |
38 | |
39 // Create prefix string literals used in Options.td | |
40 #define PREFIX(NAME, VALUE) const char *NAME[] = VALUE; | |
41 #include "Options.inc" | |
42 #undef PREFIX | |
43 | |
44 // Create table mapping all options defined in Options.td | |
45 static const OptTable::Info optInfo[] = { | |
46 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ | |
47 {X1, X2, X10, X11, OPT_##ID, Option::KIND##Class, \ | |
48 X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, | |
49 #include "Options.inc" | |
50 #undef OPTION | |
51 }; | |
52 | |
53 MachOOptTable::MachOOptTable() : OptTable(optInfo) {} | |
54 | |
55 // Set color diagnostics according to --color-diagnostics={auto,always,never} | |
56 // or --no-color-diagnostics flags. | |
57 static void handleColorDiagnostics(InputArgList &args) { | |
58 const Arg *arg = | |
59 args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, | |
60 OPT_no_color_diagnostics); | |
61 if (!arg) | |
62 return; | |
63 if (arg->getOption().getID() == OPT_color_diagnostics) { | |
64 lld::errs().enable_colors(true); | |
65 } else if (arg->getOption().getID() == OPT_no_color_diagnostics) { | |
66 lld::errs().enable_colors(false); | |
67 } else { | |
68 StringRef s = arg->getValue(); | |
69 if (s == "always") | |
70 lld::errs().enable_colors(true); | |
71 else if (s == "never") | |
72 lld::errs().enable_colors(false); | |
73 else if (s != "auto") | |
74 error("unknown option: --color-diagnostics=" + s); | |
75 } | |
76 } | |
77 | |
78 InputArgList MachOOptTable::parse(ArrayRef<const char *> argv) { | |
79 // Make InputArgList from string vectors. | |
80 unsigned missingIndex; | |
81 unsigned missingCount; | |
82 SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size()); | |
83 | |
84 // Expand response files (arguments in the form of @<filename>) | |
85 // and then parse the argument again. | |
86 cl::ExpandResponseFiles(saver, cl::TokenizeGNUCommandLine, vec); | |
87 InputArgList args = ParseArgs(vec, missingIndex, missingCount); | |
88 | |
89 // Handle -fatal_warnings early since it converts missing argument warnings | |
90 // to errors. | |
91 errorHandler().fatalWarnings = args.hasArg(OPT_fatal_warnings); | |
92 | |
93 if (missingCount) | |
94 error(Twine(args.getArgString(missingIndex)) + ": missing argument"); | |
95 | |
96 handleColorDiagnostics(args); | |
97 | |
98 for (const Arg *arg : args.filtered(OPT_UNKNOWN)) { | |
99 std::string nearest; | |
100 if (findNearest(arg->getAsString(args), nearest) > 1) | |
101 error("unknown argument '" + arg->getAsString(args) + "'"); | |
102 else | |
103 error("unknown argument '" + arg->getAsString(args) + | |
104 "', did you mean '" + nearest + "'"); | |
105 } | |
106 return args; | |
107 } | |
108 | |
109 void MachOOptTable::printHelp(const char *argv0, bool showHidden) const { | |
110 PrintHelp(lld::outs(), (std::string(argv0) + " [options] file...").c_str(), | |
111 "LLVM Linker", showHidden); | |
112 lld::outs() << "\n"; | |
113 } | |
114 | |
115 static std::string rewritePath(StringRef s) { | |
116 if (fs::exists(s)) | |
117 return relativeToRoot(s); | |
118 return std::string(s); | |
119 } | |
120 | |
121 static std::string rewriteInputPath(StringRef s) { | |
122 // Don't bother rewriting "absolute" paths that are actually under the | |
123 // syslibroot; simply rewriting the syslibroot is sufficient. | |
124 if (rerootPath(s) == s && fs::exists(s)) | |
125 return relativeToRoot(s); | |
126 return std::string(s); | |
127 } | |
128 | |
129 // Reconstructs command line arguments so that so that you can re-run | |
130 // the same command with the same inputs. This is for --reproduce. | |
131 std::string macho::createResponseFile(const InputArgList &args) { | |
132 SmallString<0> data; | |
133 raw_svector_ostream os(data); | |
134 | |
135 // Copy the command line to the output while rewriting paths. | |
136 for (const Arg *arg : args) { | |
137 switch (arg->getOption().getID()) { | |
138 case OPT_reproduce: | |
139 break; | |
140 case OPT_INPUT: | |
141 os << quote(rewriteInputPath(arg->getValue())) << "\n"; | |
142 break; | |
143 case OPT_o: | |
144 os << "-o " << quote(path::filename(arg->getValue())) << "\n"; | |
145 break; | |
146 case OPT_filelist: | |
147 if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue())) | |
148 for (StringRef path : args::getLines(*buffer)) | |
149 os << quote(rewriteInputPath(path)) << "\n"; | |
150 break; | |
151 case OPT_force_load: | |
152 case OPT_weak_library: | |
153 os << arg->getSpelling() << " " | |
154 << quote(rewriteInputPath(arg->getValue())) << "\n"; | |
155 break; | |
156 case OPT_F: | |
157 case OPT_L: | |
158 case OPT_bundle_loader: | |
159 case OPT_exported_symbols_list: | |
160 case OPT_order_file: | |
161 case OPT_rpath: | |
162 case OPT_syslibroot: | |
163 case OPT_unexported_symbols_list: | |
164 os << arg->getSpelling() << " " << quote(rewritePath(arg->getValue())) | |
165 << "\n"; | |
166 break; | |
167 case OPT_sectcreate: | |
168 os << arg->getSpelling() << " " << quote(arg->getValue(0)) << " " | |
169 << quote(arg->getValue(1)) << " " | |
170 << quote(rewritePath(arg->getValue(2))) << "\n"; | |
171 break; | |
172 default: | |
173 os << toString(*arg) << "\n"; | |
174 } | |
175 } | |
176 return std::string(data.str()); | |
177 } | |
178 | |
179 Optional<std::string> macho::resolveDylibPath(StringRef path) { | |
180 // TODO: if a tbd and dylib are both present, we should check to make sure | |
181 // they are consistent. | |
182 if (fs::exists(path)) | |
183 return std::string(path); | |
184 else | |
185 depTracker->logFileNotFound(path); | |
186 | |
187 SmallString<261> location = path; | |
188 path::replace_extension(location, ".tbd"); | |
189 if (fs::exists(location)) | |
190 return std::string(location); | |
191 else | |
192 depTracker->logFileNotFound(location); | |
193 return {}; | |
194 } | |
195 | |
196 // It's not uncommon to have multiple attempts to load a single dylib, | |
197 // especially if it's a commonly re-exported core library. | |
198 static DenseMap<CachedHashStringRef, DylibFile *> loadedDylibs; | |
199 | |
200 DylibFile *macho::loadDylib(MemoryBufferRef mbref, DylibFile *umbrella, | |
201 bool isBundleLoader) { | |
202 CachedHashStringRef path(mbref.getBufferIdentifier()); | |
203 DylibFile *&file = loadedDylibs[path]; | |
204 if (file) | |
205 return file; | |
206 | |
207 DylibFile *newFile; | |
208 file_magic magic = identify_magic(mbref.getBuffer()); | |
209 if (magic == file_magic::tapi_file) { | |
210 Expected<std::unique_ptr<InterfaceFile>> result = TextAPIReader::get(mbref); | |
211 if (!result) { | |
212 error("could not load TAPI file at " + mbref.getBufferIdentifier() + | |
213 ": " + toString(result.takeError())); | |
214 return nullptr; | |
215 } | |
216 file = make<DylibFile>(**result, umbrella, isBundleLoader); | |
217 | |
218 // parseReexports() can recursively call loadDylib(). That's fine since | |
219 // we wrote the DylibFile we just loaded to the loadDylib cache via the | |
220 // `file` reference. But the recursive load can grow loadDylibs, so the | |
221 // `file` reference might become invalid after parseReexports() -- so copy | |
222 // the pointer it refers to before continuing. | |
223 newFile = file; | |
224 if (newFile->exportingFile) | |
225 newFile->parseReexports(**result); | |
226 } else { | |
227 assert(magic == file_magic::macho_dynamically_linked_shared_lib || | |
228 magic == file_magic::macho_dynamically_linked_shared_lib_stub || | |
229 magic == file_magic::macho_executable || | |
230 magic == file_magic::macho_bundle); | |
231 file = make<DylibFile>(mbref, umbrella, isBundleLoader); | |
232 | |
233 // parseLoadCommands() can also recursively call loadDylib(). See comment | |
234 // in previous block for why this means we must copy `file` here. | |
235 newFile = file; | |
236 if (newFile->exportingFile) | |
237 newFile->parseLoadCommands(mbref); | |
238 } | |
239 return newFile; | |
240 } | |
241 | |
242 Optional<StringRef> | |
243 macho::findPathCombination(const Twine &name, | |
244 const std::vector<StringRef> &roots, | |
245 ArrayRef<StringRef> extensions) { | |
246 SmallString<261> base; | |
247 for (StringRef dir : roots) { | |
248 base = dir; | |
249 path::append(base, name); | |
250 for (StringRef ext : extensions) { | |
251 Twine location = base + ext; | |
252 if (fs::exists(location)) | |
253 return saver.save(location.str()); | |
254 else | |
255 depTracker->logFileNotFound(location); | |
256 } | |
257 } | |
258 return {}; | |
259 } | |
260 | |
261 StringRef macho::rerootPath(StringRef path) { | |
262 if (!path::is_absolute(path, path::Style::posix) || path.endswith(".o")) | |
263 return path; | |
264 | |
265 if (Optional<StringRef> rerootedPath = | |
266 findPathCombination(path, config->systemLibraryRoots)) | |
267 return *rerootedPath; | |
268 | |
269 return path; | |
270 } | |
271 | |
272 Optional<InputFile *> macho::loadArchiveMember(MemoryBufferRef mb, | |
273 uint32_t modTime, | |
274 StringRef archiveName, | |
275 bool objCOnly) { | |
276 if (config->zeroModTime) | |
277 modTime = 0; | |
278 | |
279 switch (identify_magic(mb.getBuffer())) { | |
280 case file_magic::macho_object: | |
281 if (!objCOnly || hasObjCSection(mb)) | |
282 return make<ObjFile>(mb, modTime, archiveName); | |
283 return None; | |
284 case file_magic::bitcode: | |
285 if (!objCOnly || check(isBitcodeContainingObjCCategory(mb))) | |
286 return make<BitcodeFile>(mb); | |
287 return None; | |
288 default: | |
289 error(archiveName + ": archive member " + mb.getBufferIdentifier() + | |
290 " has unhandled file type"); | |
291 return None; | |
292 } | |
293 } | |
294 | |
295 uint32_t macho::getModTime(StringRef path) { | |
296 if (config->zeroModTime) | |
297 return 0; | |
298 | |
299 fs::file_status stat; | |
300 if (!fs::status(path, stat)) | |
301 if (fs::exists(stat)) | |
302 return toTimeT(stat.getLastModificationTime()); | |
303 | |
304 warn("failed to get modification time of " + path); | |
305 return 0; | |
306 } | |
307 | |
308 void macho::printArchiveMemberLoad(StringRef reason, const InputFile *f) { | |
309 if (config->printEachFile) | |
310 message(toString(f)); | |
311 if (config->printWhyLoad) | |
312 message(reason + " forced load of " + toString(f)); | |
313 } | |
314 | |
315 macho::DependencyTracker::DependencyTracker(StringRef path) | |
316 : path(path), active(!path.empty()) { | |
317 if (active && fs::exists(path) && !fs::can_write(path)) { | |
318 warn("Ignoring dependency_info option since specified path is not " | |
319 "writeable."); | |
320 active = false; | |
321 } | |
322 } | |
323 | |
324 void macho::DependencyTracker::write(llvm::StringRef version, | |
325 const llvm::SetVector<InputFile *> &inputs, | |
326 llvm::StringRef output) { | |
327 if (!active) | |
328 return; | |
329 | |
330 std::error_code ec; | |
331 llvm::raw_fd_ostream os(path, ec, llvm::sys::fs::OF_None); | |
332 if (ec) { | |
333 warn("Error writing dependency info to file"); | |
334 return; | |
335 } | |
336 | |
337 auto addDep = [&os](DepOpCode opcode, const StringRef &path) { | |
338 // XXX: Even though DepOpCode's underlying type is uint8_t, | |
339 // this cast is still needed because Clang older than 10.x has a bug, | |
340 // where it doesn't know to cast the enum to its underlying type. | |
341 // Hence `<< DepOpCode` is ambiguous to it. | |
342 os << static_cast<uint8_t>(opcode); | |
343 os << path; | |
344 os << '\0'; | |
345 }; | |
346 | |
347 addDep(DepOpCode::Version, version); | |
348 | |
349 // Sort the input by its names. | |
350 std::vector<StringRef> inputNames; | |
351 inputNames.reserve(inputs.size()); | |
352 for (InputFile *f : inputs) | |
353 inputNames.push_back(f->getName()); | |
354 llvm::sort(inputNames); | |
355 | |
356 for (const StringRef &in : inputNames) | |
357 addDep(DepOpCode::Input, in); | |
358 | |
359 for (const std::string &f : notFounds) | |
360 addDep(DepOpCode::NotFound, f); | |
361 | |
362 addDep(DepOpCode::Output, output); | |
363 } |