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// This file contains utility functions for the ctx.driver. Because there
10// are so many small functions, we created this separate file to make
11// Driver.cpp less cluttered.
12//
13//===----------------------------------------------------------------------===//
14
15#include "Config.h"
16#include "Driver.h"
17#include "lld/Common/CommonLinkerContext.h"
18#include "lld/Common/Reproduce.h"
19#include "llvm/Option/Option.h"
20#include "llvm/Support/CommandLine.h"
21#include "llvm/Support/FileSystem.h"
22#include "llvm/Support/Path.h"
23#include "llvm/Support/TimeProfiler.h"
24#include "llvm/TargetParser/Host.h"
25#include "llvm/TargetParser/Triple.h"
26#include <optional>
27
28using namespace llvm;
29using namespace llvm::sys;
30using namespace llvm::opt;
31using namespace lld;
32using namespace lld::elf;
33
34// Create OptTable
35
36#define OPTTABLE_STR_TABLE_CODE
37#include "Options.inc"
38#undef OPTTABLE_STR_TABLE_CODE
39
40// Create prefix string literals used in Options.td
41#define OPTTABLE_PREFIXES_TABLE_CODE
42#include "Options.inc"
43#undef OPTTABLE_PREFIXES_TABLE_CODE
44
45// Create table mapping all options defined in Options.td
46static constexpr opt::OptTable::Info optInfo[] = {
47#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
48#include "Options.inc"
49#undef OPTION
50};
51
52ELFOptTable::ELFOptTable()
53 : GenericOptTable(OptionStrTable, OptionPrefixesTable, optInfo) {}
54
55// Set color diagnostics according to --color-diagnostics={auto,always,never}
56// or --no-color-diagnostics flags.
57static void handleColorDiagnostics(Ctx &ctx, opt::InputArgList &args) {
58 auto *arg = args.getLastArg(OPT_color_diagnostics);
59 if (!arg)
60 return;
61 StringRef s = arg->getValue();
62 if (s == "always")
63 ctx.e.errs().enable_colors(enable: true);
64 else if (s == "never")
65 ctx.e.errs().enable_colors(enable: false);
66 else if (s != "auto")
67 ErrAlways(ctx) << "unknown option: --color-diagnostics=" << s;
68}
69
70static cl::TokenizerCallback getQuotingStyle(Ctx &ctx,
71 opt::InputArgList &args) {
72 if (auto *arg = args.getLastArg(OPT_rsp_quoting)) {
73 StringRef s = arg->getValue();
74 if (s != "windows" && s != "posix")
75 ErrAlways(ctx) << "invalid response file quoting: " << s;
76 if (s == "windows")
77 return cl::TokenizeWindowsCommandLine;
78 return cl::TokenizeGNUCommandLine;
79 }
80 if (Triple(sys::getProcessTriple()).isOSWindows())
81 return cl::TokenizeWindowsCommandLine;
82 return cl::TokenizeGNUCommandLine;
83}
84
85// Gold LTO plugin takes a `--plugin-opt foo=bar` option as an alias for
86// `--plugin-opt=foo=bar`. We want to handle `--plugin-opt=foo=` as an
87// option name and `bar` as a value. Unfortunately, OptParser cannot
88// handle an option with a space in it.
89//
90// In this function, we concatenate command line arguments so that
91// `--plugin-opt <foo>` is converted to `--plugin-opt=<foo>`. This is a
92// bit hacky, but looks like it is still better than handling --plugin-opt
93// options by hand.
94static void concatLTOPluginOptions(Ctx &ctx,
95 SmallVectorImpl<const char *> &args) {
96 SmallVector<const char *, 256> v;
97 for (size_t i = 0, e = args.size(); i != e; ++i) {
98 StringRef s = args[i];
99 if ((s == "-plugin-opt" || s == "--plugin-opt") && i + 1 != e) {
100 v.push_back(Elt: ctx.saver.save(S: s + "=" + args[i + 1]).data());
101 ++i;
102 } else {
103 v.push_back(Elt: args[i]);
104 }
105 }
106 args = std::move(v);
107}
108
109// Parses a given list of options.
110opt::InputArgList ELFOptTable::parse(Ctx &ctx, ArrayRef<const char *> argv) {
111 // Make InputArgList from string vectors.
112 unsigned missingIndex;
113 unsigned missingCount;
114 SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());
115
116 // We need to get the quoting style for response files before parsing all
117 // options so we parse here before and ignore all the options but
118 // --rsp-quoting.
119 opt::InputArgList args = this->ParseArgs(Args: vec, MissingArgIndex&: missingIndex, MissingArgCount&: missingCount);
120
121 // Expand response files (arguments in the form of @<filename>)
122 // and then parse the argument again.
123 cl::ExpandResponseFiles(Saver&: ctx.saver, Tokenizer: getQuotingStyle(ctx, args), Argv&: vec);
124 concatLTOPluginOptions(ctx, args&: vec);
125 args = this->ParseArgs(Args: vec, MissingArgIndex&: missingIndex, MissingArgCount&: missingCount);
126
127 handleColorDiagnostics(ctx, args);
128 if (missingCount)
129 ErrAlways(ctx) << args.getArgString(Index: missingIndex) << ": missing argument";
130
131 for (opt::Arg *arg : args.filtered(OPT_UNKNOWN)) {
132 std::string nearest;
133 if (findNearest(arg->getAsString(args), nearest) > 1)
134 ErrAlways(ctx) << "unknown argument '" << arg->getAsString(args) << "'";
135 else
136 ErrAlways(ctx) << "unknown argument '" << arg->getAsString(args)
137 << "', did you mean '" << nearest << "'";
138 }
139 return args;
140}
141
142void elf::printHelp(Ctx &ctx) {
143 auto &outs = ctx.e.outs();
144 ELFOptTable().printHelp(
145 OS&: outs, Usage: (ctx.arg.progName + " [options] file...").str().c_str(), Title: "lld",
146 ShowHidden: false /*ShowHidden*/, ShowAllAliases: true /*ShowAllAliases*/);
147 outs << "\n";
148
149 // Scripts generated by Libtool versions up to 2021-10 expect /: supported
150 // targets:.* elf/ in a message for the --help option. If it doesn't match,
151 // the scripts assume that the linker doesn't support very basic features
152 // such as shared libraries. Therefore, we need to print out at least "elf".
153 outs << ctx.arg.progName << ": supported targets: elf\n";
154}
155
156static std::string rewritePath(StringRef s) {
157 if (fs::exists(Path: s))
158 return relativeToRoot(path: s);
159 return std::string(s);
160}
161
162// Reconstructs command line arguments so that so that you can re-run
163// the same command with the same inputs. This is for --reproduce.
164std::string elf::createResponseFile(const opt::InputArgList &args) {
165 SmallString<0> data;
166 raw_svector_ostream os(data);
167 os << "--chroot .\n";
168
169 // Copy the command line to the output while rewriting paths.
170 for (auto *arg : args) {
171 switch (arg->getOption().getID()) {
172 case OPT_reproduce:
173 break;
174 case OPT_INPUT:
175 os << quote(s: rewritePath(s: arg->getValue())) << "\n";
176 break;
177 case OPT_o:
178 case OPT_Map:
179 case OPT_dependency_file:
180 case OPT_print_archive_stats:
181 case OPT_why_extract:
182 // If an output path contains directories, "lld @response.txt" will
183 // likely fail because the archive we are creating doesn't contain empty
184 // directories for the output path (-o doesn't create directories).
185 // Strip directories to prevent the issue.
186 os << arg->getSpelling();
187 if (arg->getOption().getRenderStyle() == opt::Option::RenderSeparateStyle)
188 os << ' ';
189 os << quote(s: path::filename(path: arg->getValue())) << '\n';
190 break;
191 case OPT_lto_sample_profile:
192 os << arg->getSpelling() << quote(s: rewritePath(s: arg->getValue())) << "\n";
193 break;
194 case OPT_call_graph_ordering_file:
195 case OPT_default_script:
196 case OPT_dynamic_list:
197 case OPT_export_dynamic_symbol_list:
198 case OPT_just_symbols:
199 case OPT_library_path:
200 case OPT_remap_inputs_file:
201 case OPT_retain_symbols_file:
202 case OPT_rpath:
203 case OPT_script:
204 case OPT_symbol_ordering_file:
205 case OPT_sysroot:
206 case OPT_version_script:
207 os << arg->getSpelling() << " " << quote(s: rewritePath(s: arg->getValue()))
208 << "\n";
209 break;
210 default:
211 os << toString(arg: *arg) << "\n";
212 }
213 }
214 return std::string(data);
215}
216
217// Find a file by concatenating given paths. If a resulting path
218// starts with "=", the character is replaced with a --sysroot value.
219static std::optional<std::string> findFile(Ctx &ctx, StringRef path1,
220 const Twine &path2) {
221 SmallString<128> s;
222 if (path1.starts_with(Prefix: "="))
223 path::append(path&: s, a: ctx.arg.sysroot, b: path1.substr(Start: 1), c: path2);
224 else
225 path::append(path&: s, a: path1, b: path2);
226
227 if (fs::exists(Path: s))
228 return std::string(s);
229 return std::nullopt;
230}
231
232std::optional<std::string> elf::findFromSearchPaths(Ctx &ctx, StringRef path) {
233 for (StringRef dir : ctx.arg.searchPaths)
234 if (std::optional<std::string> s = findFile(ctx, path1: dir, path2: path))
235 return s;
236 return std::nullopt;
237}
238
239// This is for -l<basename>. We'll look for lib<basename>.so or lib<basename>.a from
240// search paths.
241std::optional<std::string> elf::searchLibraryBaseName(Ctx &ctx,
242 StringRef name) {
243 for (StringRef dir : ctx.arg.searchPaths) {
244 if (!ctx.arg.isStatic)
245 if (std::optional<std::string> s =
246 findFile(ctx, path1: dir, path2: "lib" + name + ".so"))
247 return s;
248 if (std::optional<std::string> s = findFile(ctx, path1: dir, path2: "lib" + name + ".a"))
249 return s;
250 }
251 return std::nullopt;
252}
253
254// This is for -l<namespec>.
255std::optional<std::string> elf::searchLibrary(Ctx &ctx, StringRef name) {
256 llvm::TimeTraceScope timeScope("Locate library", name);
257 if (name.starts_with(Prefix: ":"))
258 return findFromSearchPaths(ctx, path: name.substr(Start: 1));
259 return searchLibraryBaseName(ctx, name);
260}
261
262// If a linker/version script doesn't exist in the current directory, we also
263// look for the script in the '-L' search paths. This matches the behaviour of
264// '-T', --version-script=, and linker script INPUT() command in ld.bfd.
265std::optional<std::string> elf::searchScript(Ctx &ctx, StringRef name) {
266 if (fs::exists(Path: name))
267 return name.str();
268 return findFromSearchPaths(ctx, path: name);
269}
270

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of lld/ELF/DriverUtils.cpp