1 //===- DriverUtils.cpp ----------------------------------------------------===// 2 // 3 // The LLVM Linker 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file contains utility functions for the driver. Because there 11 // are so many small functions, we created this separate file to make 12 // Driver.cpp less cluttered. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "Driver.h" 17 #include "Error.h" 18 #include "lld/Config/Version.h" 19 #include "llvm/ADT/STLExtras.h" 20 #include "llvm/Option/Option.h" 21 #include "llvm/Support/CommandLine.h" 22 #include "llvm/Support/FileSystem.h" 23 #include "llvm/Support/Path.h" 24 #include "llvm/Support/StringSaver.h" 25 26 using namespace llvm; 27 using namespace llvm::sys; 28 29 using namespace lld; 30 using namespace lld::elf; 31 32 // Create OptTable 33 34 // Create prefix string literals used in Options.td 35 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; 36 #include "Options.inc" 37 #undef PREFIX 38 39 // Create table mapping all options defined in Options.td 40 static const opt::OptTable::Info OptInfo[] = { 41 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \ 42 { \ 43 X1, X2, X9, X10, OPT_##ID, opt::Option::KIND##Class, X8, X7, OPT_##GROUP, \ 44 OPT_##ALIAS, X6 \ 45 }, 46 #include "Options.inc" 47 #undef OPTION 48 }; 49 50 ELFOptTable::ELFOptTable() : OptTable(OptInfo) {} 51 52 // Parses a given list of options. 53 opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) { 54 // Make InputArgList from string vectors. 55 unsigned MissingIndex; 56 unsigned MissingCount; 57 58 // Expand response files. '@<filename>' is replaced by the file's contents. 59 SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size()); 60 StringSaver Saver(Alloc); 61 cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Vec); 62 63 // Parse options and then do error checking. 64 opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount); 65 if (MissingCount) 66 error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) + 67 "\", expected " + Twine(MissingCount) + 68 (MissingCount == 1 ? " argument.\n" : " arguments")); 69 70 iterator_range<opt::arg_iterator> Unknowns = Args.filtered(OPT_UNKNOWN); 71 for (auto *Arg : Unknowns) 72 warning("warning: unknown argument: " + Arg->getSpelling()); 73 if (Unknowns.begin() != Unknowns.end()) 74 error("unknown argument(s) found"); 75 return Args; 76 } 77 78 void elf::printHelp(const char *Argv0) { 79 ELFOptTable Table; 80 Table.PrintHelp(outs(), Argv0, "lld", false); 81 } 82 83 std::string elf::getVersionString() { 84 std::string Version = getLLDVersion(); 85 std::string Repo = getLLDRepositoryVersion(); 86 if (Repo.empty()) 87 return "LLD " + Version + "\n"; 88 return "LLD " + Version + " " + Repo + "\n"; 89 } 90 91 // Makes a given pathname an absolute path first, and then remove 92 // beginning /. For example, "../foo.o" is converted to "home/john/foo.o", 93 // assuming that the current directory is "/home/john/bar". 94 std::string elf::relativeToRoot(StringRef Path) { 95 SmallString<128> Abs = Path; 96 if (std::error_code EC = fs::make_absolute(Abs)) 97 fatal("make_absolute failed: " + EC.message()); 98 path::remove_dots(Abs, /*remove_dot_dot=*/true); 99 100 // This is Windows specific. root_name() returns a drive letter 101 // (e.g. "c:") or a UNC name (//net). We want to keep it as part 102 // of the result. 103 SmallString<128> Res; 104 StringRef Root = path::root_name(Abs); 105 if (Root.endswith(":")) 106 Res = Root.drop_back(); 107 else if (Root.startswith("//")) 108 Res = Root.substr(2); 109 110 path::append(Res, path::relative_path(Abs)); 111 return Res.str(); 112 } 113 114 CpioFile::CpioFile(std::unique_ptr<llvm::raw_fd_ostream> OS, StringRef S) 115 : OS(std::move(OS)), Basename(S) {} 116 117 CpioFile *CpioFile::create(StringRef OutputPath) { 118 std::string Path = (OutputPath + ".cpio").str(); 119 std::error_code EC; 120 auto OS = llvm::make_unique<raw_fd_ostream>(Path, EC, fs::F_None); 121 if (EC) { 122 error(EC, "--reproduce: failed to open " + Path); 123 return nullptr; 124 } 125 return new CpioFile(std::move(OS), path::filename(OutputPath)); 126 } 127 128 static void writeMember(raw_fd_ostream &OS, StringRef Path, StringRef Data) { 129 // The c_dev/c_ino pair should be unique according to the spec, 130 // but no one seems to care. 131 OS << "070707"; // c_magic 132 OS << "000000"; // c_dev 133 OS << "000000"; // c_ino 134 OS << "100664"; // c_mode: C_ISREG | rw-rw-r-- 135 OS << "000000"; // c_uid 136 OS << "000000"; // c_gid 137 OS << "000001"; // c_nlink 138 OS << "000000"; // c_rdev 139 OS << "00000000000"; // c_mtime 140 OS << format("%06o", Path.size() + 1); // c_namesize 141 OS << format("%011o", Data.size()); // c_filesize 142 OS << Path << '\0'; // c_name 143 OS << Data; // c_filedata 144 } 145 146 void CpioFile::append(StringRef Path, StringRef Data) { 147 if (!Seen.insert(Path).second) 148 return; 149 150 // Construct an in-archive filename so that /home/foo/bar is stored 151 // as baz/home/foo/bar where baz is the basename of the output file. 152 // (i.e. in that case we are creating baz.cpio.) 153 SmallString<128> Fullpath; 154 path::append(Fullpath, Basename, Path); 155 writeMember(*OS, Fullpath, Data); 156 157 // Print the trailer and seek back. 158 // This way we have a valid archive if we crash. 159 uint64_t Pos = OS->tell(); 160 writeMember(*OS, "TRAILER!!!", ""); 161 OS->seek(Pos); 162 } 163 164 // Quote a given string if it contains a space character. 165 static std::string quote(StringRef S) { 166 if (S.find(' ') == StringRef::npos) 167 return S; 168 return ("\"" + S + "\"").str(); 169 } 170 171 static std::string rewritePath(StringRef S) { 172 if (fs::exists(S)) 173 return relativeToRoot(S); 174 return S; 175 } 176 177 static std::string stringize(opt::Arg *Arg) { 178 std::string K = Arg->getSpelling(); 179 if (Arg->getNumValues() == 0) 180 return K; 181 std::string V = quote(Arg->getValue()); 182 if (Arg->getOption().getRenderStyle() == opt::Option::RenderJoinedStyle) 183 return K + V; 184 return K + " " + V; 185 } 186 187 // Reconstructs command line arguments so that so that you can re-run 188 // the same command with the same inputs. This is for --reproduce. 189 std::string elf::createResponseFile(const opt::InputArgList &Args) { 190 SmallString<0> Data; 191 raw_svector_ostream OS(Data); 192 193 // Copy the command line to the output while rewriting paths. 194 for (auto *Arg : Args) { 195 switch (Arg->getOption().getID()) { 196 case OPT_reproduce: 197 break; 198 case OPT_INPUT: 199 OS << quote(rewritePath(Arg->getValue())) << "\n"; 200 break; 201 case OPT_L: 202 case OPT_dynamic_list: 203 case OPT_rpath: 204 case OPT_alias_script_T: 205 case OPT_script: 206 case OPT_version_script: 207 OS << Arg->getSpelling() << " " 208 << quote(rewritePath(Arg->getValue())) << "\n"; 209 break; 210 default: 211 OS << stringize(Arg) << "\n"; 212 } 213 } 214 return Data.str(); 215 } 216 217 std::string elf::findFromSearchPaths(StringRef Path) { 218 for (StringRef Dir : Config->SearchPaths) { 219 std::string FullPath = buildSysrootedPath(Dir, Path); 220 if (fs::exists(FullPath)) 221 return FullPath; 222 } 223 return ""; 224 } 225 226 // Searches a given library from input search paths, which are filled 227 // from -L command line switches. Returns a path to an existent library file. 228 std::string elf::searchLibrary(StringRef Path) { 229 if (Path.startswith(":")) 230 return findFromSearchPaths(Path.substr(1)); 231 for (StringRef Dir : Config->SearchPaths) { 232 if (!Config->Static) { 233 std::string S = buildSysrootedPath(Dir, ("lib" + Path + ".so").str()); 234 if (fs::exists(S)) 235 return S; 236 } 237 std::string S = buildSysrootedPath(Dir, ("lib" + Path + ".a").str()); 238 if (fs::exists(S)) 239 return S; 240 } 241 return ""; 242 } 243 244 // Makes a path by concatenating Dir and File. 245 // If Dir starts with '=' the result will be preceded by Sysroot, 246 // which can be set with --sysroot command line switch. 247 std::string elf::buildSysrootedPath(StringRef Dir, StringRef File) { 248 SmallString<128> Path; 249 if (Dir.startswith("=")) 250 path::append(Path, Config->Sysroot, Dir.substr(1), File); 251 else 252 path::append(Path, Dir, File); 253 return Path.str(); 254 } 255