xref: /freebsd-src/contrib/llvm-project/lld/MachO/DriverUtils.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
1*e8d8bef9SDimitry Andric //===- DriverUtils.cpp ----------------------------------------------------===//
2*e8d8bef9SDimitry Andric //
3*e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*e8d8bef9SDimitry Andric //
7*e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8*e8d8bef9SDimitry Andric 
9*e8d8bef9SDimitry Andric #include "Driver.h"
10*e8d8bef9SDimitry Andric #include "Config.h"
11*e8d8bef9SDimitry Andric #include "InputFiles.h"
12*e8d8bef9SDimitry Andric 
13*e8d8bef9SDimitry Andric #include "lld/Common/Args.h"
14*e8d8bef9SDimitry Andric #include "lld/Common/ErrorHandler.h"
15*e8d8bef9SDimitry Andric #include "lld/Common/Memory.h"
16*e8d8bef9SDimitry Andric #include "lld/Common/Reproduce.h"
17*e8d8bef9SDimitry Andric #include "llvm/ADT/CachedHashString.h"
18*e8d8bef9SDimitry Andric #include "llvm/ADT/DenseMap.h"
19*e8d8bef9SDimitry Andric #include "llvm/Option/Arg.h"
20*e8d8bef9SDimitry Andric #include "llvm/Option/ArgList.h"
21*e8d8bef9SDimitry Andric #include "llvm/Option/Option.h"
22*e8d8bef9SDimitry Andric #include "llvm/Support/CommandLine.h"
23*e8d8bef9SDimitry Andric #include "llvm/Support/Path.h"
24*e8d8bef9SDimitry Andric #include "llvm/TextAPI/MachO/TextAPIReader.h"
25*e8d8bef9SDimitry Andric 
26*e8d8bef9SDimitry Andric using namespace llvm;
27*e8d8bef9SDimitry Andric using namespace llvm::MachO;
28*e8d8bef9SDimitry Andric using namespace llvm::opt;
29*e8d8bef9SDimitry Andric using namespace llvm::sys;
30*e8d8bef9SDimitry Andric using namespace lld;
31*e8d8bef9SDimitry Andric using namespace lld::macho;
32*e8d8bef9SDimitry Andric 
33*e8d8bef9SDimitry Andric // Create prefix string literals used in Options.td
34*e8d8bef9SDimitry Andric #define PREFIX(NAME, VALUE) const char *NAME[] = VALUE;
35*e8d8bef9SDimitry Andric #include "Options.inc"
36*e8d8bef9SDimitry Andric #undef PREFIX
37*e8d8bef9SDimitry Andric 
38*e8d8bef9SDimitry Andric // Create table mapping all options defined in Options.td
39*e8d8bef9SDimitry Andric static const opt::OptTable::Info optInfo[] = {
40*e8d8bef9SDimitry Andric #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12)      \
41*e8d8bef9SDimitry Andric   {X1, X2, X10,         X11,         OPT_##ID, opt::Option::KIND##Class,       \
42*e8d8bef9SDimitry Andric    X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
43*e8d8bef9SDimitry Andric #include "Options.inc"
44*e8d8bef9SDimitry Andric #undef OPTION
45*e8d8bef9SDimitry Andric };
46*e8d8bef9SDimitry Andric 
47*e8d8bef9SDimitry Andric MachOOptTable::MachOOptTable() : OptTable(optInfo) {}
48*e8d8bef9SDimitry Andric 
49*e8d8bef9SDimitry Andric // Set color diagnostics according to --color-diagnostics={auto,always,never}
50*e8d8bef9SDimitry Andric // or --no-color-diagnostics flags.
51*e8d8bef9SDimitry Andric static void handleColorDiagnostics(opt::InputArgList &args) {
52*e8d8bef9SDimitry Andric   auto *arg = args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
53*e8d8bef9SDimitry Andric                               OPT_no_color_diagnostics);
54*e8d8bef9SDimitry Andric   if (!arg)
55*e8d8bef9SDimitry Andric     return;
56*e8d8bef9SDimitry Andric   if (arg->getOption().getID() == OPT_color_diagnostics) {
57*e8d8bef9SDimitry Andric     lld::errs().enable_colors(true);
58*e8d8bef9SDimitry Andric   } else if (arg->getOption().getID() == OPT_no_color_diagnostics) {
59*e8d8bef9SDimitry Andric     lld::errs().enable_colors(false);
60*e8d8bef9SDimitry Andric   } else {
61*e8d8bef9SDimitry Andric     StringRef s = arg->getValue();
62*e8d8bef9SDimitry Andric     if (s == "always")
63*e8d8bef9SDimitry Andric       lld::errs().enable_colors(true);
64*e8d8bef9SDimitry Andric     else if (s == "never")
65*e8d8bef9SDimitry Andric       lld::errs().enable_colors(false);
66*e8d8bef9SDimitry Andric     else if (s != "auto")
67*e8d8bef9SDimitry Andric       error("unknown option: --color-diagnostics=" + s);
68*e8d8bef9SDimitry Andric   }
69*e8d8bef9SDimitry Andric }
70*e8d8bef9SDimitry Andric 
71*e8d8bef9SDimitry Andric opt::InputArgList MachOOptTable::parse(ArrayRef<const char *> argv) {
72*e8d8bef9SDimitry Andric   // Make InputArgList from string vectors.
73*e8d8bef9SDimitry Andric   unsigned missingIndex;
74*e8d8bef9SDimitry Andric   unsigned missingCount;
75*e8d8bef9SDimitry Andric   SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());
76*e8d8bef9SDimitry Andric 
77*e8d8bef9SDimitry Andric   // Expand response files (arguments in the form of @<filename>)
78*e8d8bef9SDimitry Andric   // and then parse the argument again.
79*e8d8bef9SDimitry Andric   cl::ExpandResponseFiles(saver, cl::TokenizeGNUCommandLine, vec);
80*e8d8bef9SDimitry Andric   opt::InputArgList args = ParseArgs(vec, missingIndex, missingCount);
81*e8d8bef9SDimitry Andric 
82*e8d8bef9SDimitry Andric   // Handle -fatal_warnings early since it converts missing argument warnings
83*e8d8bef9SDimitry Andric   // to errors.
84*e8d8bef9SDimitry Andric   errorHandler().fatalWarnings = args.hasArg(OPT_fatal_warnings);
85*e8d8bef9SDimitry Andric 
86*e8d8bef9SDimitry Andric   if (missingCount)
87*e8d8bef9SDimitry Andric     error(Twine(args.getArgString(missingIndex)) + ": missing argument");
88*e8d8bef9SDimitry Andric 
89*e8d8bef9SDimitry Andric   handleColorDiagnostics(args);
90*e8d8bef9SDimitry Andric 
91*e8d8bef9SDimitry Andric   for (opt::Arg *arg : args.filtered(OPT_UNKNOWN)) {
92*e8d8bef9SDimitry Andric     std::string nearest;
93*e8d8bef9SDimitry Andric     if (findNearest(arg->getAsString(args), nearest) > 1)
94*e8d8bef9SDimitry Andric       error("unknown argument '" + arg->getAsString(args) + "'");
95*e8d8bef9SDimitry Andric     else
96*e8d8bef9SDimitry Andric       error("unknown argument '" + arg->getAsString(args) +
97*e8d8bef9SDimitry Andric             "', did you mean '" + nearest + "'");
98*e8d8bef9SDimitry Andric   }
99*e8d8bef9SDimitry Andric   return args;
100*e8d8bef9SDimitry Andric }
101*e8d8bef9SDimitry Andric 
102*e8d8bef9SDimitry Andric void MachOOptTable::printHelp(const char *argv0, bool showHidden) const {
103*e8d8bef9SDimitry Andric   PrintHelp(lld::outs(), (std::string(argv0) + " [options] file...").c_str(),
104*e8d8bef9SDimitry Andric             "LLVM Linker", showHidden);
105*e8d8bef9SDimitry Andric   lld::outs() << "\n";
106*e8d8bef9SDimitry Andric }
107*e8d8bef9SDimitry Andric 
108*e8d8bef9SDimitry Andric static std::string rewritePath(StringRef s) {
109*e8d8bef9SDimitry Andric   if (fs::exists(s))
110*e8d8bef9SDimitry Andric     return relativeToRoot(s);
111*e8d8bef9SDimitry Andric   return std::string(s);
112*e8d8bef9SDimitry Andric }
113*e8d8bef9SDimitry Andric 
114*e8d8bef9SDimitry Andric // Reconstructs command line arguments so that so that you can re-run
115*e8d8bef9SDimitry Andric // the same command with the same inputs. This is for --reproduce.
116*e8d8bef9SDimitry Andric std::string macho::createResponseFile(const opt::InputArgList &args) {
117*e8d8bef9SDimitry Andric   SmallString<0> data;
118*e8d8bef9SDimitry Andric   raw_svector_ostream os(data);
119*e8d8bef9SDimitry Andric 
120*e8d8bef9SDimitry Andric   // Copy the command line to the output while rewriting paths.
121*e8d8bef9SDimitry Andric   for (auto *arg : args) {
122*e8d8bef9SDimitry Andric     switch (arg->getOption().getID()) {
123*e8d8bef9SDimitry Andric     case OPT_reproduce:
124*e8d8bef9SDimitry Andric       break;
125*e8d8bef9SDimitry Andric     case OPT_INPUT:
126*e8d8bef9SDimitry Andric       os << quote(rewritePath(arg->getValue())) << "\n";
127*e8d8bef9SDimitry Andric       break;
128*e8d8bef9SDimitry Andric     case OPT_o:
129*e8d8bef9SDimitry Andric       os << "-o " << quote(path::filename(arg->getValue())) << "\n";
130*e8d8bef9SDimitry Andric       break;
131*e8d8bef9SDimitry Andric     case OPT_filelist:
132*e8d8bef9SDimitry Andric       if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue()))
133*e8d8bef9SDimitry Andric         for (StringRef path : args::getLines(*buffer))
134*e8d8bef9SDimitry Andric           os << quote(rewritePath(path)) << "\n";
135*e8d8bef9SDimitry Andric       break;
136*e8d8bef9SDimitry Andric     case OPT_force_load:
137*e8d8bef9SDimitry Andric     case OPT_rpath:
138*e8d8bef9SDimitry Andric     case OPT_syslibroot:
139*e8d8bef9SDimitry Andric     case OPT_F:
140*e8d8bef9SDimitry Andric     case OPT_L:
141*e8d8bef9SDimitry Andric     case OPT_order_file:
142*e8d8bef9SDimitry Andric       os << arg->getSpelling() << " " << quote(rewritePath(arg->getValue()))
143*e8d8bef9SDimitry Andric          << "\n";
144*e8d8bef9SDimitry Andric       break;
145*e8d8bef9SDimitry Andric     case OPT_sectcreate:
146*e8d8bef9SDimitry Andric       os << arg->getSpelling() << " " << quote(arg->getValue(0)) << " "
147*e8d8bef9SDimitry Andric          << quote(arg->getValue(1)) << " "
148*e8d8bef9SDimitry Andric          << quote(rewritePath(arg->getValue(2))) << "\n";
149*e8d8bef9SDimitry Andric       break;
150*e8d8bef9SDimitry Andric     default:
151*e8d8bef9SDimitry Andric       os << toString(*arg) << "\n";
152*e8d8bef9SDimitry Andric     }
153*e8d8bef9SDimitry Andric   }
154*e8d8bef9SDimitry Andric   return std::string(data.str());
155*e8d8bef9SDimitry Andric }
156*e8d8bef9SDimitry Andric 
157*e8d8bef9SDimitry Andric Optional<std::string> macho::resolveDylibPath(StringRef path) {
158*e8d8bef9SDimitry Andric   // TODO: if a tbd and dylib are both present, we should check to make sure
159*e8d8bef9SDimitry Andric   // they are consistent.
160*e8d8bef9SDimitry Andric   if (fs::exists(path))
161*e8d8bef9SDimitry Andric     return std::string(path);
162*e8d8bef9SDimitry Andric 
163*e8d8bef9SDimitry Andric   SmallString<261> location = path;
164*e8d8bef9SDimitry Andric   path::replace_extension(location, ".tbd");
165*e8d8bef9SDimitry Andric   if (fs::exists(location))
166*e8d8bef9SDimitry Andric     return std::string(location);
167*e8d8bef9SDimitry Andric 
168*e8d8bef9SDimitry Andric   return {};
169*e8d8bef9SDimitry Andric }
170*e8d8bef9SDimitry Andric 
171*e8d8bef9SDimitry Andric // It's not uncommon to have multiple attempts to load a single dylib,
172*e8d8bef9SDimitry Andric // especially if it's a commonly re-exported core library.
173*e8d8bef9SDimitry Andric static DenseMap<CachedHashStringRef, DylibFile *> loadedDylibs;
174*e8d8bef9SDimitry Andric 
175*e8d8bef9SDimitry Andric Optional<DylibFile *> macho::loadDylib(MemoryBufferRef mbref,
176*e8d8bef9SDimitry Andric                                        DylibFile *umbrella) {
177*e8d8bef9SDimitry Andric   StringRef path = mbref.getBufferIdentifier();
178*e8d8bef9SDimitry Andric   DylibFile *&file = loadedDylibs[CachedHashStringRef(path)];
179*e8d8bef9SDimitry Andric   if (file)
180*e8d8bef9SDimitry Andric     return file;
181*e8d8bef9SDimitry Andric 
182*e8d8bef9SDimitry Andric   file_magic magic = identify_magic(mbref.getBuffer());
183*e8d8bef9SDimitry Andric   if (magic == file_magic::tapi_file) {
184*e8d8bef9SDimitry Andric     Expected<std::unique_ptr<InterfaceFile>> result = TextAPIReader::get(mbref);
185*e8d8bef9SDimitry Andric     if (!result) {
186*e8d8bef9SDimitry Andric       error("could not load TAPI file at " + mbref.getBufferIdentifier() +
187*e8d8bef9SDimitry Andric             ": " + toString(result.takeError()));
188*e8d8bef9SDimitry Andric       return {};
189*e8d8bef9SDimitry Andric     }
190*e8d8bef9SDimitry Andric     file = make<DylibFile>(**result, umbrella);
191*e8d8bef9SDimitry Andric   } else {
192*e8d8bef9SDimitry Andric     assert(magic == file_magic::macho_dynamically_linked_shared_lib ||
193*e8d8bef9SDimitry Andric            magic == file_magic::macho_dynamically_linked_shared_lib_stub);
194*e8d8bef9SDimitry Andric     file = make<DylibFile>(mbref, umbrella);
195*e8d8bef9SDimitry Andric   }
196*e8d8bef9SDimitry Andric   return file;
197*e8d8bef9SDimitry Andric }
198*e8d8bef9SDimitry Andric 
199*e8d8bef9SDimitry Andric uint32_t macho::getModTime(StringRef path) {
200*e8d8bef9SDimitry Andric   fs::file_status stat;
201*e8d8bef9SDimitry Andric   if (!fs::status(path, stat))
202*e8d8bef9SDimitry Andric     if (fs::exists(stat))
203*e8d8bef9SDimitry Andric       return toTimeT(stat.getLastModificationTime());
204*e8d8bef9SDimitry Andric 
205*e8d8bef9SDimitry Andric   warn("failed to get modification time of " + path);
206*e8d8bef9SDimitry Andric   return 0;
207*e8d8bef9SDimitry Andric }
208*e8d8bef9SDimitry Andric 
209*e8d8bef9SDimitry Andric void macho::printArchiveMemberLoad(StringRef reason, const InputFile *f) {
210*e8d8bef9SDimitry Andric   if (config->printEachFile)
211*e8d8bef9SDimitry Andric     message(toString(f));
212*e8d8bef9SDimitry Andric   if (config->printWhyLoad)
213*e8d8bef9SDimitry Andric     message(reason + " forced load of " + toString(f));
214*e8d8bef9SDimitry Andric }
215