diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2017-01-24 10:17:57 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2017-01-24 10:17:57 +0000 |
commit | 7474d3ea4ce6a30a393508e6bc1bd3abe9c73136 (patch) | |
tree | 8dac78dfe49aa203655d049f50a76f44a8946b40 /gnu/llvm | |
parent | 8b85ece55d580edd744e451b375cb730b3d0ecdb (diff) |
Handle the OpenBSD-style major/minor shared library version scheme.
Don't try to upstream this; we are considering moving to a more standard
way that uses symbolic links to point the linker at the right version of
shared libraries.
Diffstat (limited to 'gnu/llvm')
-rw-r--r-- | gnu/llvm/tools/lld/ELF/DriverUtils.cpp | 245 |
1 files changed, 92 insertions, 153 deletions
diff --git a/gnu/llvm/tools/lld/ELF/DriverUtils.cpp b/gnu/llvm/tools/lld/ELF/DriverUtils.cpp index 3f18259b4ae..2c0b4405ba2 100644 --- a/gnu/llvm/tools/lld/ELF/DriverUtils.cpp +++ b/gnu/llvm/tools/lld/ELF/DriverUtils.cpp @@ -15,14 +15,18 @@ #include "Driver.h" #include "Error.h" +#include "Memory.h" +#include "ScriptParser.h" #include "lld/Config/Version.h" +#include "lld/Core/Reproduce.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" -#include "llvm/Support/StringSaver.h" +#include "llvm/Support/Process.h" using namespace llvm; using namespace llvm::sys; @@ -40,16 +44,37 @@ using namespace lld::elf; // Create table mapping all options defined in Options.td static const opt::OptTable::Info OptInfo[] = { #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \ - { \ - X1, X2, X9, X10, OPT_##ID, opt::Option::KIND##Class, X8, X7, OPT_##GROUP, \ - OPT_##ALIAS, X6 \ - }, + {X1, X2, X9, X10, OPT_##ID, opt::Option::KIND##Class, \ + X8, X7, OPT_##GROUP, OPT_##ALIAS, X6}, #include "Options.inc" #undef OPTION }; ELFOptTable::ELFOptTable() : OptTable(OptInfo) {} +// Parse -color-diagnostics={auto,always,never} or -no-color-diagnostics. +static bool getColorDiagnostics(opt::InputArgList &Args) { + bool Default = (ErrorOS == &errs() && Process::StandardErrHasColors()); + + auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, + OPT_no_color_diagnostics); + if (!Arg) + return Default; + if (Arg->getOption().getID() == OPT_color_diagnostics) + return true; + if (Arg->getOption().getID() == OPT_no_color_diagnostics) + return false; + + StringRef S = Arg->getValue(); + if (S == "auto") + return Default; + if (S == "always") + return true; + if (S != "never") + error("unknown option: -color-diagnostics=" + S); + return false; +} + static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) { if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) { StringRef S = Arg->getValue(); @@ -76,16 +101,16 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) { // --rsp-quoting. opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount); - // Expand response files. '@<filename>' is replaced by the file's contents. - StringSaver Saver(Alloc); + // Expand response files (arguments in the form of @<filename>) + // and then parse the argument again. cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec); - - // Parse options and then do error checking. Args = this->ParseArgs(Vec, MissingIndex, MissingCount); + + // Interpret -color-diagnostics early so that error messages + // for unknown flags are colored. + Config->ColorDiagnostics = getColorDiagnostics(Args); if (MissingCount) - error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) + - "\", expected " + Twine(MissingCount) + - (MissingCount == 1 ? " argument.\n" : " arguments")); + error(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); for (auto *Arg : Args.filtered(OPT_UNKNOWN)) error("unknown argument: " + Arg->getSpelling()); @@ -97,115 +122,6 @@ void elf::printHelp(const char *Argv0) { Table.PrintHelp(outs(), Argv0, "lld", false); } -std::string elf::getVersionString() { - std::string Version = getLLDVersion(); - std::string Repo = getLLDRepositoryVersion(); - if (Repo.empty()) - return "LLD " + Version + "\n"; - return "LLD " + Version + " " + Repo + "\n"; -} - -// Makes a given pathname an absolute path first, and then remove -// beginning /. For example, "../foo.o" is converted to "home/john/foo.o", -// assuming that the current directory is "/home/john/bar". -std::string elf::relativeToRoot(StringRef Path) { - SmallString<128> Abs = Path; - if (std::error_code EC = fs::make_absolute(Abs)) - fatal("make_absolute failed: " + EC.message()); - path::remove_dots(Abs, /*remove_dot_dot=*/true); - - // This is Windows specific. root_name() returns a drive letter - // (e.g. "c:") or a UNC name (//net). We want to keep it as part - // of the result. - SmallString<128> Res; - StringRef Root = path::root_name(Abs); - if (Root.endswith(":")) - Res = Root.drop_back(); - else if (Root.startswith("//")) - Res = Root.substr(2); - - path::append(Res, path::relative_path(Abs)); - return Res.str(); -} - -CpioFile::CpioFile(std::unique_ptr<raw_fd_ostream> OS, StringRef S) - : OS(std::move(OS)), Basename(S) {} - -CpioFile *CpioFile::create(StringRef OutputPath) { - std::string Path = (OutputPath + ".cpio").str(); - std::error_code EC; - auto OS = llvm::make_unique<raw_fd_ostream>(Path, EC, fs::F_None); - if (EC) { - error(EC, "--reproduce: failed to open " + Path); - return nullptr; - } - return new CpioFile(std::move(OS), path::filename(OutputPath)); -} - -static void writeMember(raw_fd_ostream &OS, StringRef Path, StringRef Data) { - // The c_dev/c_ino pair should be unique according to the spec, - // but no one seems to care. - OS << "070707"; // c_magic - OS << "000000"; // c_dev - OS << "000000"; // c_ino - OS << "100664"; // c_mode: C_ISREG | rw-rw-r-- - OS << "000000"; // c_uid - OS << "000000"; // c_gid - OS << "000001"; // c_nlink - OS << "000000"; // c_rdev - OS << "00000000000"; // c_mtime - OS << format("%06o", Path.size() + 1); // c_namesize - OS << format("%011o", Data.size()); // c_filesize - OS << Path << '\0'; // c_name - OS << Data; // c_filedata -} - -void CpioFile::append(StringRef Path, StringRef Data) { - if (!Seen.insert(Path).second) - return; - - // Construct an in-archive filename so that /home/foo/bar is stored - // as baz/home/foo/bar where baz is the basename of the output file. - // (i.e. in that case we are creating baz.cpio.) - SmallString<128> Fullpath; - path::append(Fullpath, Basename, Path); - - // Use unix path separators so the cpio can be extracted on both unix and - // windows. - std::replace(Fullpath.begin(), Fullpath.end(), '\\', '/'); - - writeMember(*OS, Fullpath, Data); - - // Print the trailer and seek back. - // This way we have a valid archive if we crash. - uint64_t Pos = OS->tell(); - writeMember(*OS, "TRAILER!!!", ""); - OS->seek(Pos); -} - -// Quote a given string if it contains a space character. -static std::string quote(StringRef S) { - if (S.find(' ') == StringRef::npos) - return S; - return ("\"" + S + "\"").str(); -} - -static std::string rewritePath(StringRef S) { - if (fs::exists(S)) - return relativeToRoot(S); - return S; -} - -static std::string stringize(opt::Arg *Arg) { - std::string K = Arg->getSpelling(); - if (Arg->getNumValues() == 0) - return K; - std::string V = quote(Arg->getValue()); - if (Arg->getOption().getRenderStyle() == opt::Option::RenderJoinedStyle) - return K + V; - return K + " " + V; -} - // Reconstructs command line arguments so that so that you can re-run // the same command with the same inputs. This is for --reproduce. std::string elf::createResponseFile(const opt::InputArgList &Args) { @@ -226,51 +142,74 @@ std::string elf::createResponseFile(const opt::InputArgList &Args) { case OPT_alias_script_T: case OPT_script: case OPT_version_script: - OS << Arg->getSpelling() << " " - << quote(rewritePath(Arg->getValue())) << "\n"; + OS << Arg->getSpelling() << " " << quote(rewritePath(Arg->getValue())) + << "\n"; break; default: - OS << stringize(Arg) << "\n"; + OS << toString(Arg) << "\n"; } } return Data.str(); } -std::string elf::findFromSearchPaths(StringRef Path) { - for (StringRef Dir : Config->SearchPaths) { - std::string FullPath = buildSysrootedPath(Dir, Path); - if (fs::exists(FullPath)) - return FullPath; - } - return ""; +// Find a file by concatenating given paths. If a resulting path +// starts with "=", the character is replaced with a --sysroot value. +static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) { + SmallString<128> S; + if (Path1.startswith("=")) + path::append(S, Config->Sysroot, Path1.substr(1), Path2); + else + path::append(S, Path1, Path2); + + if (fs::exists(S)) + return S.str().str(); + return None; +} + +Optional<std::string> elf::findFromSearchPaths(StringRef Path) { + for (StringRef Dir : Config->SearchPaths) + if (Optional<std::string> S = findFile(Dir, Path)) + return S; + return None; } -// Searches a given library from input search paths, which are filled -// from -L command line switches. Returns a path to an existent library file. -std::string elf::searchLibrary(StringRef Path) { - if (Path.startswith(":")) - return findFromSearchPaths(Path.substr(1)); +// This is for -lfoo. We'll look for libfoo.so or libfoo.a from +// search paths. +Optional<std::string> elf::searchLibrary(StringRef Name) { + if (Name.startswith(":")) + return findFromSearchPaths(Name.substr(1)); + for (StringRef Dir : Config->SearchPaths) { if (!Config->Static) { - std::string S = buildSysrootedPath(Dir, ("lib" + Path + ".so").str()); - if (fs::exists(S)) + if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".so")) return S; + + const StringRef LibName = (Twine("lib") + Name + ".so.").str(); + int MaxMaj = -1, MaxMin = -1; + std::error_code EC; + for (fs::directory_iterator LI(Dir, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef FilePath = LI->path(); + StringRef FileName = path::filename(FilePath); + if (!(FileName.startswith(LibName))) + continue; + std::pair<StringRef, StringRef> MajMin = + FileName.substr(LibName.size()).split('.'); + int Maj, Min; + if (MajMin.first.getAsInteger(10, Maj) || Maj < 0) + continue; + if (MajMin.second.getAsInteger(10, Min) || Min < 0) + continue; + if (Maj > MaxMaj) + MaxMaj = Maj, MaxMin = Min; + if (MaxMaj == Maj && Min > MaxMin) + MaxMin = Min; + } + if (MaxMaj >= 0) + return findFile(Dir, LibName + Twine(MaxMaj) + "." + Twine(MaxMin)); } - std::string S = buildSysrootedPath(Dir, ("lib" + Path + ".a").str()); - if (fs::exists(S)) + if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a")) return S; } - return ""; -} - -// Makes a path by concatenating Dir and File. -// If Dir starts with '=' the result will be preceded by Sysroot, -// which can be set with --sysroot command line switch. -std::string elf::buildSysrootedPath(StringRef Dir, StringRef File) { - SmallString<128> Path; - if (Dir.startswith("=")) - path::append(Path, Config->Sysroot, Dir.substr(1), File); - else - path::append(Path, Dir, File); - return Path.str(); + return None; } |