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