diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h --- a/lld/COFF/Driver.h +++ b/lld/COFF/Driver.h @@ -21,6 +21,7 @@ #include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/TarWriter.h" +#include "llvm/WindowsDriver/LLVMPaths.h" #include "llvm/WindowsDriver/MSVCPaths.h" #include #include @@ -84,6 +85,9 @@ // config->machine has been set. void addWinSysRootLibSearchPaths(); + // Add runtimes and library paths from our toolchain path + void addLLVMSearchPaths(); + // Used by the resolver to parse .drectve section contents. void parseDirectives(InputFile *file); @@ -116,6 +120,7 @@ StringRef mangle(StringRef sym); llvm::Triple::ArchType getArch(); + llvm::Triple constructTriple(); uint64_t getDefaultImageBase(); diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -473,6 +473,7 @@ SmallString<128> path = dir; sys::path::append(path, filename); path = SmallString<128>{getFilename(path.str())}; + llvm::outs() << path << "\n"; if (sys::fs::exists(path.str())) return saver().save(path.str()); if (!hasExt) { @@ -648,6 +649,52 @@ } } +llvm::Triple LinkerDriver::constructTriple() { + llvm::Triple t; + t.setOS(llvm::Triple::OSType::Win32); + t.setVendor(llvm::Triple::VendorType::PC); + t.setEnvironment(ctx.config.mingw ? llvm::Triple::EnvironmentType::GNU : llvm::Triple::EnvironmentType::MSVC); + + switch (ctx.config.machine) { + case I386: + t.setArch(llvm::Triple::ArchType::x86); + break; + case AMD64: + t.setArch(llvm::Triple::ArchType::x86_64); + break; + case ARMNT: + t.setArch(llvm::Triple::ArchType::arm); + break; + case ARM64: + t.setArch(llvm::Triple::ArchType::aarch64); + break; + default: + t.setArch(llvm::Triple::ArchType::UnknownArch); + } + + return t; +} + +void LinkerDriver::addLLVMSearchPaths() { + static int dummy; + std::string lldBinary = llvm::sys::fs::getMainExecutable("lld", (void *)&dummy); + llvm::Triple t = constructTriple(); + llvm::outs() << t.getTriple() << "\n"; + for (const auto & p : getToolchainLibDirs(lldBinary, t)) { + if (llvm::sys::fs::exists(p) && llvm::sys::fs::is_directory(p)) { + llvm::outs() << p << "\n"; + searchPaths.push_back(saver().save(p)); + } + } + + for (const auto & p : getToolchainRuntimeDirs(lldBinary, t)) { + if (llvm::sys::fs::exists(p) && llvm::sys::fs::is_directory(p)) { + llvm::outs() << p << "\n"; + searchPaths.push_back(saver().save(p)); + } + } +} + // Parses LIB environment which contains a list of search paths. void LinkerDriver::addLibSearchPaths() { std::optional envOpt = Process::GetEnv("LIB"); @@ -1663,6 +1710,7 @@ if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) fatal(Twine("unknown /machine argument: ") + arg->getValue()); addWinSysRootLibSearchPaths(); + addLLVMSearchPaths(); } // Handle /nodefaultlib: @@ -2027,6 +2075,7 @@ warn("/machine is not specified. x64 is assumed"); config->machine = AMD64; addWinSysRootLibSearchPaths(); + addLLVMSearchPaths(); } config->wordsize = config->is64() ? 8 : 4; @@ -2042,7 +2091,7 @@ // Handle /RELEASE if (args.hasArg(OPT_release)) config->writeCheckSum = true; - + // Handle /safeseh, x86 only, on by default, except for mingw. if (config->machine == I386) { config->safeSEH = args.hasFlag(OPT_safeseh, OPT_safeseh_no, !config->mingw); diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -56,6 +56,7 @@ if (ctx.config.machine == IMAGE_FILE_MACHINE_UNKNOWN) { ctx.config.machine = mt; ctx.driver.addWinSysRootLibSearchPaths(); + ctx.driver.addLLVMSearchPaths(); } else if (mt != IMAGE_FILE_MACHINE_UNKNOWN && ctx.config.machine != mt) { error(toString(file) + ": machine type " + machineToStr(mt) + " conflicts with " + machineToStr(ctx.config.machine)); diff --git a/llvm/include/llvm/WindowsDriver/LLVMPaths.h b/llvm/include/llvm/WindowsDriver/LLVMPaths.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/WindowsDriver/LLVMPaths.h @@ -0,0 +1,26 @@ + +//===-- LLVMPaths.h - Paths to resource dir and runtimes ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_WINDOWSDRIVER_LLVMPATHS_H +#define LLVM_WINDOWSDRIVER_LLVMPATHS_H + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/TargetParser/Triple.h" + +namespace llvm { + +llvm::SmallVector +getToolchainRuntimeDirs(llvm::StringRef BinaryPath, llvm::Triple Triple); +llvm::SmallVector getToolchainLibDirs(llvm::StringRef BinaryPath, + llvm::Triple Triple); + +} // namespace llvm + +#endif \ No newline at end of file diff --git a/llvm/lib/WindowsDriver/CMakeLists.txt b/llvm/lib/WindowsDriver/CMakeLists.txt --- a/llvm/lib/WindowsDriver/CMakeLists.txt +++ b/llvm/lib/WindowsDriver/CMakeLists.txt @@ -1,5 +1,6 @@ add_llvm_component_library(LLVMWindowsDriver MSVCPaths.cpp + LLVMPaths.cpp ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/WindowsDriver diff --git a/llvm/lib/WindowsDriver/LLVMPaths.cpp b/llvm/lib/WindowsDriver/LLVMPaths.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/WindowsDriver/LLVMPaths.cpp @@ -0,0 +1,109 @@ +//===-- LLVMPaths.cpp - Paths to resource dir and runtimes +//-----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include + +#include "llvm/Config/llvm-config.h" + +#define STRINGIFY(X) (#X) +#define TOSTRING(X) STRINGIFY(X) + +static std::string getResourcePath(llvm::StringRef BinaryPath, + llvm::StringRef CustomResourceDir) { + // Since the resource directory is embedded in the module hash, it's important + // that all places that need it call this function, so that they get the + // exact same string ("a/../b/" and "b/" get different hashes, for example). + + // Dir is bin/ or lib/, depending on where BinaryPath is. + std::string Dir = std::string(llvm::sys::path::parent_path(BinaryPath)); + + llvm::SmallString<128> P(Dir); + if (CustomResourceDir != "") { + llvm::sys::path::append(P, CustomResourceDir); + } else { + // On Windows, libclang.dll is in bin/. + // On non-Windows, libclang.so/.dylib is in lib/. + // With a static-library build of libclang, LibClangPath will contain the + // path of the embedding binary, which for LLVM binaries will be in bin/. + // ../lib gets us to lib/ in both cases. + P = llvm::sys::path::parent_path(Dir); + + // TODO: in clang we use CLANG_INSTALL_LIBDIR_BASENAME instead of defaulting + // to lib - but we don't have that macro available in LLVM. + llvm::sys::path::append(P, "lib", "clang", TOSTRING(LLVM_VERSION_MAJOR)); + } + + return std::string(P.str()); +} + +static llvm::StringRef getToolchainOSLibName(llvm::Triple Triple) { + if (Triple.isOSDarwin()) + return "darwin"; + + switch (Triple.getOS()) { + case llvm::Triple::FreeBSD: + return "freebsd"; + case llvm::Triple::NetBSD: + return "netbsd"; + case llvm::Triple::OpenBSD: + return "openbsd"; + case llvm::Triple::Solaris: + return "sunos"; + case llvm::Triple::AIX: + return "aix"; + default: + return Triple.getOSName(); + } +} + +namespace llvm { + +llvm::SmallVector +getToolchainRuntimeDirs(llvm::StringRef BinaryPath, llvm::Triple Triple) { + llvm::SmallVector Paths; + + std::string RP(getResourcePath(BinaryPath, "")); + llvm::SmallString<128> P(RP); + llvm::sys::path::append(P, "lib", Triple.getTriple()); + + Paths.push_back(std::string(P)); + + P = RP; + llvm::sys::path::append(P, "lib", getToolchainOSLibName(Triple)); + Paths.push_back(std::string(P)); + + return Paths; +} + +llvm::SmallVector getToolchainLibDirs(llvm::StringRef BinaryPath, + llvm::Triple Triple) { + llvm::SmallVector Paths; + + llvm::SmallString<128> RP( + llvm::sys::path::parent_path(llvm::sys::path::parent_path(BinaryPath))); + llvm::sys::path::append(RP, "lib"); + + // /lib + llvm::SmallString<122> P(RP); + Paths.push_back(std::string(P)); + + // Reset + P = RP; + + // /lib/ + llvm::sys::path::append(P, Triple.getTriple()); + Paths.push_back(std::string(P)); + return Paths; +} + +} // namespace llvm \ No newline at end of file