184487f11SMichael J. Spencer //===- DriverUtils.cpp ----------------------------------------------------===//
284487f11SMichael J. Spencer //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
684487f11SMichael J. Spencer //
784487f11SMichael J. Spencer //===----------------------------------------------------------------------===//
884487f11SMichael J. Spencer //
984487f11SMichael J. Spencer // This file contains utility functions for the driver. Because there
1084487f11SMichael J. Spencer // are so many small functions, we created this separate file to make
1184487f11SMichael J. Spencer // Driver.cpp less cluttered.
1284487f11SMichael J. Spencer //
1384487f11SMichael J. Spencer //===----------------------------------------------------------------------===//
1484487f11SMichael J. Spencer
1527bb7990SFangrui Song #include "Config.h"
1684487f11SMichael J. Spencer #include "Driver.h"
1783d59e05SAlexandre Ganea #include "lld/Common/CommonLinkerContext.h"
183f851704SRui Ueyama #include "lld/Common/Reproduce.h"
19ec75220fSRui Ueyama #include "llvm/ADT/Optional.h"
20f296a7eeSDavide Italiano #include "llvm/ADT/Triple.h"
21af2312feSRui Ueyama #include "llvm/Option/Option.h"
22eeb22f82SRui Ueyama #include "llvm/Support/CommandLine.h"
234b02ca99SRui Ueyama #include "llvm/Support/FileSystem.h"
24213aea4cSReid Kleckner #include "llvm/Support/Host.h"
254b02ca99SRui Ueyama #include "llvm/Support/Path.h"
26439341b9SJames Henderson #include "llvm/Support/TimeProfiler.h"
2784487f11SMichael J. Spencer
2884487f11SMichael J. Spencer using namespace llvm;
29cf0dd1ebSRui Ueyama using namespace llvm::sys;
30eed97254SRafael Espindola using namespace llvm::opt;
3107837b8fSFangrui Song using namespace lld;
3207837b8fSFangrui Song using namespace lld::elf;
3384487f11SMichael J. Spencer
3484487f11SMichael J. Spencer // Create OptTable
3584487f11SMichael J. Spencer
3684487f11SMichael J. Spencer // Create prefix string literals used in Options.td
3784487f11SMichael J. Spencer #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
3884487f11SMichael J. Spencer #include "Options.inc"
3984487f11SMichael J. Spencer #undef PREFIX
4084487f11SMichael J. Spencer
4184487f11SMichael J. Spencer // Create table mapping all options defined in Options.td
423837f427SRui Ueyama static const opt::OptTable::Info optInfo[] = {
437859216bSSam Clegg #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
447859216bSSam Clegg {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \
457859216bSSam Clegg X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
4684487f11SMichael J. Spencer #include "Options.inc"
4784487f11SMichael J. Spencer #undef OPTION
4884487f11SMichael J. Spencer };
4984487f11SMichael J. Spencer
ELFOptTable()503837f427SRui Ueyama ELFOptTable::ELFOptTable() : OptTable(optInfo) {}
5184487f11SMichael J. Spencer
52bf6e259bSFangrui Song // Set color diagnostics according to --color-diagnostics={auto,always,never}
53bf6e259bSFangrui Song // or --no-color-diagnostics flags.
handleColorDiagnostics(opt::InputArgList & args)543837f427SRui Ueyama static void handleColorDiagnostics(opt::InputArgList &args) {
55cbcdb524SFangrui Song auto *arg = args.getLastArg(OPT_color_diagnostics);
563837f427SRui Ueyama if (!arg)
57b8a59c8aSBob Haarman return;
583837f427SRui Ueyama StringRef s = arg->getValue();
593837f427SRui Ueyama if (s == "always")
60d3fec7fbSJames Y Knight lld::errs().enable_colors(true);
613837f427SRui Ueyama else if (s == "never")
62d3fec7fbSJames Y Knight lld::errs().enable_colors(false);
633837f427SRui Ueyama else if (s != "auto")
643837f427SRui Ueyama error("unknown option: --color-diagnostics=" + s);
65b8a59c8aSBob Haarman }
66398f55f6SRui Ueyama
getQuotingStyle(opt::InputArgList & args)673837f427SRui Ueyama static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &args) {
683837f427SRui Ueyama if (auto *arg = args.getLastArg(OPT_rsp_quoting)) {
693837f427SRui Ueyama StringRef s = arg->getValue();
703837f427SRui Ueyama if (s != "windows" && s != "posix")
713837f427SRui Ueyama error("invalid response file quoting: " + s);
723837f427SRui Ueyama if (s == "windows")
73f296a7eeSDavide Italiano return cl::TokenizeWindowsCommandLine;
74f296a7eeSDavide Italiano return cl::TokenizeGNUCommandLine;
75f296a7eeSDavide Italiano }
76928e9e17SSam Clegg if (Triple(sys::getProcessTriple()).isOSWindows())
77f296a7eeSDavide Italiano return cl::TokenizeWindowsCommandLine;
78f296a7eeSDavide Italiano return cl::TokenizeGNUCommandLine;
79f296a7eeSDavide Italiano }
80f296a7eeSDavide Italiano
810dd56dcdSRui Ueyama // Gold LTO plugin takes a `--plugin-opt foo=bar` option as an alias for
820dd56dcdSRui Ueyama // `--plugin-opt=foo=bar`. We want to handle `--plugin-opt=foo=` as an
830dd56dcdSRui Ueyama // option name and `bar` as a value. Unfortunately, OptParser cannot
840dd56dcdSRui Ueyama // handle an option with a space in it.
850dd56dcdSRui Ueyama //
860dd56dcdSRui Ueyama // In this function, we concatenate command line arguments so that
870dd56dcdSRui Ueyama // `--plugin-opt <foo>` is converted to `--plugin-opt=<foo>`. This is a
880dd56dcdSRui Ueyama // bit hacky, but looks like it is still better than handling --plugin-opt
890dd56dcdSRui Ueyama // options by hand.
concatLTOPluginOptions(SmallVectorImpl<const char * > & args)903837f427SRui Ueyama static void concatLTOPluginOptions(SmallVectorImpl<const char *> &args) {
913837f427SRui Ueyama SmallVector<const char *, 256> v;
923837f427SRui Ueyama for (size_t i = 0, e = args.size(); i != e; ++i) {
933837f427SRui Ueyama StringRef s = args[i];
943837f427SRui Ueyama if ((s == "-plugin-opt" || s == "--plugin-opt") && i + 1 != e) {
9583d59e05SAlexandre Ganea v.push_back(saver().save(s + "=" + args[i + 1]).data());
963837f427SRui Ueyama ++i;
970dd56dcdSRui Ueyama } else {
983837f427SRui Ueyama v.push_back(args[i]);
990dd56dcdSRui Ueyama }
1000dd56dcdSRui Ueyama }
1013837f427SRui Ueyama args = std::move(v);
1020dd56dcdSRui Ueyama }
1030dd56dcdSRui Ueyama
10484487f11SMichael J. Spencer // Parses a given list of options.
parse(ArrayRef<const char * > argv)1053837f427SRui Ueyama opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> argv) {
10684487f11SMichael J. Spencer // Make InputArgList from string vectors.
1073837f427SRui Ueyama unsigned missingIndex;
1083837f427SRui Ueyama unsigned missingCount;
1093837f427SRui Ueyama SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());
110f296a7eeSDavide Italiano
111f296a7eeSDavide Italiano // We need to get the quoting style for response files before parsing all
112f296a7eeSDavide Italiano // options so we parse here before and ignore all the options but
113f296a7eeSDavide Italiano // --rsp-quoting.
1143837f427SRui Ueyama opt::InputArgList args = this->ParseArgs(vec, missingIndex, missingCount);
11584487f11SMichael J. Spencer
116398f55f6SRui Ueyama // Expand response files (arguments in the form of @<filename>)
117398f55f6SRui Ueyama // and then parse the argument again.
11883d59e05SAlexandre Ganea cl::ExpandResponseFiles(saver(), getQuotingStyle(args), vec);
1193837f427SRui Ueyama concatLTOPluginOptions(vec);
1203837f427SRui Ueyama args = this->ParseArgs(vec, missingIndex, missingCount);
121398f55f6SRui Ueyama
1223837f427SRui Ueyama handleColorDiagnostics(args);
1233837f427SRui Ueyama if (missingCount)
1243837f427SRui Ueyama error(Twine(args.getArgString(missingIndex)) + ": missing argument");
125d5b5ab76SRui Ueyama
12611b76258SNico Weber for (opt::Arg *arg : args.filtered(OPT_UNKNOWN)) {
1273837f427SRui Ueyama std::string nearest;
1283837f427SRui Ueyama if (findNearest(arg->getAsString(args), nearest) > 1)
1293837f427SRui Ueyama error("unknown argument '" + arg->getAsString(args) + "'");
13054743d57SNico Weber else
1313837f427SRui Ueyama error("unknown argument '" + arg->getAsString(args) +
1323837f427SRui Ueyama "', did you mean '" + nearest + "'");
13354743d57SNico Weber }
1343837f427SRui Ueyama return args;
13584487f11SMichael J. Spencer }
1364b02ca99SRui Ueyama
printHelp()13707837b8fSFangrui Song void elf::printHelp() {
138f1e2d585SFangrui Song ELFOptTable().printHelp(
139b11386f9SRui Ueyama lld::outs(), (config->progName + " [options] file...").str().c_str(),
140b11386f9SRui Ueyama "lld", false /*ShowHidden*/, true /*ShowAllAliases*/);
141b11386f9SRui Ueyama lld::outs() << "\n";
142b57412e9SRui Ueyama
143bf6e259bSFangrui Song // Scripts generated by Libtool versions up to 2021-10 expect /: supported
144bf6e259bSFangrui Song // targets:.* elf/ in a message for the --help option. If it doesn't match,
145bf6e259bSFangrui Song // the scripts assume that the linker doesn't support very basic features
146bf6e259bSFangrui Song // such as shared libraries. Therefore, we need to print out at least "elf".
147b11386f9SRui Ueyama lld::outs() << config->progName << ": supported targets: elf\n";
1481eb9f441SRui Ueyama }
1491eb9f441SRui Ueyama
rewritePath(StringRef s)1503837f427SRui Ueyama static std::string rewritePath(StringRef s) {
1513837f427SRui Ueyama if (fs::exists(s))
1523837f427SRui Ueyama return relativeToRoot(s);
153adcd0268SBenjamin Kramer return std::string(s);
154c94dad9dSRui Ueyama }
155c94dad9dSRui Ueyama
156fe65877cSRui Ueyama // Reconstructs command line arguments so that so that you can re-run
157fe65877cSRui Ueyama // the same command with the same inputs. This is for --reproduce.
createResponseFile(const opt::InputArgList & args)15807837b8fSFangrui Song std::string elf::createResponseFile(const opt::InputArgList &args) {
1593837f427SRui Ueyama SmallString<0> data;
1603837f427SRui Ueyama raw_svector_ostream os(data);
1613837f427SRui Ueyama os << "--chroot .\n";
162fe65877cSRui Ueyama
163fe65877cSRui Ueyama // Copy the command line to the output while rewriting paths.
1643837f427SRui Ueyama for (auto *arg : args) {
1653837f427SRui Ueyama switch (arg->getOption().getID()) {
166aa00e96aSRui Ueyama case OPT_reproduce:
167aa00e96aSRui Ueyama break;
1682796ae3fSRui Ueyama case OPT_INPUT:
1693837f427SRui Ueyama os << quote(rewritePath(arg->getValue())) << "\n";
170aa00e96aSRui Ueyama break;
171bba87168SRafael Espindola case OPT_o:
172bba87168SRafael Espindola // If -o path contains directories, "lld @response.txt" will likely
173bba87168SRafael Espindola // fail because the archive we are creating doesn't contain empty
174bba87168SRafael Espindola // directories for the output path (-o doesn't create directories).
175bba87168SRafael Espindola // Strip directories to prevent the issue.
17683e60f5aSNico Weber os << "-o " << quote(path::filename(arg->getValue())) << "\n";
177bba87168SRafael Espindola break;
1785b8db127SHongtao Yu case OPT_lto_sample_profile:
1795b8db127SHongtao Yu os << arg->getSpelling() << quote(rewritePath(arg->getValue())) << "\n";
1805b8db127SHongtao Yu break;
1814431c212SNico Weber case OPT_call_graph_ordering_file:
1822796ae3fSRui Ueyama case OPT_dynamic_list:
183*b8940715SFangrui Song case OPT_export_dynamic_symbol_list:
1844431c212SNico Weber case OPT_just_symbols:
1854f37d575SGeorge Rimar case OPT_library_path:
1864431c212SNico Weber case OPT_retain_symbols_file:
1872796ae3fSRui Ueyama case OPT_rpath:
1882796ae3fSRui Ueyama case OPT_script:
1891304e8ddSJames Henderson case OPT_symbol_ordering_file:
190d6424948SAlexander Richardson case OPT_sysroot:
1912796ae3fSRui Ueyama case OPT_version_script:
1923837f427SRui Ueyama os << arg->getSpelling() << " " << quote(rewritePath(arg->getValue()))
193feee2103SPeter Collingbourne << "\n";
1942796ae3fSRui Ueyama break;
195aa00e96aSRui Ueyama default:
1963837f427SRui Ueyama os << toString(*arg) << "\n";
197aa00e96aSRui Ueyama }
198aa00e96aSRui Ueyama }
199adcd0268SBenjamin Kramer return std::string(data.str());
200cf0dd1ebSRui Ueyama }
201cf0dd1ebSRui Ueyama
202ec75220fSRui Ueyama // Find a file by concatenating given paths. If a resulting path
203ec75220fSRui Ueyama // starts with "=", the character is replaced with a --sysroot value.
findFile(StringRef path1,const Twine & path2)2043837f427SRui Ueyama static Optional<std::string> findFile(StringRef path1, const Twine &path2) {
2053837f427SRui Ueyama SmallString<128> s;
2063837f427SRui Ueyama if (path1.startswith("="))
2073837f427SRui Ueyama path::append(s, config->sysroot, path1.substr(1), path2);
2084b02ca99SRui Ueyama else
2093837f427SRui Ueyama path::append(s, path1, path2);
210ec75220fSRui Ueyama
2113837f427SRui Ueyama if (fs::exists(s))
2123e24242aSJonas Devlieghere return std::string(s);
213ec75220fSRui Ueyama return None;
214ec75220fSRui Ueyama }
215ec75220fSRui Ueyama
findFromSearchPaths(StringRef path)21607837b8fSFangrui Song Optional<std::string> elf::findFromSearchPaths(StringRef path) {
2173837f427SRui Ueyama for (StringRef dir : config->searchPaths)
2183837f427SRui Ueyama if (Optional<std::string> s = findFile(dir, path))
2193837f427SRui Ueyama return s;
220061f9286SRui Ueyama return None;
221ec75220fSRui Ueyama }
222ec75220fSRui Ueyama
2231d16515fSBen Dunbobbin // This is for -l<basename>. We'll look for lib<basename>.so or lib<basename>.a from
2241cb63183SRui Ueyama // search paths.
searchLibraryBaseName(StringRef name)22507837b8fSFangrui Song Optional<std::string> elf::searchLibraryBaseName(StringRef name) {
2263837f427SRui Ueyama for (StringRef dir : config->searchPaths) {
2273837f427SRui Ueyama if (!config->isStatic)
2283837f427SRui Ueyama if (Optional<std::string> s = findFile(dir, "lib" + name + ".so"))
2293837f427SRui Ueyama return s;
2303837f427SRui Ueyama if (Optional<std::string> s = findFile(dir, "lib" + name + ".a"))
2313837f427SRui Ueyama return s;
232ec75220fSRui Ueyama }
233061f9286SRui Ueyama return None;
2344b02ca99SRui Ueyama }
2351de78471SAlexander Richardson
2361d16515fSBen Dunbobbin // This is for -l<namespec>.
searchLibrary(StringRef name)23707837b8fSFangrui Song Optional<std::string> elf::searchLibrary(StringRef name) {
238439341b9SJames Henderson llvm::TimeTraceScope timeScope("Locate library", name);
2393837f427SRui Ueyama if (name.startswith(":"))
2403837f427SRui Ueyama return findFromSearchPaths(name.substr(1));
2413837f427SRui Ueyama return searchLibraryBaseName(name);
2421d16515fSBen Dunbobbin }
2431d16515fSBen Dunbobbin
244c60f85d0SFangrui Song // If a linker/version script doesn't exist in the current directory, we also
245c60f85d0SFangrui Song // look for the script in the '-L' search paths. This matches the behaviour of
246c60f85d0SFangrui Song // '-T', --version-script=, and linker script INPUT() command in ld.bfd.
searchScript(StringRef name)24707837b8fSFangrui Song Optional<std::string> elf::searchScript(StringRef name) {
2483837f427SRui Ueyama if (fs::exists(name))
2493837f427SRui Ueyama return name.str();
2503837f427SRui Ueyama return findFromSearchPaths(name);
2511de78471SAlexander Richardson }
252