blob: 6d027c529c19e9f9edd78247cd73359592fb94d8 [file] [log] [blame]
Michael J. Spencer84487f12015-07-24 21:03:07 +00001//===- DriverUtils.cpp ----------------------------------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Michael J. Spencer84487f12015-07-24 21:03:07 +00006//
7//===----------------------------------------------------------------------===//
8//
Fangrui Songf596d822022-10-01 15:12:50 -07009// This file contains utility functions for the ctx.driver. Because there
Michael J. Spencer84487f12015-07-24 21:03:07 +000010// are so many small functions, we created this separate file to make
11// Driver.cpp less cluttered.
12//
13//===----------------------------------------------------------------------===//
14
Fangrui Song27bb7992022-02-07 21:53:34 -080015#include "Config.h"
Michael J. Spencer84487f12015-07-24 21:03:07 +000016#include "Driver.h"
Alexandre Ganea83d59e02022-01-20 14:53:18 -050017#include "lld/Common/CommonLinkerContext.h"
Rui Ueyama3f851702017-10-02 21:00:41 +000018#include "lld/Common/Reproduce.h"
Rui Ueyamaaf2312f2016-05-04 23:12:55 +000019#include "llvm/Option/Option.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"
Rui Ueyama4b02ca92015-10-11 03:28:39 +000022#include "llvm/Support/Path.h"
James Henderson439341b2020-11-03 14:41:09 +000023#include "llvm/Support/TimeProfiler.h"
Archibald Elliottd768bf92023-02-10 09:59:46 +000024#include "llvm/TargetParser/Host.h"
Archibald Elliott62c7f032023-02-07 12:21:51 +000025#include "llvm/TargetParser/Triple.h"
Fangrui Song4191fda2022-11-26 19:19:15 -080026#include <optional>
Michael J. Spencer84487f12015-07-24 21:03:07 +000027
28using namespace llvm;
Rui Ueyamacf0dd1e2016-04-26 20:41:32 +000029using namespace llvm::sys;
Rafael Espindolaeed97252018-02-06 18:12:41 +000030using namespace llvm::opt;
Fangrui Song07837b82020-05-14 22:18:58 -070031using namespace lld;
32using namespace lld::elf;
Michael J. Spencer84487f12015-07-24 21:03:07 +000033
34// Create OptTable
35
Chandler Carruthdd647e32024-12-11 15:44:44 -080036#define OPTTABLE_STR_TABLE_CODE
Michael J. Spencer84487f12015-07-24 21:03:07 +000037#include "Options.inc"
Chandler Carruthdd647e32024-12-11 15:44:44 -080038#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
Michael J. Spencer84487f12015-07-24 21:03:07 +000044
45// Create table mapping all options defined in Options.td
serge-sans-paille07d9ab92022-12-23 13:25:58 +010046static constexpr opt::OptTable::Info optInfo[] = {
Jan Svoboda3f092f32023-08-04 11:19:09 -070047#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
Michael J. Spencer84487f12015-07-24 21:03:07 +000048#include "Options.inc"
49#undef OPTION
50};
51
Chandler Carruthdd647e32024-12-11 15:44:44 -080052ELFOptTable::ELFOptTable()
53 : GenericOptTable(OptionStrTable, OptionPrefixesTable, optInfo) {}
Michael J. Spencer84487f12015-07-24 21:03:07 +000054
Fangrui Songbf6e2592021-10-25 12:52:06 -070055// Set color diagnostics according to --color-diagnostics={auto,always,never}
56// or --no-color-diagnostics flags.
Fangrui Song942928f2024-11-14 23:04:18 -080057static void handleColorDiagnostics(Ctx &ctx, opt::InputArgList &args) {
Fangrui Songcbcdb522022-07-25 01:14:53 -070058 auto *arg = args.getLastArg(OPT_color_diagnostics);
Rui Ueyama3837f422019-07-10 05:00:37 +000059 if (!arg)
Bob Haarmanb8a59c82017-10-25 22:28:38 +000060 return;
Fangrui Songcbcdb522022-07-25 01:14:53 -070061 StringRef s = arg->getValue();
62 if (s == "always")
Fangrui Song8f238f62024-11-16 22:28:54 -080063 ctx.e.errs().enable_colors(true);
Fangrui Songcbcdb522022-07-25 01:14:53 -070064 else if (s == "never")
Fangrui Song8f238f62024-11-16 22:28:54 -080065 ctx.e.errs().enable_colors(false);
Fangrui Songcbcdb522022-07-25 01:14:53 -070066 else if (s != "auto")
Fangrui Song09c2c5e2024-11-06 22:04:52 -080067 ErrAlways(ctx) << "unknown option: --color-diagnostics=" << s;
Rui Ueyama398f55f2016-12-20 02:17:24 +000068}
69
Fangrui Songe24457a2024-11-14 22:17:10 -080070static cl::TokenizerCallback getQuotingStyle(Ctx &ctx,
71 opt::InputArgList &args) {
Rui Ueyama3837f422019-07-10 05:00:37 +000072 if (auto *arg = args.getLastArg(OPT_rsp_quoting)) {
73 StringRef s = arg->getValue();
74 if (s != "windows" && s != "posix")
Fangrui Song09c2c5e2024-11-06 22:04:52 -080075 ErrAlways(ctx) << "invalid response file quoting: " << s;
Rui Ueyama3837f422019-07-10 05:00:37 +000076 if (s == "windows")
Davide Italianof296a7e2016-07-06 21:24:34 +000077 return cl::TokenizeWindowsCommandLine;
78 return cl::TokenizeGNUCommandLine;
79 }
Sam Clegg928e9e12020-03-04 11:29:45 -080080 if (Triple(sys::getProcessTriple()).isOSWindows())
Davide Italianof296a7e2016-07-06 21:24:34 +000081 return cl::TokenizeWindowsCommandLine;
82 return cl::TokenizeGNUCommandLine;
83}
84
Rui Ueyama0dd56dc2018-05-22 02:53:11 +000085// 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.
Fangrui Song7d137752024-11-16 15:48:01 -080094static void concatLTOPluginOptions(Ctx &ctx,
95 SmallVectorImpl<const char *> &args) {
Rui Ueyama3837f422019-07-10 05:00:37 +000096 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) {
Fangrui Song2991a4e2024-11-16 22:34:12 -0800100 v.push_back(ctx.saver.save(s + "=" + args[i + 1]).data());
Rui Ueyama3837f422019-07-10 05:00:37 +0000101 ++i;
Rui Ueyama0dd56dc2018-05-22 02:53:11 +0000102 } else {
Rui Ueyama3837f422019-07-10 05:00:37 +0000103 v.push_back(args[i]);
Rui Ueyama0dd56dc2018-05-22 02:53:11 +0000104 }
105 }
Rui Ueyama3837f422019-07-10 05:00:37 +0000106 args = std::move(v);
Rui Ueyama0dd56dc2018-05-22 02:53:11 +0000107}
108
Michael J. Spencer84487f12015-07-24 21:03:07 +0000109// Parses a given list of options.
Fangrui Songe24457a2024-11-14 22:17:10 -0800110opt::InputArgList ELFOptTable::parse(Ctx &ctx, ArrayRef<const char *> argv) {
Michael J. Spencer84487f12015-07-24 21:03:07 +0000111 // Make InputArgList from string vectors.
Rui Ueyama3837f422019-07-10 05:00:37 +0000112 unsigned missingIndex;
113 unsigned missingCount;
114 SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());
Davide Italianof296a7e2016-07-06 21:24:34 +0000115
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.
Rui Ueyama3837f422019-07-10 05:00:37 +0000119 opt::InputArgList args = this->ParseArgs(vec, missingIndex, missingCount);
Michael J. Spencer84487f12015-07-24 21:03:07 +0000120
Rui Ueyama398f55f2016-12-20 02:17:24 +0000121 // Expand response files (arguments in the form of @<filename>)
122 // and then parse the argument again.
Fangrui Song2991a4e2024-11-16 22:34:12 -0800123 cl::ExpandResponseFiles(ctx.saver, getQuotingStyle(ctx, args), vec);
Fangrui Song7d137752024-11-16 15:48:01 -0800124 concatLTOPluginOptions(ctx, vec);
Rui Ueyama3837f422019-07-10 05:00:37 +0000125 args = this->ParseArgs(vec, missingIndex, missingCount);
Rui Ueyama398f55f2016-12-20 02:17:24 +0000126
Fangrui Song942928f2024-11-14 23:04:18 -0800127 handleColorDiagnostics(ctx, args);
Rui Ueyama3837f422019-07-10 05:00:37 +0000128 if (missingCount)
Fangrui Song483516f2024-11-16 20:32:44 -0800129 ErrAlways(ctx) << args.getArgString(missingIndex) << ": missing argument";
Rui Ueyamad5b5ab72015-09-24 18:55:33 +0000130
Nico Weber11b76252020-11-23 10:51:56 -0500131 for (opt::Arg *arg : args.filtered(OPT_UNKNOWN)) {
Rui Ueyama3837f422019-07-10 05:00:37 +0000132 std::string nearest;
133 if (findNearest(arg->getAsString(args), nearest) > 1)
Fangrui Song09c2c5e2024-11-06 22:04:52 -0800134 ErrAlways(ctx) << "unknown argument '" << arg->getAsString(args) << "'";
Nico Weber54743d52019-05-07 13:48:30 +0000135 else
Fangrui Song09c2c5e2024-11-06 22:04:52 -0800136 ErrAlways(ctx) << "unknown argument '" << arg->getAsString(args)
137 << "', did you mean '" << nearest << "'";
Nico Weber54743d52019-05-07 13:48:30 +0000138 }
Rui Ueyama3837f422019-07-10 05:00:37 +0000139 return args;
Michael J. Spencer84487f12015-07-24 21:03:07 +0000140}
Rui Ueyama4b02ca92015-10-11 03:28:39 +0000141
Fangrui Songa7550e12024-09-25 22:04:45 -0700142void elf::printHelp(Ctx &ctx) {
Fangrui Song8f238f62024-11-16 22:28:54 -0800143 auto &outs = ctx.e.outs();
Fangrui Songf1e2d582021-06-24 14:47:03 -0700144 ELFOptTable().printHelp(
Fangrui Songdc6229b2024-11-16 18:25:50 -0800145 outs, (ctx.arg.progName + " [options] file...").str().c_str(), "lld",
146 false /*ShowHidden*/, true /*ShowAllAliases*/);
147 outs << "\n";
Rui Ueyamab57412e2017-03-23 01:00:22 +0000148
Fangrui Songbf6e2592021-10-25 12:52:06 -0700149 // 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".
Fangrui Songdc6229b2024-11-16 18:25:50 -0800153 outs << ctx.arg.progName << ": supported targets: elf\n";
Rui Ueyama1eb9f442016-02-28 03:18:09 +0000154}
155
Rui Ueyama3837f422019-07-10 05:00:37 +0000156static std::string rewritePath(StringRef s) {
157 if (fs::exists(s))
158 return relativeToRoot(s);
Benjamin Krameradcd0262020-01-28 20:23:46 +0100159 return std::string(s);
Rui Ueyamac94dad92019-02-22 23:59:43 +0000160}
161
Rui Ueyamafe658772016-05-15 17:10:23 +0000162// Reconstructs command line arguments so that so that you can re-run
163// the same command with the same inputs. This is for --reproduce.
Fangrui Song07837b82020-05-14 22:18:58 -0700164std::string elf::createResponseFile(const opt::InputArgList &args) {
Rui Ueyama3837f422019-07-10 05:00:37 +0000165 SmallString<0> data;
166 raw_svector_ostream os(data);
167 os << "--chroot .\n";
Rui Ueyamafe658772016-05-15 17:10:23 +0000168
169 // Copy the command line to the output while rewriting paths.
Rui Ueyama3837f422019-07-10 05:00:37 +0000170 for (auto *arg : args) {
171 switch (arg->getOption().getID()) {
Rui Ueyamaaa00e962016-04-30 21:40:04 +0000172 case OPT_reproduce:
173 break;
Rui Ueyama2796ae32016-04-30 22:46:47 +0000174 case OPT_INPUT:
Rui Ueyama3837f422019-07-10 05:00:37 +0000175 os << quote(rewritePath(arg->getValue())) << "\n";
Rui Ueyamaaa00e962016-04-30 21:40:04 +0000176 break;
Rafael Espindolabba87162017-02-01 18:04:45 +0000177 case OPT_o:
Alex Brachet7baf1db2022-07-29 16:17:33 +0000178 case OPT_Map:
Fangrui Song6aeffa12024-11-24 17:23:52 -0800179 case OPT_dependency_file:
Fangrui Songdde41c62022-08-01 22:06:46 -0700180 case OPT_print_archive_stats:
181 case OPT_why_extract:
Alex Brachet7baf1db2022-07-29 16:17:33 +0000182 // If an output path contains directories, "lld @response.txt" will
183 // likely fail because the archive we are creating doesn't contain empty
Rafael Espindolabba87162017-02-01 18:04:45 +0000184 // directories for the output path (-o doesn't create directories).
185 // Strip directories to prevent the issue.
Fangrui Songdde41c62022-08-01 22:06:46 -0700186 os << arg->getSpelling();
187 if (arg->getOption().getRenderStyle() == opt::Option::RenderSeparateStyle)
188 os << ' ';
189 os << quote(path::filename(arg->getValue())) << '\n';
Rafael Espindolabba87162017-02-01 18:04:45 +0000190 break;
Hongtao Yu5b8db122021-02-05 17:56:45 -0800191 case OPT_lto_sample_profile:
192 os << arg->getSpelling() << quote(rewritePath(arg->getValue())) << "\n";
193 break;
Nico Weber4431c212020-11-30 19:54:04 -0500194 case OPT_call_graph_ordering_file:
Fangrui Songf02a27d2024-04-19 09:09:41 -0700195 case OPT_default_script:
Rui Ueyama2796ae32016-04-30 22:46:47 +0000196 case OPT_dynamic_list:
Fangrui Songb8940712022-07-25 01:20:32 -0700197 case OPT_export_dynamic_symbol_list:
Nico Weber4431c212020-11-30 19:54:04 -0500198 case OPT_just_symbols:
George Rimar4f37d572017-07-21 16:27:26 +0000199 case OPT_library_path:
Fangrui Song39c20a62023-04-26 13:18:55 -0700200 case OPT_remap_inputs_file:
Nico Weber4431c212020-11-30 19:54:04 -0500201 case OPT_retain_symbols_file:
Rui Ueyama2796ae32016-04-30 22:46:47 +0000202 case OPT_rpath:
203 case OPT_script:
James Henderson1304e8d2017-09-06 10:10:49 +0000204 case OPT_symbol_ordering_file:
Alexander Richardsond6424942017-11-20 15:49:48 +0000205 case OPT_sysroot:
Rui Ueyama2796ae32016-04-30 22:46:47 +0000206 case OPT_version_script:
Rui Ueyama3837f422019-07-10 05:00:37 +0000207 os << arg->getSpelling() << " " << quote(rewritePath(arg->getValue()))
Peter Collingbournefeee2102016-07-26 02:00:42 +0000208 << "\n";
Rui Ueyama2796ae32016-04-30 22:46:47 +0000209 break;
Rui Ueyamaaa00e962016-04-30 21:40:04 +0000210 default:
Rui Ueyama3837f422019-07-10 05:00:37 +0000211 os << toString(*arg) << "\n";
Rui Ueyamaaa00e962016-04-30 21:40:04 +0000212 }
213 }
Kazu Hirata21730eb2024-01-22 00:13:23 -0800214 return std::string(data);
Rui Ueyamacf0dd1e2016-04-26 20:41:32 +0000215}
216
Rui Ueyamaec752202016-11-19 19:23:56 +0000217// Find a file by concatenating given paths. If a resulting path
218// starts with "=", the character is replaced with a --sysroot value.
Fangrui Songdd326b12024-10-11 21:10:05 -0700219static std::optional<std::string> findFile(Ctx &ctx, StringRef path1,
Fangrui Song4191fda2022-11-26 19:19:15 -0800220 const Twine &path2) {
Rui Ueyama3837f422019-07-10 05:00:37 +0000221 SmallString<128> s;
Fangrui Song8d85c962023-06-05 14:36:19 -0700222 if (path1.starts_with("="))
Fangrui Songa7e14e22024-09-21 22:54:37 -0700223 path::append(s, ctx.arg.sysroot, path1.substr(1), path2);
Rui Ueyama4b02ca92015-10-11 03:28:39 +0000224 else
Rui Ueyama3837f422019-07-10 05:00:37 +0000225 path::append(s, path1, path2);
Rui Ueyamaec752202016-11-19 19:23:56 +0000226
Rui Ueyama3837f422019-07-10 05:00:37 +0000227 if (fs::exists(s))
Jonas Devlieghere3e242422020-01-29 21:30:21 -0800228 return std::string(s);
Fangrui Song4191fda2022-11-26 19:19:15 -0800229 return std::nullopt;
Rui Ueyamaec752202016-11-19 19:23:56 +0000230}
231
Fangrui Song49865102024-10-06 11:27:24 -0700232std::optional<std::string> elf::findFromSearchPaths(Ctx &ctx, StringRef path) {
Fangrui Songa7e14e22024-09-21 22:54:37 -0700233 for (StringRef dir : ctx.arg.searchPaths)
Fangrui Songdd326b12024-10-11 21:10:05 -0700234 if (std::optional<std::string> s = findFile(ctx, dir, path))
Rui Ueyama3837f422019-07-10 05:00:37 +0000235 return s;
Fangrui Song4191fda2022-11-26 19:19:15 -0800236 return std::nullopt;
Rui Ueyamaec752202016-11-19 19:23:56 +0000237}
238
Ben Dunbobbin1d165152019-05-17 03:44:15 +0000239// This is for -l<basename>. We'll look for lib<basename>.so or lib<basename>.a from
Rui Ueyama1cb63182016-11-19 19:26:52 +0000240// search paths.
Fangrui Song49865102024-10-06 11:27:24 -0700241std::optional<std::string> elf::searchLibraryBaseName(Ctx &ctx,
242 StringRef name) {
Fangrui Songa7e14e22024-09-21 22:54:37 -0700243 for (StringRef dir : ctx.arg.searchPaths) {
244 if (!ctx.arg.isStatic)
Fangrui Songdd326b12024-10-11 21:10:05 -0700245 if (std::optional<std::string> s =
246 findFile(ctx, dir, "lib" + name + ".so"))
Rui Ueyama3837f422019-07-10 05:00:37 +0000247 return s;
Fangrui Songdd326b12024-10-11 21:10:05 -0700248 if (std::optional<std::string> s = findFile(ctx, dir, "lib" + name + ".a"))
Rui Ueyama3837f422019-07-10 05:00:37 +0000249 return s;
Rui Ueyamaec752202016-11-19 19:23:56 +0000250 }
Fangrui Song4191fda2022-11-26 19:19:15 -0800251 return std::nullopt;
Rui Ueyama4b02ca92015-10-11 03:28:39 +0000252}
Alexander Richardson1de78472017-11-20 15:43:20 +0000253
Ben Dunbobbin1d165152019-05-17 03:44:15 +0000254// This is for -l<namespec>.
Fangrui Song49865102024-10-06 11:27:24 -0700255std::optional<std::string> elf::searchLibrary(Ctx &ctx, StringRef name) {
James Henderson439341b2020-11-03 14:41:09 +0000256 llvm::TimeTraceScope timeScope("Locate library", name);
Fangrui Song8d85c962023-06-05 14:36:19 -0700257 if (name.starts_with(":"))
Fangrui Song49865102024-10-06 11:27:24 -0700258 return findFromSearchPaths(ctx, name.substr(1));
259 return searchLibraryBaseName(ctx, name);
Ben Dunbobbin1d165152019-05-17 03:44:15 +0000260}
261
Fangrui Songc60f85d2018-07-25 21:53:18 +0000262// 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.
Fangrui Song49865102024-10-06 11:27:24 -0700265std::optional<std::string> elf::searchScript(Ctx &ctx, StringRef name) {
Rui Ueyama3837f422019-07-10 05:00:37 +0000266 if (fs::exists(name))
267 return name.str();
Fangrui Song49865102024-10-06 11:27:24 -0700268 return findFromSearchPaths(ctx, name);
Alexander Richardson1de78472017-11-20 15:43:20 +0000269}