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