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 "Driver.h" 10 #include "InputFiles.h" 11 12 #include "lld/Common/Args.h" 13 #include "lld/Common/ErrorHandler.h" 14 #include "lld/Common/Memory.h" 15 #include "lld/Common/Reproduce.h" 16 #include "llvm/Option/Arg.h" 17 #include "llvm/Option/ArgList.h" 18 #include "llvm/Option/Option.h" 19 #include "llvm/Support/CommandLine.h" 20 #include "llvm/Support/Path.h" 21 #include "llvm/TextAPI/MachO/TextAPIReader.h" 22 23 using namespace llvm; 24 using namespace llvm::MachO; 25 using namespace llvm::opt; 26 using namespace llvm::sys; 27 using namespace lld; 28 using namespace lld::macho; 29 30 // Create prefix string literals used in Options.td 31 #define PREFIX(NAME, VALUE) const char *NAME[] = VALUE; 32 #include "Options.inc" 33 #undef PREFIX 34 35 // Create table mapping all options defined in Options.td 36 static const opt::OptTable::Info optInfo[] = { 37 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ 38 {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ 39 X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, 40 #include "Options.inc" 41 #undef OPTION 42 }; 43 44 MachOOptTable::MachOOptTable() : OptTable(optInfo) {} 45 46 // Set color diagnostics according to --color-diagnostics={auto,always,never} 47 // or --no-color-diagnostics flags. 48 static void handleColorDiagnostics(opt::InputArgList &args) { 49 auto *arg = args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, 50 OPT_no_color_diagnostics); 51 if (!arg) 52 return; 53 if (arg->getOption().getID() == OPT_color_diagnostics) { 54 lld::errs().enable_colors(true); 55 } else if (arg->getOption().getID() == OPT_no_color_diagnostics) { 56 lld::errs().enable_colors(false); 57 } else { 58 StringRef s = arg->getValue(); 59 if (s == "always") 60 lld::errs().enable_colors(true); 61 else if (s == "never") 62 lld::errs().enable_colors(false); 63 else if (s != "auto") 64 error("unknown option: --color-diagnostics=" + s); 65 } 66 } 67 68 opt::InputArgList MachOOptTable::parse(ArrayRef<const char *> argv) { 69 // Make InputArgList from string vectors. 70 unsigned missingIndex; 71 unsigned missingCount; 72 SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size()); 73 74 // Expand response files (arguments in the form of @<filename>) 75 // and then parse the argument again. 76 cl::ExpandResponseFiles(saver, cl::TokenizeGNUCommandLine, vec); 77 opt::InputArgList args = ParseArgs(vec, missingIndex, missingCount); 78 79 // Handle -fatal_warnings early since it converts missing argument warnings 80 // to errors. 81 errorHandler().fatalWarnings = args.hasArg(OPT_fatal_warnings); 82 83 if (missingCount) 84 error(Twine(args.getArgString(missingIndex)) + ": missing argument"); 85 86 handleColorDiagnostics(args); 87 88 for (opt::Arg *arg : args.filtered(OPT_UNKNOWN)) { 89 std::string nearest; 90 if (findNearest(arg->getAsString(args), nearest) > 1) 91 error("unknown argument '" + arg->getAsString(args) + "'"); 92 else 93 error("unknown argument '" + arg->getAsString(args) + 94 "', did you mean '" + nearest + "'"); 95 } 96 return args; 97 } 98 99 void MachOOptTable::printHelp(const char *argv0, bool showHidden) const { 100 PrintHelp(lld::outs(), (std::string(argv0) + " [options] file...").c_str(), 101 "LLVM Linker", showHidden); 102 lld::outs() << "\n"; 103 } 104 105 static std::string rewritePath(StringRef s) { 106 if (fs::exists(s)) 107 return relativeToRoot(s); 108 return std::string(s); 109 } 110 111 // Reconstructs command line arguments so that so that you can re-run 112 // the same command with the same inputs. This is for --reproduce. 113 std::string macho::createResponseFile(const opt::InputArgList &args) { 114 SmallString<0> data; 115 raw_svector_ostream os(data); 116 117 // Copy the command line to the output while rewriting paths. 118 for (auto *arg : args) { 119 switch (arg->getOption().getID()) { 120 case OPT_reproduce: 121 break; 122 case OPT_INPUT: 123 os << quote(rewritePath(arg->getValue())) << "\n"; 124 break; 125 case OPT_o: 126 os << "-o " << quote(path::filename(arg->getValue())) << "\n"; 127 break; 128 case OPT_filelist: 129 if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue())) 130 for (StringRef path : args::getLines(*buffer)) 131 os << quote(rewritePath(path)) << "\n"; 132 break; 133 case OPT_force_load: 134 case OPT_rpath: 135 case OPT_syslibroot: 136 case OPT_F: 137 case OPT_L: 138 case OPT_order_file: 139 os << arg->getSpelling() << " " << quote(rewritePath(arg->getValue())) 140 << "\n"; 141 break; 142 case OPT_sectcreate: 143 os << arg->getSpelling() << " " << quote(arg->getValue(0)) << " " 144 << quote(arg->getValue(1)) << " " 145 << quote(rewritePath(arg->getValue(2))) << "\n"; 146 break; 147 default: 148 os << toString(*arg) << "\n"; 149 } 150 } 151 return std::string(data.str()); 152 } 153 154 Optional<std::string> macho::resolveDylibPath(StringRef path) { 155 // TODO: if a tbd and dylib are both present, we should check to make sure 156 // they are consistent. 157 if (fs::exists(path)) 158 return std::string(path); 159 160 SmallString<261> location = path; 161 path::replace_extension(location, ".tbd"); 162 if (fs::exists(location)) 163 return std::string(location); 164 165 return {}; 166 } 167 168 Optional<DylibFile *> macho::makeDylibFromTAPI(MemoryBufferRef mbref, 169 DylibFile *umbrella) { 170 Expected<std::unique_ptr<InterfaceFile>> result = TextAPIReader::get(mbref); 171 if (!result) { 172 error("could not load TAPI file at " + mbref.getBufferIdentifier() + ": " + 173 toString(result.takeError())); 174 return {}; 175 } 176 return make<DylibFile>(**result, umbrella); 177 } 178