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