blob: 179b8b79caf1493a73bed08e633652fcad96004f [file] [log] [blame]
Michael J. Spencer84487f12015-07-24 21:03:07 +00001//===- 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"
Rafael Espindola192e1fa2015-08-06 15:08:23 +000017#include "Error.h"
Rui Ueyama1abcf372016-02-28 03:18:07 +000018#include "lld/Config/Version.h"
Michael J. Spencer84487f12015-07-24 21:03:07 +000019#include "llvm/ADT/STLExtras.h"
Rui Ueyamaeeb22f82015-09-25 15:37:33 +000020#include "llvm/Support/CommandLine.h"
Rui Ueyama4b02ca92015-10-11 03:28:39 +000021#include "llvm/Support/FileSystem.h"
22#include "llvm/Support/Path.h"
Rui Ueyamac6e1b972015-10-11 18:19:01 +000023#include "llvm/Support/StringSaver.h"
Michael J. Spencer84487f12015-07-24 21:03:07 +000024
25using namespace llvm;
Rui Ueyamacf0dd1e2016-04-26 20:41:32 +000026using namespace llvm::sys;
Michael J. Spencer84487f12015-07-24 21:03:07 +000027
28using namespace lld;
Rafael Espindolae0df00b2016-02-28 00:25:54 +000029using namespace lld::elf;
Michael J. Spencer84487f12015-07-24 21:03:07 +000030
31// Create OptTable
32
33// Create prefix string literals used in Options.td
34#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
35#include "Options.inc"
36#undef PREFIX
37
38// Create table mapping all options defined in Options.td
Rui Ueyama8fe7ce52016-04-02 19:15:26 +000039static const opt::OptTable::Info OptInfo[] = {
Michael J. Spencer84487f12015-07-24 21:03:07 +000040#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \
41 { \
42 X1, X2, X9, X10, OPT_##ID, opt::Option::KIND##Class, X8, X7, OPT_##GROUP, \
43 OPT_##ALIAS, X6 \
Rui Ueyama8fe7ce52016-04-02 19:15:26 +000044 },
Michael J. Spencer84487f12015-07-24 21:03:07 +000045#include "Options.inc"
46#undef OPTION
47};
48
Rui Ueyama8fe7ce52016-04-02 19:15:26 +000049ELFOptTable::ELFOptTable() : OptTable(OptInfo) {}
Michael J. Spencer84487f12015-07-24 21:03:07 +000050
51// Parses a given list of options.
Rui Ueyama15fa0352016-03-15 18:20:50 +000052opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
Michael J. Spencer84487f12015-07-24 21:03:07 +000053 // Make InputArgList from string vectors.
Michael J. Spencer84487f12015-07-24 21:03:07 +000054 unsigned MissingIndex;
55 unsigned MissingCount;
56
Rui Ueyamaeeb22f82015-09-25 15:37:33 +000057 // Expand response files. '@<filename>' is replaced by the file's contents.
58 SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());
Rui Ueyama15fa0352016-03-15 18:20:50 +000059 StringSaver Saver(Alloc);
Rui Ueyama5002a672016-05-02 19:59:56 +000060 cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Vec);
Rui Ueyamaeeb22f82015-09-25 15:37:33 +000061
62 // Parse options and then do error checking.
Rui Ueyama15fa0352016-03-15 18:20:50 +000063 opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
Michael J. Spencer84487f12015-07-24 21:03:07 +000064 if (MissingCount)
George Rimar57610422016-03-11 14:43:02 +000065 error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) +
Michael J. Spencer84487f12015-07-24 21:03:07 +000066 "\", expected " + Twine(MissingCount) +
67 (MissingCount == 1 ? " argument.\n" : " arguments"));
Rui Ueyamad5b5ab72015-09-24 18:55:33 +000068
69 iterator_range<opt::arg_iterator> Unknowns = Args.filtered(OPT_UNKNOWN);
70 for (auto *Arg : Unknowns)
George Rimar57610422016-03-11 14:43:02 +000071 warning("warning: unknown argument: " + Arg->getSpelling());
Rui Ueyamad5b5ab72015-09-24 18:55:33 +000072 if (Unknowns.begin() != Unknowns.end())
George Rimar57610422016-03-11 14:43:02 +000073 error("unknown argument(s) found");
Michael J. Spencer84487f12015-07-24 21:03:07 +000074 return Args;
75}
Rui Ueyama4b02ca92015-10-11 03:28:39 +000076
Rui Ueyama1eb9f442016-02-28 03:18:09 +000077void elf::printHelp(const char *Argv0) {
78 ELFOptTable Table;
79 Table.PrintHelp(outs(), Argv0, "lld", false);
80}
81
Rui Ueyama1abcf372016-02-28 03:18:07 +000082void elf::printVersion() {
83 outs() << "LLD " << getLLDVersion();
84 std::string S = getLLDRepositoryVersion();
85 if (!S.empty())
Rui Ueyama5bc2acd2016-03-13 23:07:42 +000086 outs() << " " << S;
87 outs() << "\n";
Rui Ueyama1abcf372016-02-28 03:18:07 +000088}
89
Rui Ueyamaaa00e962016-04-30 21:40:04 +000090// Makes a given pathname an absolute path first, and then remove
91// beginning /. For example, "../foo.o" is converted to "home/john/foo.o",
92// assuming that the current directory is "/home/john/bar".
Rui Ueyama9aea9572016-04-30 22:23:29 +000093static std::string relativeToRoot(StringRef Path) {
Rui Ueyamaaa00e962016-04-30 21:40:04 +000094 SmallString<128> Abs = Path;
95 if (std::error_code EC = fs::make_absolute(Abs))
96 fatal("make_absolute failed: " + EC.message());
97 path::remove_dots(Abs, /*remove_dot_dot=*/true);
Rui Ueyamacf0dd1e2016-04-26 20:41:32 +000098
Rui Ueyamaaa00e962016-04-30 21:40:04 +000099 // This is Windows specific. root_name() returns a drive letter
100 // (e.g. "c:") or a UNC name (//net). We want to keep it as part
101 // of the result.
Rui Ueyamacf0dd1e2016-04-26 20:41:32 +0000102 SmallString<128> Res;
Rui Ueyamaff12f232016-05-02 18:16:14 +0000103 StringRef Root = path::root_name(Abs);
Rui Ueyama38aa57d2016-04-30 22:20:27 +0000104 if (Root.endswith(":"))
Rui Ueyamaaa00e962016-04-30 21:40:04 +0000105 Res = Root.drop_back();
Rui Ueyama38aa57d2016-04-30 22:20:27 +0000106 else if (Root.startswith("//"))
Rui Ueyamaaa00e962016-04-30 21:40:04 +0000107 Res = Root.substr(2);
108
109 path::append(Res, path::relative_path(Abs));
Rui Ueyamacf0dd1e2016-04-26 20:41:32 +0000110 return Res.str();
111}
112
Rui Ueyama9aea9572016-04-30 22:23:29 +0000113static std::string getDestPath(StringRef Path) {
114 std::string Relpath = relativeToRoot(Path);
Rui Ueyamaaa00e962016-04-30 21:40:04 +0000115 SmallString<128> Dest;
Rafael Espindola1dd2b3d2016-05-03 17:30:44 +0000116 path::append(Dest, path::filename(Config->Reproduce), Relpath);
Rui Ueyama9aea9572016-04-30 22:23:29 +0000117 return Dest.str();
118}
Rui Ueyamaaa00e962016-04-30 21:40:04 +0000119
Rafael Espindola2c51e612016-05-04 12:47:56 +0000120static void maybePrintCpioMemberAux(raw_fd_ostream &OS, StringRef Path,
121 StringRef Data) {
Rafael Espindola1dd2b3d2016-05-03 17:30:44 +0000122 OS << "070707"; // c_magic
123
124 // The c_dev/c_ino pair should be unique according to the spec, but no one
125 // seems to care.
126 OS << "000000"; // c_dev
127 OS << "000000"; // c_ino
128
129 OS << "100664"; // c_mode: C_ISREG | rw-rw-r--
130 OS << "000000"; // c_uid
131 OS << "000000"; // c_gid
132 OS << "000001"; // c_nlink
133 OS << "000000"; // c_rdev
134 OS << "00000000000"; // c_mtime
135 OS << format("%06o", Path.size() + 1); // c_namesize
136 OS << format("%011o", Data.size()); // c_filesize
137 OS << Path << '\0'; // c_name
138 OS << Data; // c_filedata
139}
140
Rafael Espindola2c51e612016-05-04 12:47:56 +0000141static void maybePrintCpioMember(StringRef Path, StringRef Data) {
142 if (Config->Reproduce.empty())
143 return;
144
145 if (!Driver->IncludedFiles.insert(Path).second)
146 return;
147 raw_fd_ostream &OS = *Driver->ReproduceArchive;
148 maybePrintCpioMemberAux(OS, Path, Data);
149
150 // Print the trailer and seek back. This way we have a valid archive if we
151 // crash.
152 uint64_t Pos = OS.tell();
153 maybePrintCpioMemberAux(OS, "TRAILER!!!", "");
154 OS.seek(Pos);
155}
156
Rafael Espindola1dd2b3d2016-05-03 17:30:44 +0000157// Write file Src with content Data to the archive.
158void elf::maybeCopyInputFile(StringRef Src, StringRef Data) {
159 std::string Dest = getDestPath(Src);
160 maybePrintCpioMember(Dest, Data);
161}
162
Rui Ueyamaaa00e962016-04-30 21:40:04 +0000163// Quote a given string if it contains a space character.
164static std::string quote(StringRef S) {
165 if (S.find(' ') == StringRef::npos)
166 return S;
167 return ("\"" + S + "\"").str();
168}
169
Rui Ueyama2796ae32016-04-30 22:46:47 +0000170static std::string rewritePath(StringRef S) {
171 if (fs::exists(S))
Rafael Espindolae85bcbd2016-05-02 14:12:35 +0000172 return relativeToRoot(S);
Rui Ueyama2796ae32016-04-30 22:46:47 +0000173 return S;
174}
175
Rui Ueyamaaa00e962016-04-30 21:40:04 +0000176// Copies all input files to Config->Reproduce directory and
177// create a response file as "response.txt", so that you can re-run
178// the same command with the same inputs just by executing
179// "ld.lld @response.txt". Used by --reproduce. This feature is
180// supposed to be used by users to report an issue to LLD developers.
Rui Ueyama5002a672016-05-02 19:59:56 +0000181void elf::createResponseFile(const opt::InputArgList &Args) {
Rafael Espindola1dd2b3d2016-05-03 17:30:44 +0000182 SmallString<0> Data;
183 raw_svector_ostream OS(Data);
Rui Ueyama2796ae32016-04-30 22:46:47 +0000184 // Copy the command line to response.txt while rewriting paths.
Rui Ueyamaaa00e962016-04-30 21:40:04 +0000185 for (auto *Arg : Args) {
186 switch (Arg->getOption().getID()) {
187 case OPT_reproduce:
188 break;
Rui Ueyama2796ae32016-04-30 22:46:47 +0000189 case OPT_INPUT:
190 OS << quote(rewritePath(Arg->getValue())) << "\n";
Rui Ueyamaaa00e962016-04-30 21:40:04 +0000191 break;
Rui Ueyama2796ae32016-04-30 22:46:47 +0000192 case OPT_L:
193 case OPT_dynamic_list:
Rui Ueyama2796ae32016-04-30 22:46:47 +0000194 case OPT_rpath:
195 case OPT_script:
196 case OPT_version_script:
197 OS << Arg->getSpelling() << " "
198 << quote(rewritePath(Arg->getValue())) << "\n";
199 break;
Rui Ueyamaaa00e962016-04-30 21:40:04 +0000200 default:
Rui Ueyamae951a1d2016-05-02 17:34:17 +0000201 OS << Arg->getSpelling();
202 if (Arg->getNumValues() > 0)
203 OS << " " << quote(Arg->getValue());
204 OS << "\n";
Rui Ueyamaaa00e962016-04-30 21:40:04 +0000205 }
206 }
Rafael Espindola1dd2b3d2016-05-03 17:30:44 +0000207
208 SmallString<128> Dest;
209 path::append(Dest, path::filename(Config->Reproduce), "response.txt");
210 maybePrintCpioMember(Dest, Data);
Rui Ueyamacf0dd1e2016-04-26 20:41:32 +0000211}
212
Rafael Espindolae0df00b2016-02-28 00:25:54 +0000213std::string elf::findFromSearchPaths(StringRef Path) {
Rui Ueyama52a15092015-10-11 03:28:42 +0000214 for (StringRef Dir : Config->SearchPaths) {
215 std::string FullPath = buildSysrootedPath(Dir, Path);
Rui Ueyamafc288272016-05-02 18:51:08 +0000216 if (fs::exists(FullPath))
Rui Ueyama52a15092015-10-11 03:28:42 +0000217 return FullPath;
218 }
219 return "";
220}
221
Rui Ueyama4b02ca92015-10-11 03:28:39 +0000222// Searches a given library from input search paths, which are filled
223// from -L command line switches. Returns a path to an existent library file.
Rafael Espindolae0df00b2016-02-28 00:25:54 +0000224std::string elf::searchLibrary(StringRef Path) {
Rui Ueyama319d7302016-03-29 20:53:21 +0000225 if (Path.startswith(":"))
226 return findFromSearchPaths(Path.substr(1));
227 if (!Config->Static) {
228 std::string S = findFromSearchPaths(("lib" + Path + ".so").str());
Rui Ueyama52a15092015-10-11 03:28:42 +0000229 if (!S.empty())
230 return S;
Rui Ueyama4b02ca92015-10-11 03:28:39 +0000231 }
Rui Ueyama319d7302016-03-29 20:53:21 +0000232 return findFromSearchPaths(("lib" + Path + ".a").str());
Rui Ueyama4b02ca92015-10-11 03:28:39 +0000233}
234
235// Makes a path by concatenating Dir and File.
236// If Dir starts with '=' the result will be preceded by Sysroot,
237// which can be set with --sysroot command line switch.
Rafael Espindolae0df00b2016-02-28 00:25:54 +0000238std::string elf::buildSysrootedPath(StringRef Dir, StringRef File) {
Rui Ueyama4b02ca92015-10-11 03:28:39 +0000239 SmallString<128> Path;
240 if (Dir.startswith("="))
Rui Ueyamafc288272016-05-02 18:51:08 +0000241 path::append(Path, Config->Sysroot, Dir.substr(1), File);
Rui Ueyama4b02ca92015-10-11 03:28:39 +0000242 else
Rui Ueyamafc288272016-05-02 18:51:08 +0000243 path::append(Path, Dir, File);
Rui Ueyama4b02ca92015-10-11 03:28:39 +0000244 return Path.str();
245}