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