Revert "[lld/coff] Make lld-link work in a non-MSVC shell, add /winsysroot:"

This reverts commit b3b2538df1,
it introduced a cycklic module depenency that broke the -DLLVM_ENABLE_MODULES=1 build.
This commit is contained in:
Adrian Prantl 2022-02-11 13:02:28 -08:00
parent d5c314cdf4
commit baac665adf
15 changed files with 751 additions and 1057 deletions

View File

@ -285,6 +285,7 @@ clang/lib/Driver/ToolChains/InterfaceStubs.h
clang/lib/Driver/ToolChains/Minix.h
clang/lib/Driver/ToolChains/MipsLinux.cpp
clang/lib/Driver/ToolChains/MSP430.h
clang/lib/Driver/ToolChains/MSVCSetupApi.h
clang/lib/Driver/ToolChains/PPCFreeBSD.cpp
clang/lib/Driver/ToolChains/PPCFreeBSD.h
clang/lib/Driver/ToolChains/PPCLinux.h
@ -5149,8 +5150,6 @@ llvm/include/llvm/Support/MemoryBufferRef.h
llvm/include/llvm/Support/MSP430AttributeParser.h
llvm/include/llvm/Support/MSP430Attributes.h
llvm/include/llvm/Support/MSVCErrorWorkarounds.h
llvm/include/llvm/Support/MSVCPaths.h
llvm/include/llvm/Support/MSVCSetupApi.h
llvm/include/llvm/Support/Parallel.h
llvm/include/llvm/Support/PGOOptions.h
llvm/include/llvm/Support/PointerLikeTypeTraits.h
@ -5841,7 +5840,6 @@ llvm/lib/Support/Memory.cpp
llvm/lib/Support/MemoryBufferRef.cpp
llvm/lib/Support/MSP430AttributeParser.cpp
llvm/lib/Support/MSP430Attributes.cpp
llvm/lib/Support/MSVCPaths.cpp
llvm/lib/Support/Optional.cpp
llvm/lib/Support/Parallel.cpp
llvm/lib/Support/Program.cpp

View File

@ -25,7 +25,6 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MSVCPaths.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
@ -41,12 +40,91 @@
#include <windows.h>
#endif
#ifdef _MSC_VER
// Don't support SetupApi on MinGW.
#define USE_MSVC_SETUP_API
// Make sure this comes before MSVCSetupApi.h
#include <comdef.h>
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
#endif
#include "MSVCSetupApi.h"
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#include "llvm/Support/COM.h"
_COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration));
_COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2));
_COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper));
_COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances));
_COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance));
_COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2));
#endif
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
// Windows SDKs and VC Toolchains group their contents into subdirectories based
// on the target architecture. This function converts an llvm::Triple::ArchType
// to the corresponding subdirectory name.
static const char *llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch) {
using ArchType = llvm::Triple::ArchType;
switch (Arch) {
case ArchType::x86:
return "x86";
case ArchType::x86_64:
return "x64";
case ArchType::arm:
return "arm";
case ArchType::aarch64:
return "arm64";
default:
return "";
}
}
// Similar to the above function, but for Visual Studios before VS2017.
static const char *llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch) {
using ArchType = llvm::Triple::ArchType;
switch (Arch) {
case ArchType::x86:
// x86 is default in legacy VC toolchains.
// e.g. x86 libs are directly in /lib as opposed to /lib/x86.
return "";
case ArchType::x86_64:
return "amd64";
case ArchType::arm:
return "arm";
case ArchType::aarch64:
return "arm64";
default:
return "";
}
}
// Similar to the above function, but for DevDiv internal builds.
static const char *llvmArchToDevDivInternalArch(llvm::Triple::ArchType Arch) {
using ArchType = llvm::Triple::ArchType;
switch (Arch) {
case ArchType::x86:
return "i386";
case ArchType::x86_64:
return "amd64";
case ArchType::arm:
return "arm";
case ArchType::aarch64:
return "arm64";
default:
return "";
}
}
static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) {
auto Status = VFS.status(Path);
if (!Status)
@ -54,6 +132,294 @@ static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) {
return (Status->getPermissions() & llvm::sys::fs::perms::all_exe) != 0;
}
// Defined below.
// Forward declare this so there aren't too many things above the constructor.
static bool getSystemRegistryString(const char *keyPath, const char *valueName,
std::string &value, std::string *phValue);
static std::string getHighestNumericTupleInDirectory(llvm::vfs::FileSystem &VFS,
StringRef Directory) {
std::string Highest;
llvm::VersionTuple HighestTuple;
std::error_code EC;
for (llvm::vfs::directory_iterator DirIt = VFS.dir_begin(Directory, EC),
DirEnd;
!EC && DirIt != DirEnd; DirIt.increment(EC)) {
auto Status = VFS.status(DirIt->path());
if (!Status || !Status->isDirectory())
continue;
StringRef CandidateName = llvm::sys::path::filename(DirIt->path());
llvm::VersionTuple Tuple;
if (Tuple.tryParse(CandidateName)) // tryParse() returns true on error.
continue;
if (Tuple > HighestTuple) {
HighestTuple = Tuple;
Highest = CandidateName.str();
}
}
return Highest;
}
// Check command line arguments to try and find a toolchain.
static bool
findVCToolChainViaCommandLine(llvm::vfs::FileSystem &VFS, const ArgList &Args,
std::string &Path,
MSVCToolChain::ToolsetLayout &VSLayout) {
// Don't validate the input; trust the value supplied by the user.
// The primary motivation is to prevent unnecessary file and registry access.
if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir,
options::OPT__SLASH_winsysroot)) {
if (A->getOption().getID() == options::OPT__SLASH_winsysroot) {
llvm::SmallString<128> ToolsPath(A->getValue());
llvm::sys::path::append(ToolsPath, "VC", "Tools", "MSVC");
std::string VCToolsVersion;
if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion))
VCToolsVersion = A->getValue();
else
VCToolsVersion = getHighestNumericTupleInDirectory(VFS, ToolsPath);
llvm::sys::path::append(ToolsPath, VCToolsVersion);
Path = std::string(ToolsPath.str());
} else {
Path = A->getValue();
}
VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
return true;
}
return false;
}
// Check various environment variables to try and find a toolchain.
static bool
findVCToolChainViaEnvironment(llvm::vfs::FileSystem &VFS, std::string &Path,
MSVCToolChain::ToolsetLayout &VSLayout) {
// These variables are typically set by vcvarsall.bat
// when launching a developer command prompt.
if (llvm::Optional<std::string> VCToolsInstallDir =
llvm::sys::Process::GetEnv("VCToolsInstallDir")) {
// This is only set by newer Visual Studios, and it leads straight to
// the toolchain directory.
Path = std::move(*VCToolsInstallDir);
VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
return true;
}
if (llvm::Optional<std::string> VCInstallDir =
llvm::sys::Process::GetEnv("VCINSTALLDIR")) {
// If the previous variable isn't set but this one is, then we've found
// an older Visual Studio. This variable is set by newer Visual Studios too,
// so this check has to appear second.
// In older Visual Studios, the VC directory is the toolchain.
Path = std::move(*VCInstallDir);
VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
return true;
}
// We couldn't find any VC environment variables. Let's walk through PATH and
// see if it leads us to a VC toolchain bin directory. If it does, pick the
// first one that we find.
if (llvm::Optional<std::string> PathEnv =
llvm::sys::Process::GetEnv("PATH")) {
llvm::SmallVector<llvm::StringRef, 8> PathEntries;
llvm::StringRef(*PathEnv).split(PathEntries, llvm::sys::EnvPathSeparator);
for (llvm::StringRef PathEntry : PathEntries) {
if (PathEntry.empty())
continue;
llvm::SmallString<256> ExeTestPath;
// If cl.exe doesn't exist, then this definitely isn't a VC toolchain.
ExeTestPath = PathEntry;
llvm::sys::path::append(ExeTestPath, "cl.exe");
if (!VFS.exists(ExeTestPath))
continue;
// cl.exe existing isn't a conclusive test for a VC toolchain; clang also
// has a cl.exe. So let's check for link.exe too.
ExeTestPath = PathEntry;
llvm::sys::path::append(ExeTestPath, "link.exe");
if (!VFS.exists(ExeTestPath))
continue;
// whatever/VC/bin --> old toolchain, VC dir is toolchain dir.
llvm::StringRef TestPath = PathEntry;
bool IsBin =
llvm::sys::path::filename(TestPath).equals_insensitive("bin");
if (!IsBin) {
// Strip any architecture subdir like "amd64".
TestPath = llvm::sys::path::parent_path(TestPath);
IsBin = llvm::sys::path::filename(TestPath).equals_insensitive("bin");
}
if (IsBin) {
llvm::StringRef ParentPath = llvm::sys::path::parent_path(TestPath);
llvm::StringRef ParentFilename = llvm::sys::path::filename(ParentPath);
if (ParentFilename.equals_insensitive("VC")) {
Path = std::string(ParentPath);
VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
return true;
}
if (ParentFilename.equals_insensitive("x86ret") ||
ParentFilename.equals_insensitive("x86chk") ||
ParentFilename.equals_insensitive("amd64ret") ||
ParentFilename.equals_insensitive("amd64chk")) {
Path = std::string(ParentPath);
VSLayout = MSVCToolChain::ToolsetLayout::DevDivInternal;
return true;
}
} else {
// This could be a new (>=VS2017) toolchain. If it is, we should find
// path components with these prefixes when walking backwards through
// the path.
// Note: empty strings match anything.
llvm::StringRef ExpectedPrefixes[] = {"", "Host", "bin", "",
"MSVC", "Tools", "VC"};
auto It = llvm::sys::path::rbegin(PathEntry);
auto End = llvm::sys::path::rend(PathEntry);
for (llvm::StringRef Prefix : ExpectedPrefixes) {
if (It == End)
goto NotAToolChain;
if (!It->startswith_insensitive(Prefix))
goto NotAToolChain;
++It;
}
// We've found a new toolchain!
// Back up 3 times (/bin/Host/arch) to get the root path.
llvm::StringRef ToolChainPath(PathEntry);
for (int i = 0; i < 3; ++i)
ToolChainPath = llvm::sys::path::parent_path(ToolChainPath);
Path = std::string(ToolChainPath);
VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
return true;
}
NotAToolChain:
continue;
}
}
return false;
}
// Query the Setup Config server for installs, then pick the newest version
// and find its default VC toolchain.
// This is the preferred way to discover new Visual Studios, as they're no
// longer listed in the registry.
static bool
findVCToolChainViaSetupConfig(llvm::vfs::FileSystem &VFS, std::string &Path,
MSVCToolChain::ToolsetLayout &VSLayout) {
#if !defined(USE_MSVC_SETUP_API)
return false;
#else
// FIXME: This really should be done once in the top-level program's main
// function, as it may have already been initialized with a different
// threading model otherwise.
llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::SingleThreaded);
HRESULT HR;
// _com_ptr_t will throw a _com_error if a COM calls fail.
// The LLVM coding standards forbid exception handling, so we'll have to
// stop them from being thrown in the first place.
// The destructor will put the regular error handler back when we leave
// this scope.
struct SuppressCOMErrorsRAII {
static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {}
SuppressCOMErrorsRAII() { _set_com_error_handler(handler); }
~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); }
} COMErrorSuppressor;
ISetupConfigurationPtr Query;
HR = Query.CreateInstance(__uuidof(SetupConfiguration));
if (FAILED(HR))
return false;
IEnumSetupInstancesPtr EnumInstances;
HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances);
if (FAILED(HR))
return false;
ISetupInstancePtr Instance;
HR = EnumInstances->Next(1, &Instance, nullptr);
if (HR != S_OK)
return false;
ISetupInstancePtr NewestInstance;
Optional<uint64_t> NewestVersionNum;
do {
bstr_t VersionString;
uint64_t VersionNum;
HR = Instance->GetInstallationVersion(VersionString.GetAddress());
if (FAILED(HR))
continue;
HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum);
if (FAILED(HR))
continue;
if (!NewestVersionNum || (VersionNum > NewestVersionNum)) {
NewestInstance = Instance;
NewestVersionNum = VersionNum;
}
} while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK);
if (!NewestInstance)
return false;
bstr_t VCPathWide;
HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress());
if (FAILED(HR))
return false;
std::string VCRootPath;
llvm::convertWideToUTF8(std::wstring(VCPathWide), VCRootPath);
llvm::SmallString<256> ToolsVersionFilePath(VCRootPath);
llvm::sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build",
"Microsoft.VCToolsVersion.default.txt");
auto ToolsVersionFile = llvm::MemoryBuffer::getFile(ToolsVersionFilePath);
if (!ToolsVersionFile)
return false;
llvm::SmallString<256> ToolchainPath(VCRootPath);
llvm::sys::path::append(ToolchainPath, "Tools", "MSVC",
ToolsVersionFile->get()->getBuffer().rtrim());
auto Status = VFS.status(ToolchainPath);
if (!Status || !Status->isDirectory())
return false;
Path = std::string(ToolchainPath.str());
VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
return true;
#endif
}
// Look in the registry for Visual Studio installs, and use that to get
// a toolchain path. VS2017 and newer don't get added to the registry.
// So if we find something here, we know that it's an older version.
static bool findVCToolChainViaRegistry(std::string &Path,
MSVCToolChain::ToolsetLayout &VSLayout) {
std::string VSInstallPath;
if (getSystemRegistryString(R"(SOFTWARE\Microsoft\VisualStudio\$VERSION)",
"InstallDir", VSInstallPath, nullptr) ||
getSystemRegistryString(R"(SOFTWARE\Microsoft\VCExpress\$VERSION)",
"InstallDir", VSInstallPath, nullptr)) {
if (!VSInstallPath.empty()) {
llvm::SmallString<256> VCPath(llvm::StringRef(
VSInstallPath.c_str(), VSInstallPath.find(R"(\Common7\IDE)")));
llvm::sys::path::append(VCPath, "VC");
Path = std::string(VCPath.str());
VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
return true;
}
}
return false;
}
// Try to find Exe from a Visual Studio distribution. This first tries to find
// an installed copy of Visual Studio and, failing that, looks in the PATH,
// making sure that whatever executable that's found is not a same-named exe
@ -61,8 +427,8 @@ static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) {
static std::string FindVisualStudioExecutable(const ToolChain &TC,
const char *Exe) {
const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);
SmallString<128> FilePath(
MSVC.getSubDirectoryPath(llvm::SubDirectoryType::Bin));
SmallString<128> FilePath(MSVC.getSubDirectoryPath(
toolchains::MSVCToolChain::SubDirectoryType::Bin));
llvm::sys::path::append(FilePath, Exe);
return std::string(canExecute(TC.getVFS(), FilePath) ? FilePath.str() : Exe);
}
@ -103,7 +469,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// The DIA SDK always uses the legacy vc arch, even in new MSVC versions.
llvm::sys::path::append(DIAPath, "lib",
llvm::archToLegacyVCArch(TC.getArch()));
llvmArchToLegacyVCArch(TC.getArch()));
CmdArgs.push_back(Args.MakeArgString(Twine("-libpath:") + DIAPath));
}
if (!llvm::sys::Process::GetEnv("LIB") ||
@ -111,10 +477,12 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT__SLASH_winsysroot)) {
CmdArgs.push_back(Args.MakeArgString(
Twine("-libpath:") +
TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib)));
TC.getSubDirectoryPath(
toolchains::MSVCToolChain::SubDirectoryType::Lib)));
CmdArgs.push_back(Args.MakeArgString(
Twine("-libpath:") +
TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib, "atlmfc")));
TC.getSubDirectoryPath(toolchains::MSVCToolChain::SubDirectoryType::Lib,
"atlmfc")));
}
if (!llvm::sys::Process::GetEnv("LIB") ||
Args.getLastArg(options::OPT__SLASH_winsdkdir,
@ -327,7 +695,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// native target bin directory.
// e.g. when compiling for x86 on an x64 host, PATH should start with:
// /bin/Hostx64/x86;/bin/Hostx64/x64
// This doesn't attempt to handle llvm::ToolsetLayout::DevDivInternal.
// This doesn't attempt to handle ToolsetLayout::DevDivInternal.
if (TC.getIsVS2017OrNewer() &&
llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) {
auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch();
@ -362,12 +730,13 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) {
llvm::StringRef EnvVar(Cursor);
if (EnvVar.startswith_insensitive("path=")) {
using SubDirectoryType = toolchains::MSVCToolChain::SubDirectoryType;
constexpr size_t PrefixLen = 5; // strlen("path=")
Environment.push_back(Args.MakeArgString(
EnvVar.substr(0, PrefixLen) +
TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin) +
TC.getSubDirectoryPath(SubDirectoryType::Bin) +
llvm::Twine(llvm::sys::EnvPathSeparator) +
TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin, HostArch) +
TC.getSubDirectoryPath(SubDirectoryType::Bin, "", HostArch) +
(EnvVar.size() > PrefixLen
? llvm::Twine(llvm::sys::EnvPathSeparator) +
EnvVar.substr(PrefixLen)
@ -400,29 +769,14 @@ MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
llvm::StringRef VCToolsDir, VCToolsVersion;
if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir))
VCToolsDir = A->getValue();
if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion))
VCToolsVersion = A->getValue();
if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir))
WinSdkDir = A->getValue();
if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion))
WinSdkVersion = A->getValue();
if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsysroot))
WinSysRoot = A->getValue();
// Check the command line first, that's the user explicitly telling us what to
// use. Check the environment next, in case we're being invoked from a VS
// command prompt. Failing that, just try to find the newest Visual Studio
// version we can and use its default VC toolchain.
llvm::findVCToolChainViaCommandLine(getVFS(), VCToolsDir, VCToolsVersion,
WinSysRoot, VCToolChainPath, VSLayout) ||
llvm::findVCToolChainViaEnvironment(getVFS(), VCToolChainPath,
VSLayout) ||
llvm::findVCToolChainViaSetupConfig(getVFS(), VCToolChainPath,
VSLayout) ||
llvm::findVCToolChainViaRegistry(VCToolChainPath, VSLayout);
findVCToolChainViaCommandLine(getVFS(), Args, VCToolChainPath, VSLayout) ||
findVCToolChainViaEnvironment(getVFS(), VCToolChainPath, VSLayout) ||
findVCToolChainViaSetupConfig(getVFS(), VCToolChainPath, VSLayout) ||
findVCToolChainViaRegistry(VCToolChainPath, VSLayout);
}
Tool *MSVCToolChain::buildLinker() const {
@ -481,48 +835,355 @@ void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const {
RocmInstallation.print(OS);
}
// Get the path to a specific subdirectory in the current toolchain for
// a given target architecture.
// VS2017 changed the VC toolchain layout, so this should be used instead
// of hardcoding paths.
std::string
MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type,
llvm::StringRef SubdirParent) const {
return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, getArch(),
SubdirParent);
MSVCToolChain::getSubDirectoryPath(SubDirectoryType Type,
llvm::StringRef SubdirParent,
llvm::Triple::ArchType TargetArch) const {
const char *SubdirName;
const char *IncludeName;
switch (VSLayout) {
case ToolsetLayout::OlderVS:
SubdirName = llvmArchToLegacyVCArch(TargetArch);
IncludeName = "include";
break;
case ToolsetLayout::VS2017OrNewer:
SubdirName = llvmArchToWindowsSDKArch(TargetArch);
IncludeName = "include";
break;
case ToolsetLayout::DevDivInternal:
SubdirName = llvmArchToDevDivInternalArch(TargetArch);
IncludeName = "inc";
break;
}
llvm::SmallString<256> Path(VCToolChainPath);
if (!SubdirParent.empty())
llvm::sys::path::append(Path, SubdirParent);
switch (Type) {
case SubDirectoryType::Bin:
if (VSLayout == ToolsetLayout::VS2017OrNewer) {
const bool HostIsX64 =
llvm::Triple(llvm::sys::getProcessTriple()).isArch64Bit();
const char *const HostName = HostIsX64 ? "Hostx64" : "Hostx86";
llvm::sys::path::append(Path, "bin", HostName, SubdirName);
} else { // OlderVS or DevDivInternal
llvm::sys::path::append(Path, "bin", SubdirName);
}
break;
case SubDirectoryType::Include:
llvm::sys::path::append(Path, IncludeName);
break;
case SubDirectoryType::Lib:
llvm::sys::path::append(Path, "lib", SubdirName);
break;
}
return std::string(Path.str());
}
std::string
MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type,
llvm::Triple::ArchType TargetArch) const {
return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, TargetArch,
"");
#ifdef _WIN32
static bool readFullStringValue(HKEY hkey, const char *valueName,
std::string &value) {
std::wstring WideValueName;
if (!llvm::ConvertUTF8toWide(valueName, WideValueName))
return false;
DWORD result = 0;
DWORD valueSize = 0;
DWORD type = 0;
// First just query for the required size.
result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, &type, NULL,
&valueSize);
if (result != ERROR_SUCCESS || type != REG_SZ || !valueSize)
return false;
std::vector<BYTE> buffer(valueSize);
result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, NULL, &buffer[0],
&valueSize);
if (result == ERROR_SUCCESS) {
std::wstring WideValue(reinterpret_cast<const wchar_t *>(buffer.data()),
valueSize / sizeof(wchar_t));
if (valueSize && WideValue.back() == L'\0') {
WideValue.pop_back();
}
// The destination buffer must be empty as an invariant of the conversion
// function; but this function is sometimes called in a loop that passes in
// the same buffer, however. Simply clear it out so we can overwrite it.
value.clear();
return llvm::convertWideToUTF8(WideValue, value);
}
return false;
}
#endif
/// Read registry string.
/// This also supports a means to look for high-versioned keys by use
/// of a $VERSION placeholder in the key path.
/// $VERSION in the key path is a placeholder for the version number,
/// causing the highest value path to be searched for and used.
/// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
/// There can be additional characters in the component. Only the numeric
/// characters are compared. This function only searches HKLM.
static bool getSystemRegistryString(const char *keyPath, const char *valueName,
std::string &value, std::string *phValue) {
#ifndef _WIN32
return false;
#else
HKEY hRootKey = HKEY_LOCAL_MACHINE;
HKEY hKey = NULL;
long lResult;
bool returnValue = false;
const char *placeHolder = strstr(keyPath, "$VERSION");
std::string bestName;
// If we have a $VERSION placeholder, do the highest-version search.
if (placeHolder) {
const char *keyEnd = placeHolder - 1;
const char *nextKey = placeHolder;
// Find end of previous key.
while ((keyEnd > keyPath) && (*keyEnd != '\\'))
keyEnd--;
// Find end of key containing $VERSION.
while (*nextKey && (*nextKey != '\\'))
nextKey++;
size_t partialKeyLength = keyEnd - keyPath;
char partialKey[256];
if (partialKeyLength >= sizeof(partialKey))
partialKeyLength = sizeof(partialKey) - 1;
strncpy(partialKey, keyPath, partialKeyLength);
partialKey[partialKeyLength] = '\0';
HKEY hTopKey = NULL;
lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY,
&hTopKey);
if (lResult == ERROR_SUCCESS) {
char keyName[256];
double bestValue = 0.0;
DWORD index, size = sizeof(keyName) - 1;
for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, NULL,
NULL, NULL) == ERROR_SUCCESS;
index++) {
const char *sp = keyName;
while (*sp && !isDigit(*sp))
sp++;
if (!*sp)
continue;
const char *ep = sp + 1;
while (*ep && (isDigit(*ep) || (*ep == '.')))
ep++;
char numBuf[32];
strncpy(numBuf, sp, sizeof(numBuf) - 1);
numBuf[sizeof(numBuf) - 1] = '\0';
double dvalue = strtod(numBuf, NULL);
if (dvalue > bestValue) {
// Test that InstallDir is indeed there before keeping this index.
// Open the chosen key path remainder.
bestName = keyName;
// Append rest of key.
bestName.append(nextKey);
lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0,
KEY_READ | KEY_WOW64_32KEY, &hKey);
if (lResult == ERROR_SUCCESS) {
if (readFullStringValue(hKey, valueName, value)) {
bestValue = dvalue;
if (phValue)
*phValue = bestName;
returnValue = true;
}
RegCloseKey(hKey);
}
}
size = sizeof(keyName) - 1;
}
RegCloseKey(hTopKey);
}
} else {
lResult =
RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey);
if (lResult == ERROR_SUCCESS) {
if (readFullStringValue(hKey, valueName, value))
returnValue = true;
if (phValue)
phValue->clear();
RegCloseKey(hKey);
}
}
return returnValue;
#endif // _WIN32
}
// Find the most recent version of Universal CRT or Windows 10 SDK.
// vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include
// directory by name and uses the last one of the list.
// So we compare entry names lexicographically to find the greatest one.
static bool getWindows10SDKVersionFromPath(llvm::vfs::FileSystem &VFS,
const std::string &SDKPath,
std::string &SDKVersion) {
llvm::SmallString<128> IncludePath(SDKPath);
llvm::sys::path::append(IncludePath, "Include");
SDKVersion = getHighestNumericTupleInDirectory(VFS, IncludePath);
return !SDKVersion.empty();
}
static bool getWindowsSDKDirViaCommandLine(llvm::vfs::FileSystem &VFS,
const ArgList &Args,
std::string &Path, int &Major,
std::string &Version) {
if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir,
options::OPT__SLASH_winsysroot)) {
// Don't validate the input; trust the value supplied by the user.
// The motivation is to prevent unnecessary file and registry access.
llvm::VersionTuple SDKVersion;
if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion))
SDKVersion.tryParse(A->getValue());
if (A->getOption().getID() == options::OPT__SLASH_winsysroot) {
llvm::SmallString<128> SDKPath(A->getValue());
llvm::sys::path::append(SDKPath, "Windows Kits");
if (!SDKVersion.empty())
llvm::sys::path::append(SDKPath, Twine(SDKVersion.getMajor()));
else
llvm::sys::path::append(
SDKPath, getHighestNumericTupleInDirectory(VFS, SDKPath));
Path = std::string(SDKPath.str());
} else {
Path = A->getValue();
}
if (!SDKVersion.empty()) {
Major = SDKVersion.getMajor();
Version = SDKVersion.getAsString();
} else if (getWindows10SDKVersionFromPath(VFS, Path, Version)) {
Major = 10;
}
return true;
}
return false;
}
/// Get Windows SDK installation directory.
static bool getWindowsSDKDir(llvm::vfs::FileSystem &VFS, const ArgList &Args,
std::string &Path, int &Major,
std::string &WindowsSDKIncludeVersion,
std::string &WindowsSDKLibVersion) {
// Trust /winsdkdir and /winsdkversion if present.
if (getWindowsSDKDirViaCommandLine(VFS, Args, Path, Major,
WindowsSDKIncludeVersion)) {
WindowsSDKLibVersion = WindowsSDKIncludeVersion;
return true;
}
// FIXME: Try env vars (%WindowsSdkDir%, %UCRTVersion%) before going to registry.
// Try the Windows registry.
std::string RegistrySDKVersion;
if (!getSystemRegistryString(
"SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
"InstallationFolder", Path, &RegistrySDKVersion))
return false;
if (Path.empty() || RegistrySDKVersion.empty())
return false;
WindowsSDKIncludeVersion.clear();
WindowsSDKLibVersion.clear();
Major = 0;
std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major);
if (Major <= 7)
return true;
if (Major == 8) {
// Windows SDK 8.x installs libraries in a folder whose names depend on the
// version of the OS you're targeting. By default choose the newest, which
// usually corresponds to the version of the OS you've installed the SDK on.
const char *Tests[] = {"winv6.3", "win8", "win7"};
for (const char *Test : Tests) {
llvm::SmallString<128> TestPath(Path);
llvm::sys::path::append(TestPath, "Lib", Test);
if (VFS.exists(TestPath)) {
WindowsSDKLibVersion = Test;
break;
}
}
return !WindowsSDKLibVersion.empty();
}
if (Major == 10) {
if (!getWindows10SDKVersionFromPath(VFS, Path, WindowsSDKIncludeVersion))
return false;
WindowsSDKLibVersion = WindowsSDKIncludeVersion;
return true;
}
// Unsupported SDK version
return false;
}
// Gets the library path required to link against the Windows SDK.
bool MSVCToolChain::getWindowsSDKLibraryPath(const ArgList &Args,
std::string &path) const {
bool MSVCToolChain::getWindowsSDKLibraryPath(
const ArgList &Args, std::string &path) const {
std::string sdkPath;
int sdkMajor = 0;
std::string windowsSDKIncludeVersion;
std::string windowsSDKLibVersion;
path.clear();
if (!llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot,
sdkPath, sdkMajor, windowsSDKIncludeVersion,
windowsSDKLibVersion))
if (!getWindowsSDKDir(getVFS(), Args, sdkPath, sdkMajor,
windowsSDKIncludeVersion, windowsSDKLibVersion))
return false;
llvm::SmallString<128> libPath(sdkPath);
llvm::sys::path::append(libPath, "Lib");
if (sdkMajor >= 8)
llvm::sys::path::append(libPath, windowsSDKLibVersion, "um");
return llvm::appendArchToWindowsSDKLibPath(sdkMajor, libPath, getArch(),
path);
if (sdkMajor >= 8) {
llvm::sys::path::append(libPath, windowsSDKLibVersion, "um",
llvmArchToWindowsSDKArch(getArch()));
} else {
switch (getArch()) {
// In Windows SDK 7.x, x86 libraries are directly in the Lib folder.
case llvm::Triple::x86:
break;
case llvm::Triple::x86_64:
llvm::sys::path::append(libPath, "x64");
break;
case llvm::Triple::arm:
// It is not necessary to link against Windows SDK 7.x when targeting ARM.
return false;
default:
return false;
}
}
path = std::string(libPath.str());
return true;
}
// Check if the Include path of a specified version of Visual Studio contains
// specific header files. If not, they are probably shipped with Universal CRT.
bool MSVCToolChain::useUniversalCRT() const {
return llvm::useUniversalCRT(VSLayout, VCToolChainPath, getArch(), getVFS());
llvm::SmallString<128> TestPath(
getSubDirectoryPath(SubDirectoryType::Include));
llvm::sys::path::append(TestPath, "stdlib.h");
return !getVFS().exists(TestPath);
}
static bool getUniversalCRTSdkDir(llvm::vfs::FileSystem &VFS,
const ArgList &Args, std::string &Path,
std::string &UCRTVersion) {
// If /winsdkdir is passed, use it as location for the UCRT too.
// FIXME: Should there be a dedicated /ucrtdir to override /winsdkdir?
int Major;
if (getWindowsSDKDirViaCommandLine(VFS, Args, Path, Major, UCRTVersion))
return true;
// FIXME: Try env vars (%UniversalCRTSdkDir%, %UCRTVersion%) before going to
// registry.
// vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry
// for the specific key "KitsRoot10". So do we.
if (!getSystemRegistryString(
"SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10",
Path, nullptr))
return false;
return getWindows10SDKVersionFromPath(VFS, Path, UCRTVersion);
}
bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args,
@ -531,12 +1192,10 @@ bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args,
std::string UCRTVersion;
Path.clear();
if (!llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion,
WinSysRoot, UniversalCRTSdkPath,
UCRTVersion))
if (!getUniversalCRTSdkDir(getVFS(), Args, UniversalCRTSdkPath, UCRTVersion))
return false;
StringRef ArchName = llvm::archToWindowsSDKArch(getArch());
StringRef ArchName = llvmArchToWindowsSDKArch(getArch());
if (ArchName.empty())
return false;
@ -654,17 +1313,15 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
// the correct include paths first.
if (!VCToolChainPath.empty()) {
addSystemInclude(DriverArgs, CC1Args,
getSubDirectoryPath(llvm::SubDirectoryType::Include));
addSystemInclude(
DriverArgs, CC1Args,
getSubDirectoryPath(llvm::SubDirectoryType::Include, "atlmfc"));
getSubDirectoryPath(SubDirectoryType::Include));
addSystemInclude(DriverArgs, CC1Args,
getSubDirectoryPath(SubDirectoryType::Include, "atlmfc"));
if (useUniversalCRT()) {
std::string UniversalCRTSdkPath;
std::string UCRTVersion;
if (llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion,
WinSysRoot, UniversalCRTSdkPath,
UCRTVersion)) {
if (getUniversalCRTSdkDir(getVFS(), DriverArgs, UniversalCRTSdkPath,
UCRTVersion)) {
AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath,
"Include", UCRTVersion, "ucrt");
}
@ -674,9 +1331,8 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
int major = 0;
std::string windowsSDKIncludeVersion;
std::string windowsSDKLibVersion;
if (llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot,
WindowsSDKDir, major, windowsSDKIncludeVersion,
windowsSDKLibVersion)) {
if (getWindowsSDKDir(getVFS(), DriverArgs, WindowsSDKDir, major,
windowsSDKIncludeVersion, windowsSDKLibVersion)) {
if (major >= 8) {
// Note: windowsSDKIncludeVersion is empty for SDKs prior to v10.
// Anyway, llvm::sys::path::append is able to manage it.
@ -733,8 +1389,7 @@ VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D,
if (MSVT.empty())
MSVT = getTriple().getEnvironmentVersion();
if (MSVT.empty() && IsWindowsMSVC)
MSVT =
getMSVCVersionFromExe(getSubDirectoryPath(llvm::SubDirectoryType::Bin));
MSVT = getMSVCVersionFromExe(getSubDirectoryPath(SubDirectoryType::Bin));
if (MSVT.empty() &&
Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
IsWindowsMSVC)) {

View File

@ -15,7 +15,6 @@
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/Support/MSVCPaths.h"
namespace clang {
namespace driver {
@ -74,15 +73,29 @@ public:
return 4;
}
std::string getSubDirectoryPath(llvm::SubDirectoryType Type,
llvm::StringRef SubdirParent = "") const;
std::string getSubDirectoryPath(llvm::SubDirectoryType Type,
enum class SubDirectoryType {
Bin,
Include,
Lib,
};
std::string getSubDirectoryPath(SubDirectoryType Type,
llvm::StringRef SubdirParent,
llvm::Triple::ArchType TargetArch) const;
bool getIsVS2017OrNewer() const {
return VSLayout == llvm::ToolsetLayout::VS2017OrNewer;
// Convenience overload.
// Uses the current target arch.
std::string getSubDirectoryPath(SubDirectoryType Type,
llvm::StringRef SubdirParent = "") const {
return getSubDirectoryPath(Type, SubdirParent, getArch());
}
enum class ToolsetLayout {
OlderVS,
VS2017OrNewer,
DevDivInternal,
};
bool getIsVS2017OrNewer() const { return VSLayout == ToolsetLayout::VS2017OrNewer; }
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
@ -129,9 +142,8 @@ protected:
Tool *buildLinker() const override;
Tool *buildAssembler() const override;
private:
llvm::StringRef WinSdkDir, WinSdkVersion, WinSysRoot;
std::string VCToolChainPath;
llvm::ToolsetLayout VSLayout = llvm::ToolsetLayout::OlderVS;
ToolsetLayout VSLayout = ToolsetLayout::OlderVS;
CudaInstallationDetector CudaInstallation;
RocmInstallationDetector RocmInstallation;
};

View File

@ -24,7 +24,6 @@
#include "lld/Common/Version.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/LTO/LTO.h"
@ -39,7 +38,6 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MSVCPaths.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Parallel.h"
#include "llvm/Support/Path.h"
@ -152,21 +150,6 @@ static StringRef mangle(StringRef sym) {
return sym;
}
static llvm::Triple::ArchType getArch() {
switch (config->machine) {
case I386:
return llvm::Triple::ArchType::x86;
case AMD64:
return llvm::Triple::ArchType::x86_64;
case ARMNT:
return llvm::Triple::ArchType::arm;
case ARM64:
return llvm::Triple::ArchType::aarch64;
default:
return llvm::Triple::ArchType::UnknownArch;
}
}
bool LinkerDriver::findUnderscoreMangle(StringRef sym) {
Symbol *s = ctx.symtab.findMangle(mangle(sym));
return s && !isa<Undefined>(s);
@ -521,101 +504,6 @@ Optional<StringRef> LinkerDriver::findLib(StringRef filename) {
return path;
}
void LinkerDriver::detectWinSysRoot(const opt::InputArgList &Args) {
IntrusiveRefCntPtr<vfs::FileSystem> VFS = vfs::getRealFileSystem();
// Check the command line first, that's the user explicitly telling us what to
// use. Check the environment next, in case we're being invoked from a VS
// command prompt. Failing that, just try to find the newest Visual Studio
// version we can and use its default VC toolchain.
StringRef VCToolsDir, VCToolsVersion, WinSysRoot;
if (auto *A = Args.getLastArg(OPT_vctoolsdir))
VCToolsDir = A->getValue();
if (auto *A = Args.getLastArg(OPT_vctoolsversion))
VCToolsVersion = A->getValue();
if (auto *A = Args.getLastArg(OPT_winsysroot))
WinSysRoot = A->getValue();
if (!findVCToolChainViaCommandLine(*VFS, VCToolsDir, VCToolsVersion,
WinSysRoot, vcToolChainPath, vsLayout) &&
(Args.hasArg(OPT_lldignoreenv) ||
!findVCToolChainViaEnvironment(*VFS, vcToolChainPath, vsLayout)) &&
!findVCToolChainViaSetupConfig(*VFS, vcToolChainPath, vsLayout) &&
!findVCToolChainViaRegistry(vcToolChainPath, vsLayout))
return;
// If the VC environment hasn't been configured (perhaps because the user did
// not run vcvarsall), try to build a consistent link environment. If the
// environment variable is set however, assume the user knows what they're
// doing. If the user passes /vctoolsdir or /winsdkdir, trust that over env
// vars.
if (const auto *A = Args.getLastArg(OPT_diasdkdir, OPT_winsysroot)) {
diaPath = A->getValue();
if (A->getOption().getID() == OPT_winsysroot)
path::append(diaPath, "DIA SDK");
}
useWinSysRootLibPath = Args.hasArg(OPT_lldignoreenv) ||
!Process::GetEnv("LIB") ||
Args.getLastArg(OPT_vctoolsdir, OPT_winsysroot);
if (Args.hasArg(OPT_lldignoreenv) || !Process::GetEnv("LIB") ||
Args.getLastArg(OPT_winsdkdir, OPT_winsysroot)) {
StringRef WinSdkDir, WinSdkVersion;
if (auto *A = Args.getLastArg(OPT_winsdkdir))
WinSdkDir = A->getValue();
if (auto *A = Args.getLastArg(OPT_winsdkversion))
WinSdkVersion = A->getValue();
if (useUniversalCRT(vsLayout, vcToolChainPath, getArch(), *VFS)) {
std::string UniversalCRTSdkPath;
std::string UCRTVersion;
if (getUniversalCRTSdkDir(*VFS, WinSdkDir, WinSdkVersion, WinSysRoot,
UniversalCRTSdkPath, UCRTVersion)) {
universalCRTLibPath = UniversalCRTSdkPath;
path::append(universalCRTLibPath, "Lib", UCRTVersion, "ucrt");
}
}
std::string sdkPath;
std::string windowsSDKIncludeVersion;
std::string windowsSDKLibVersion;
if (getWindowsSDKDir(*VFS, WinSdkDir, WinSdkVersion, WinSysRoot, sdkPath,
sdkMajor, windowsSDKIncludeVersion,
windowsSDKLibVersion)) {
windowsSdkLibPath = sdkPath;
path::append(windowsSdkLibPath, "Lib");
if (sdkMajor >= 8)
path::append(windowsSdkLibPath, windowsSDKLibVersion, "um");
}
}
}
void LinkerDriver::addWinSysRootLibSearchPaths() {
if (!diaPath.empty()) {
// The DIA SDK always uses the legacy vc arch, even in new MSVC versions.
path::append(diaPath, "lib", archToLegacyVCArch(getArch()));
searchPaths.push_back(saver().save(diaPath.str()));
}
if (useWinSysRootLibPath) {
searchPaths.push_back(saver().save(getSubDirectoryPath(
SubDirectoryType::Lib, vsLayout, vcToolChainPath, getArch())));
searchPaths.push_back(saver().save(
getSubDirectoryPath(SubDirectoryType::Lib, vsLayout, vcToolChainPath,
getArch(), "atlmfc")));
}
if (!universalCRTLibPath.empty()) {
StringRef ArchName = archToWindowsSDKArch(getArch());
if (!ArchName.empty()) {
path::append(universalCRTLibPath, ArchName);
searchPaths.push_back(saver().save(universalCRTLibPath.str()));
}
}
if (!windowsSdkLibPath.empty()) {
std::string path;
if (appendArchToWindowsSDKLibPath(sdkMajor, windowsSdkLibPath, getArch(),
path))
searchPaths.push_back(saver().save(path));
}
}
// Parses LIB environment which contains a list of search paths.
void LinkerDriver::addLibSearchPaths() {
Optional<std::string> envOpt = Process::GetEnv("LIB");
@ -738,7 +626,6 @@ static std::string createResponseFile(const opt::InputArgList &args,
case OPT_INPUT:
case OPT_defaultlib:
case OPT_libpath:
case OPT_winsysroot:
break;
case OPT_call_graph_ordering_file:
case OPT_deffile:
@ -1448,8 +1335,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
searchPaths.push_back("");
for (auto *arg : args.filtered(OPT_libpath))
searchPaths.push_back(arg->getValue());
detectWinSysRoot(args);
if (!args.hasArg(OPT_lldignoreenv) && !args.hasArg(OPT_winsysroot))
if (!args.hasArg(OPT_lldignoreenv))
addLibSearchPaths();
// Handle /ignore
@ -1589,7 +1475,6 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
config->machine = getMachineType(arg->getValue());
if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN)
fatal(Twine("unknown /machine argument: ") + arg->getValue());
addWinSysRootLibSearchPaths();
}
// Handle /nodefaultlib:<filename>
@ -1951,8 +1836,15 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
}
}
// Process files specified as /defaultlib. These should be enequeued after
// other files, which is why they are in a separate loop.
for (auto *arg : args.filtered(OPT_defaultlib))
if (Optional<StringRef> path = findLib(arg->getValue()))
enqueuePath(*path, false, false);
// Read all input files given via the command line.
run();
if (errorCount())
return;
@ -1961,19 +1853,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) {
warn("/machine is not specified. x64 is assumed");
config->machine = AMD64;
addWinSysRootLibSearchPaths();
}
config->wordsize = config->is64() ? 8 : 4;
// Process files specified as /defaultlib. These must be processed after
// addWinSysRootLibSearchPaths(), which is why they are in a separate loop.
for (auto *arg : args.filtered(OPT_defaultlib))
if (Optional<StringRef> path = findLib(arg->getValue()))
enqueuePath(*path, false, false);
run();
if (errorCount())
return;
// 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);
@ -1984,11 +1866,10 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
for (auto *arg : args.filtered(OPT_functionpadmin, OPT_functionpadmin_opt))
parseFunctionPadMin(arg, config->machine);
if (tar) {
if (tar)
tar->append("response.txt",
createResponseFile(args, filePaths,
ArrayRef<StringRef>(searchPaths).slice(1)));
}
// Handle /largeaddressaware
config->largeAddressAware = args.hasFlag(

View File

@ -22,7 +22,6 @@
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MSVCPaths.h"
#include "llvm/Support/TarWriter.h"
#include <memory>
#include <set>
@ -83,10 +82,6 @@ public:
void linkerMain(llvm::ArrayRef<const char *> args);
// Adds various search paths based on the sysroot. Must only be called once
// config->machine has been set.
void addWinSysRootLibSearchPaths();
// Used by the resolver to parse .drectve section contents.
void parseDirectives(InputFile *file);
@ -112,9 +107,6 @@ private:
bool findUnderscoreMangle(StringRef sym);
// Determines the location of the sysroot based on `args`, environment, etc.
void detectWinSysRoot(const llvm::opt::InputArgList &args);
// Parses LIB environment which contains a list of search paths.
void addLibSearchPaths();
@ -162,14 +154,6 @@ private:
llvm::StringSet<> directivesExports;
COFFLinkerContext &ctx;
llvm::ToolsetLayout vsLayout = llvm::ToolsetLayout::OlderVS;
std::string vcToolChainPath;
llvm::SmallString<128> diaPath;
bool useWinSysRootLibPath = false;
llvm::SmallString<128> universalCRTLibPath;
int sdkMajor = 0;
llvm::SmallString<128> windowsSdkLibPath;
};
// Functions below this line are defined in DriverUtils.cpp.

View File

@ -41,7 +41,6 @@ def color_diagnostics_eq: Joined<["--"], "color-diagnostics=">,
MetaVarName<"[auto,always,never]">;
def defaultlib : P<"defaultlib", "Add the library to the list of input files">;
def delayload : P<"delayload", "Delay loaded DLL name">;
def diasdkdir : P<"diasdkdir", "Set the location of the DIA SDK">;
def entry : P<"entry", "Name of entry point symbol">;
def errorlimit : P<"errorlimit",
"Maximum number of errors to emit before stopping (0 = no limit)">;
@ -90,16 +89,9 @@ def stack : P<"stack", "Size of the stack">;
def stub : P<"stub", "Specify DOS stub file">;
def subsystem : P<"subsystem", "Specify subsystem">;
def timestamp : P<"timestamp", "Specify the PE header timestamp">;
def vctoolsdir : P<"vctoolsdir", "Set the location of the VC tools">;
def vctoolsversion : P<"vctoolsversion",
"Specify which VC tools version to use">;
def version : P<"version", "Specify a version number in the PE header">;
def wholearchive_file : P<"wholearchive",
"Include all object files from this library">;
def winsdkdir : P<"winsdkdir", "Set the location of the Windows SDK">;
def winsdkversion : P<"winsdkversion", "Specify which SDK version to use">;
def winsysroot : P<"winsysroot",
"Adds several subdirectories to the library search paths">;
def disallowlib : Joined<["/", "-", "/?", "-?"], "disallowlib:">,
Alias<nodefaultlib>;

View File

@ -56,7 +56,6 @@ void SymbolTable::addFile(InputFile *file) {
MachineTypes mt = file->getMachineType();
if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) {
config->machine = mt;
driver->addWinSysRootLibSearchPaths();
} else if (mt != IMAGE_FILE_MACHINE_UNKNOWN && config->machine != mt) {
error(toString(file) + ": machine type " + machineToStr(mt) +
" conflicts with " + machineToStr(config->machine));

View File

@ -36,9 +36,6 @@ Breaking changes
COFF Improvements
-----------------
* Added autodetection of MSVC toolchain, a la clang-cl. Also added /winsysroot
support for explicit specification of MSVC toolchain location.
(`D118070 <https://reviews.llvm.org/D118070>`_)
* ...
MinGW Improvements

View File

@ -1,17 +0,0 @@
Check that /winsysroot results in the correct machine-specific subdirectory
being searched for the defaultlibs, for a 32-bit .obj.
# RUN: yaml2obj %p/Inputs/hello32.yaml -o %t.obj
# RUN: mkdir -p %t.dir/sysroot/VC/Tools/MSVC/1.1.1.1/lib/x86
# RUN: mkdir -p %t.dir/sysroot/VC/Tools/MSVC/1.1.1.1/lib/x64
# RUN: cp %p/Inputs/std32.lib %t.dir/sysroot/VC/Tools/MSVC/1.1.1.1/lib/x86
# RUN: cp %p/Inputs/std64.lib %t.dir/sysroot/VC/Tools/MSVC/1.1.1.1/lib/x64
# RUN: not lld-link %t.obj /winsysroot:%t.dir/sysroot /defaultlib:std32 2>&1 | FileCheck -check-prefix=MISSINGENTRY32 --implicit-check-not=_ExitProcess %s
MISSINGENTRY32: undefined symbol: _mainCRTStartup
Check the same for a 64-bit input .obj.
# RUN: not lld-link %p/Inputs/hello64.obj /winsysroot:%t.dir/sysroot /defaultlib:std64 2>&1 | FileCheck -check-prefix=MISSINGENTRY64 --implicit-check-not=_ExitProcess %s
MISSINGENTRY64: undefined symbol: mainCRTStartup
Check that when /winsysroot is specified, %LIB% is ignored.
# RUN: env LIB=foo.dir/sysroot/VC/Tools/MSVC/1.1.1.1/lib/x86 not lld-link %t.obj /winsysroot:%t.dir/doesnotexist /defaultlib:std32 2>&1 | FileCheck -check-prefix=LIBIGNORED %s
LIBIGNORED: could not open 'std32.lib'

View File

@ -1,99 +0,0 @@
//===-- MSVCPaths.h - MSVC path-parsing helpers -----------------*- C++ -*-===//
//
// 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_SUPPORT_MSVCPATHS_H
#define LLVM_SUPPORT_MSVCPATHS_H
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/VirtualFileSystem.h"
#include <string>
namespace llvm {
enum class SubDirectoryType {
Bin,
Include,
Lib,
};
enum class ToolsetLayout {
OlderVS,
VS2017OrNewer,
DevDivInternal,
};
// Windows SDKs and VC Toolchains group their contents into subdirectories based
// on the target architecture. This function converts an llvm::Triple::ArchType
// to the corresponding subdirectory name.
const char *archToWindowsSDKArch(llvm::Triple::ArchType Arch);
// Similar to the above function, but for Visual Studios before VS2017.
const char *archToLegacyVCArch(llvm::Triple::ArchType Arch);
// Similar to the above function, but for DevDiv internal builds.
const char *archToDevDivInternalArch(llvm::Triple::ArchType Arch);
bool appendArchToWindowsSDKLibPath(int SDKMajor, llvm::SmallString<128> LibPath,
llvm::Triple::ArchType Arch,
std::string &path);
// Get the path to a specific subdirectory in the current toolchain for
// a given target architecture.
// VS2017 changed the VC toolchain layout, so this should be used instead
// of hardcoding paths.
std::string getSubDirectoryPath(SubDirectoryType Type, ToolsetLayout VSLayout,
const std::string &VCToolChainPath,
llvm::Triple::ArchType TargetArch,
llvm::StringRef SubdirParent = "");
// Check if the Include path of a specified version of Visual Studio contains
// specific header files. If not, they are probably shipped with Universal CRT.
bool useUniversalCRT(ToolsetLayout VSLayout, const std::string &VCToolChainPath,
llvm::Triple::ArchType TargetArch,
llvm::vfs::FileSystem &VFS);
/// Get Windows SDK installation directory.
bool getWindowsSDKDir(vfs::FileSystem &VFS, llvm::StringRef WinSdkDir,
llvm::StringRef WinSdkVersion, llvm::StringRef WinSysRoot,
std::string &Path, int &Major,
std::string &WindowsSDKIncludeVersion,
std::string &WindowsSDKLibVersion);
bool getUniversalCRTSdkDir(vfs::FileSystem &VFS, llvm::StringRef WinSdkDir,
llvm::StringRef WinSdkVersion,
llvm::StringRef WinSysRoot, std::string &Path,
std::string &UCRTVersion);
// Check command line arguments to try and find a toolchain.
bool findVCToolChainViaCommandLine(vfs::FileSystem &VFS,
llvm::StringRef VCToolsDir,
llvm::StringRef VCToolsVersion,
llvm::StringRef WinSysRoot,
std::string &Path, ToolsetLayout &VSLayout);
// Check various environment variables to try and find a toolchain.
bool findVCToolChainViaEnvironment(vfs::FileSystem &VFS, std::string &Path,
ToolsetLayout &VSLayout);
// Query the Setup Config server for installs, then pick the newest version
// and find its default VC toolchain.
// This is the preferred way to discover new Visual Studios, as they're no
// longer listed in the registry.
bool findVCToolChainViaSetupConfig(vfs::FileSystem &VFS, std::string &Path,
ToolsetLayout &VSLayout);
// Look in the registry for Visual Studio installs, and use that to get
// a toolchain path. VS2017 and newer don't get added to the registry.
// So if we find something here, we know that it's an older version.
bool findVCToolChainViaRegistry(std::string &Path, ToolsetLayout &VSLayout);
} // namespace llvm
#endif

View File

@ -175,7 +175,6 @@ add_llvm_component_library(LLVMSupport
MD5.cpp
MSP430Attributes.cpp
MSP430AttributeParser.cpp
MSVCPaths.cpp
NativeFormatting.cpp
OptimizedStructLayout.cpp
Optional.cpp

View File

@ -1,709 +0,0 @@
//===-- MSVCPaths.cpp - MSVC path-parsing helpers -------------------------===//
//
// 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 "llvm/Support/MSVCPaths.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/VersionTuple.h"
#include "llvm/Support/VirtualFileSystem.h"
#include <string>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define NOGDI
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#endif
#ifdef _MSC_VER
// Don't support SetupApi on MinGW.
#define USE_MSVC_SETUP_API
// Make sure this comes before MSVCSetupApi.h
#include <comdef.h>
#include "llvm/Support/COM.h"
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
#endif
#include "llvm/Support/MSVCSetupApi.h"
#ifdef __clang__
#pragma clang diagnostic pop
#endif
_COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration));
_COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2));
_COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper));
_COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances));
_COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance));
_COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2));
#endif
static std::string
getHighestNumericTupleInDirectory(llvm::vfs::FileSystem &VFS,
llvm::StringRef Directory) {
std::string Highest;
llvm::VersionTuple HighestTuple;
std::error_code EC;
for (llvm::vfs::directory_iterator DirIt = VFS.dir_begin(Directory, EC),
DirEnd;
!EC && DirIt != DirEnd; DirIt.increment(EC)) {
auto Status = VFS.status(DirIt->path());
if (!Status || !Status->isDirectory())
continue;
llvm::StringRef CandidateName = llvm::sys::path::filename(DirIt->path());
llvm::VersionTuple Tuple;
if (Tuple.tryParse(CandidateName)) // tryParse() returns true on error.
continue;
if (Tuple > HighestTuple) {
HighestTuple = Tuple;
Highest = CandidateName.str();
}
}
return Highest;
}
static bool getWindows10SDKVersionFromPath(llvm::vfs::FileSystem &VFS,
const std::string &SDKPath,
std::string &SDKVersion) {
llvm::SmallString<128> IncludePath(SDKPath);
llvm::sys::path::append(IncludePath, "Include");
SDKVersion = getHighestNumericTupleInDirectory(VFS, IncludePath);
return !SDKVersion.empty();
}
static bool getWindowsSDKDirViaCommandLine(llvm::vfs::FileSystem &VFS,
llvm::StringRef WinSdkDir,
llvm::StringRef WinSdkVersion,
llvm::StringRef WinSysRoot,
std::string &Path, int &Major,
std::string &Version) {
if (!WinSdkDir.empty() || !WinSysRoot.empty()) {
// Don't validate the input; trust the value supplied by the user.
// The motivation is to prevent unnecessary file and registry access.
llvm::VersionTuple SDKVersion;
if (!WinSdkVersion.empty())
SDKVersion.tryParse(WinSdkVersion);
if (!WinSysRoot.empty()) {
llvm::SmallString<128> SDKPath(WinSysRoot);
llvm::sys::path::append(SDKPath, "Windows Kits");
if (!SDKVersion.empty())
llvm::sys::path::append(SDKPath, llvm::Twine(SDKVersion.getMajor()));
else
llvm::sys::path::append(
SDKPath, getHighestNumericTupleInDirectory(VFS, SDKPath));
Path = std::string(SDKPath.str());
} else {
Path = WinSdkDir.str();
}
if (!SDKVersion.empty()) {
Major = SDKVersion.getMajor();
Version = SDKVersion.getAsString();
} else if (getWindows10SDKVersionFromPath(VFS, Path, Version)) {
Major = 10;
}
return true;
}
return false;
}
#ifdef _WIN32
static bool readFullStringValue(HKEY hkey, const char *valueName,
std::string &value) {
std::wstring WideValueName;
if (!llvm::ConvertUTF8toWide(valueName, WideValueName))
return false;
DWORD result = 0;
DWORD valueSize = 0;
DWORD type = 0;
// First just query for the required size.
result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, &type, NULL,
&valueSize);
if (result != ERROR_SUCCESS || type != REG_SZ || !valueSize)
return false;
std::vector<BYTE> buffer(valueSize);
result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, NULL, &buffer[0],
&valueSize);
if (result == ERROR_SUCCESS) {
std::wstring WideValue(reinterpret_cast<const wchar_t *>(buffer.data()),
valueSize / sizeof(wchar_t));
if (valueSize && WideValue.back() == L'\0') {
WideValue.pop_back();
}
// The destination buffer must be empty as an invariant of the conversion
// function; but this function is sometimes called in a loop that passes in
// the same buffer, however. Simply clear it out so we can overwrite it.
value.clear();
return llvm::convertWideToUTF8(WideValue, value);
}
return false;
}
#endif
/// Read registry string.
/// This also supports a means to look for high-versioned keys by use
/// of a $VERSION placeholder in the key path.
/// $VERSION in the key path is a placeholder for the version number,
/// causing the highest value path to be searched for and used.
/// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
/// There can be additional characters in the component. Only the numeric
/// characters are compared. This function only searches HKLM.
static bool getSystemRegistryString(const char *keyPath, const char *valueName,
std::string &value, std::string *phValue) {
#ifndef _WIN32
return false;
#else
HKEY hRootKey = HKEY_LOCAL_MACHINE;
HKEY hKey = NULL;
long lResult;
bool returnValue = false;
const char *placeHolder = strstr(keyPath, "$VERSION");
std::string bestName;
// If we have a $VERSION placeholder, do the highest-version search.
if (placeHolder) {
const char *keyEnd = placeHolder - 1;
const char *nextKey = placeHolder;
// Find end of previous key.
while ((keyEnd > keyPath) && (*keyEnd != '\\'))
keyEnd--;
// Find end of key containing $VERSION.
while (*nextKey && (*nextKey != '\\'))
nextKey++;
size_t partialKeyLength = keyEnd - keyPath;
char partialKey[256];
if (partialKeyLength >= sizeof(partialKey))
partialKeyLength = sizeof(partialKey) - 1;
strncpy(partialKey, keyPath, partialKeyLength);
partialKey[partialKeyLength] = '\0';
HKEY hTopKey = NULL;
lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY,
&hTopKey);
if (lResult == ERROR_SUCCESS) {
char keyName[256];
double bestValue = 0.0;
DWORD index, size = sizeof(keyName) - 1;
for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, NULL,
NULL, NULL) == ERROR_SUCCESS;
index++) {
const char *sp = keyName;
while (*sp && !llvm::isDigit(*sp))
sp++;
if (!*sp)
continue;
const char *ep = sp + 1;
while (*ep && (llvm::isDigit(*ep) || (*ep == '.')))
ep++;
char numBuf[32];
strncpy(numBuf, sp, sizeof(numBuf) - 1);
numBuf[sizeof(numBuf) - 1] = '\0';
double dvalue = strtod(numBuf, NULL);
if (dvalue > bestValue) {
// Test that InstallDir is indeed there before keeping this index.
// Open the chosen key path remainder.
bestName = keyName;
// Append rest of key.
bestName.append(nextKey);
lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0,
KEY_READ | KEY_WOW64_32KEY, &hKey);
if (lResult == ERROR_SUCCESS) {
if (readFullStringValue(hKey, valueName, value)) {
bestValue = dvalue;
if (phValue)
*phValue = bestName;
returnValue = true;
}
RegCloseKey(hKey);
}
}
size = sizeof(keyName) - 1;
}
RegCloseKey(hTopKey);
}
} else {
lResult =
RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey);
if (lResult == ERROR_SUCCESS) {
if (readFullStringValue(hKey, valueName, value))
returnValue = true;
if (phValue)
phValue->clear();
RegCloseKey(hKey);
}
}
return returnValue;
#endif // _WIN32
}
namespace llvm {
const char *archToWindowsSDKArch(Triple::ArchType Arch) {
switch (Arch) {
case Triple::ArchType::x86:
return "x86";
case Triple::ArchType::x86_64:
return "x64";
case Triple::ArchType::arm:
return "arm";
case Triple::ArchType::aarch64:
return "arm64";
default:
return "";
}
}
const char *archToLegacyVCArch(Triple::ArchType Arch) {
switch (Arch) {
case Triple::ArchType::x86:
// x86 is default in legacy VC toolchains.
// e.g. x86 libs are directly in /lib as opposed to /lib/x86.
return "";
case Triple::ArchType::x86_64:
return "amd64";
case Triple::ArchType::arm:
return "arm";
case Triple::ArchType::aarch64:
return "arm64";
default:
return "";
}
}
const char *archToDevDivInternalArch(Triple::ArchType Arch) {
switch (Arch) {
case Triple::ArchType::x86:
return "i386";
case Triple::ArchType::x86_64:
return "amd64";
case Triple::ArchType::arm:
return "arm";
case Triple::ArchType::aarch64:
return "arm64";
default:
return "";
}
}
bool appendArchToWindowsSDKLibPath(int SDKMajor, SmallString<128> LibPath,
Triple::ArchType Arch, std::string &path) {
if (SDKMajor >= 8) {
sys::path::append(LibPath, archToWindowsSDKArch(Arch));
} else {
switch (Arch) {
// In Windows SDK 7.x, x86 libraries are directly in the Lib folder.
case Triple::x86:
break;
case Triple::x86_64:
sys::path::append(LibPath, "x64");
break;
case Triple::arm:
// It is not necessary to link against Windows SDK 7.x when targeting ARM.
return false;
default:
return false;
}
}
path = std::string(LibPath.str());
return true;
}
std::string getSubDirectoryPath(SubDirectoryType Type, ToolsetLayout VSLayout,
const std::string &VCToolChainPath,
Triple::ArchType TargetArch,
StringRef SubdirParent) {
const char *SubdirName;
const char *IncludeName;
switch (VSLayout) {
case ToolsetLayout::OlderVS:
SubdirName = archToLegacyVCArch(TargetArch);
IncludeName = "include";
break;
case ToolsetLayout::VS2017OrNewer:
SubdirName = archToWindowsSDKArch(TargetArch);
IncludeName = "include";
break;
case ToolsetLayout::DevDivInternal:
SubdirName = archToDevDivInternalArch(TargetArch);
IncludeName = "inc";
break;
}
SmallString<256> Path(VCToolChainPath);
if (!SubdirParent.empty())
sys::path::append(Path, SubdirParent);
switch (Type) {
case SubDirectoryType::Bin:
if (VSLayout == ToolsetLayout::VS2017OrNewer) {
const bool HostIsX64 = Triple(sys::getProcessTriple()).isArch64Bit();
const char *const HostName = HostIsX64 ? "Hostx64" : "Hostx86";
sys::path::append(Path, "bin", HostName, SubdirName);
} else { // OlderVS or DevDivInternal
sys::path::append(Path, "bin", SubdirName);
}
break;
case SubDirectoryType::Include:
sys::path::append(Path, IncludeName);
break;
case SubDirectoryType::Lib:
sys::path::append(Path, "lib", SubdirName);
break;
}
return std::string(Path.str());
}
bool useUniversalCRT(ToolsetLayout VSLayout, const std::string &VCToolChainPath,
Triple::ArchType TargetArch, vfs::FileSystem &VFS) {
SmallString<128> TestPath(getSubDirectoryPath(
SubDirectoryType::Include, VSLayout, VCToolChainPath, TargetArch));
sys::path::append(TestPath, "stdlib.h");
return !VFS.exists(TestPath);
}
bool getWindowsSDKDir(vfs::FileSystem &VFS, StringRef WinSdkDir,
StringRef WinSdkVersion, StringRef WinSysRoot,
std::string &Path, int &Major,
std::string &WindowsSDKIncludeVersion,
std::string &WindowsSDKLibVersion) {
// Trust /winsdkdir and /winsdkversion if present.
if (getWindowsSDKDirViaCommandLine(VFS, WinSdkDir, WinSdkVersion, WinSysRoot,
Path, Major, WindowsSDKIncludeVersion)) {
WindowsSDKLibVersion = WindowsSDKIncludeVersion;
return true;
}
// FIXME: Try env vars (%WindowsSdkDir%, %UCRTVersion%) before going to
// registry.
// Try the Windows registry.
std::string RegistrySDKVersion;
if (!getSystemRegistryString(
"SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
"InstallationFolder", Path, &RegistrySDKVersion))
return false;
if (Path.empty() || RegistrySDKVersion.empty())
return false;
WindowsSDKIncludeVersion.clear();
WindowsSDKLibVersion.clear();
Major = 0;
std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major);
if (Major <= 7)
return true;
if (Major == 8) {
// Windows SDK 8.x installs libraries in a folder whose names depend on the
// version of the OS you're targeting. By default choose the newest, which
// usually corresponds to the version of the OS you've installed the SDK on.
const char *Tests[] = {"winv6.3", "win8", "win7"};
for (const char *Test : Tests) {
SmallString<128> TestPath(Path);
sys::path::append(TestPath, "Lib", Test);
if (VFS.exists(TestPath)) {
WindowsSDKLibVersion = Test;
break;
}
}
return !WindowsSDKLibVersion.empty();
}
if (Major == 10) {
if (!getWindows10SDKVersionFromPath(VFS, Path, WindowsSDKIncludeVersion))
return false;
WindowsSDKLibVersion = WindowsSDKIncludeVersion;
return true;
}
// Unsupported SDK version
return false;
}
bool getUniversalCRTSdkDir(vfs::FileSystem &VFS, StringRef WinSdkDir,
StringRef WinSdkVersion, StringRef WinSysRoot,
std::string &Path, std::string &UCRTVersion) {
// If /winsdkdir is passed, use it as location for the UCRT too.
// FIXME: Should there be a dedicated /ucrtdir to override /winsdkdir?
int Major;
if (getWindowsSDKDirViaCommandLine(VFS, WinSdkDir, WinSdkVersion, WinSysRoot,
Path, Major, UCRTVersion))
return true;
// FIXME: Try env vars (%UniversalCRTSdkDir%, %UCRTVersion%) before going to
// registry.
// vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry
// for the specific key "KitsRoot10". So do we.
if (!getSystemRegistryString(
"SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10",
Path, nullptr))
return false;
return getWindows10SDKVersionFromPath(VFS, Path, UCRTVersion);
}
bool findVCToolChainViaCommandLine(vfs::FileSystem &VFS, StringRef VCToolsDir,
StringRef VCToolsVersion,
StringRef WinSysRoot, std::string &Path,
ToolsetLayout &VSLayout) {
// Don't validate the input; trust the value supplied by the user.
// The primary motivation is to prevent unnecessary file and registry access.
if (!VCToolsDir.empty() || !WinSysRoot.empty()) {
if (!WinSysRoot.empty()) {
SmallString<128> ToolsPath(WinSysRoot);
sys::path::append(ToolsPath, "VC", "Tools", "MSVC");
std::string ToolsVersion;
if (!VCToolsVersion.empty())
ToolsVersion = VCToolsVersion.str();
else
ToolsVersion = getHighestNumericTupleInDirectory(VFS, ToolsPath);
sys::path::append(ToolsPath, ToolsVersion);
Path = std::string(ToolsPath.str());
} else {
Path = VCToolsDir.str();
}
VSLayout = ToolsetLayout::VS2017OrNewer;
return true;
}
return false;
}
bool findVCToolChainViaEnvironment(vfs::FileSystem &VFS, std::string &Path,
ToolsetLayout &VSLayout) {
// These variables are typically set by vcvarsall.bat
// when launching a developer command prompt.
if (Optional<std::string> VCToolsInstallDir =
sys::Process::GetEnv("VCToolsInstallDir")) {
// This is only set by newer Visual Studios, and it leads straight to
// the toolchain directory.
Path = std::move(*VCToolsInstallDir);
VSLayout = ToolsetLayout::VS2017OrNewer;
return true;
}
if (Optional<std::string> VCInstallDir =
sys::Process::GetEnv("VCINSTALLDIR")) {
// If the previous variable isn't set but this one is, then we've found
// an older Visual Studio. This variable is set by newer Visual Studios too,
// so this check has to appear second.
// In older Visual Studios, the VC directory is the toolchain.
Path = std::move(*VCInstallDir);
VSLayout = ToolsetLayout::OlderVS;
return true;
}
// We couldn't find any VC environment variables. Let's walk through PATH and
// see if it leads us to a VC toolchain bin directory. If it does, pick the
// first one that we find.
if (Optional<std::string> PathEnv = sys::Process::GetEnv("PATH")) {
SmallVector<StringRef, 8> PathEntries;
StringRef(*PathEnv).split(PathEntries, sys::EnvPathSeparator);
for (StringRef PathEntry : PathEntries) {
if (PathEntry.empty())
continue;
SmallString<256> ExeTestPath;
// If cl.exe doesn't exist, then this definitely isn't a VC toolchain.
ExeTestPath = PathEntry;
sys::path::append(ExeTestPath, "cl.exe");
if (!VFS.exists(ExeTestPath))
continue;
// cl.exe existing isn't a conclusive test for a VC toolchain; clang also
// has a cl.exe. So let's check for link.exe too.
ExeTestPath = PathEntry;
sys::path::append(ExeTestPath, "link.exe");
if (!VFS.exists(ExeTestPath))
continue;
// whatever/VC/bin --> old toolchain, VC dir is toolchain dir.
StringRef TestPath = PathEntry;
bool IsBin = sys::path::filename(TestPath).equals_insensitive("bin");
if (!IsBin) {
// Strip any architecture subdir like "amd64".
TestPath = sys::path::parent_path(TestPath);
IsBin = sys::path::filename(TestPath).equals_insensitive("bin");
}
if (IsBin) {
StringRef ParentPath = sys::path::parent_path(TestPath);
StringRef ParentFilename = sys::path::filename(ParentPath);
if (ParentFilename.equals_insensitive("VC")) {
Path = std::string(ParentPath);
VSLayout = ToolsetLayout::OlderVS;
return true;
}
if (ParentFilename.equals_insensitive("x86ret") ||
ParentFilename.equals_insensitive("x86chk") ||
ParentFilename.equals_insensitive("amd64ret") ||
ParentFilename.equals_insensitive("amd64chk")) {
Path = std::string(ParentPath);
VSLayout = ToolsetLayout::DevDivInternal;
return true;
}
} else {
// This could be a new (>=VS2017) toolchain. If it is, we should find
// path components with these prefixes when walking backwards through
// the path.
// Note: empty strings match anything.
StringRef ExpectedPrefixes[] = {"", "Host", "bin", "",
"MSVC", "Tools", "VC"};
auto It = sys::path::rbegin(PathEntry);
auto End = sys::path::rend(PathEntry);
for (StringRef Prefix : ExpectedPrefixes) {
if (It == End)
goto NotAToolChain;
if (!It->startswith_insensitive(Prefix))
goto NotAToolChain;
++It;
}
// We've found a new toolchain!
// Back up 3 times (/bin/Host/arch) to get the root path.
StringRef ToolChainPath(PathEntry);
for (int i = 0; i < 3; ++i)
ToolChainPath = sys::path::parent_path(ToolChainPath);
Path = std::string(ToolChainPath);
VSLayout = ToolsetLayout::VS2017OrNewer;
return true;
}
NotAToolChain:
continue;
}
}
return false;
}
bool findVCToolChainViaSetupConfig(vfs::FileSystem &VFS, std::string &Path,
ToolsetLayout &VSLayout) {
#if !defined(USE_MSVC_SETUP_API)
return false;
#else
// FIXME: This really should be done once in the top-level program's main
// function, as it may have already been initialized with a different
// threading model otherwise.
sys::InitializeCOMRAII COM(sys::COMThreadingMode::SingleThreaded);
HRESULT HR;
// _com_ptr_t will throw a _com_error if a COM calls fail.
// The LLVM coding standards forbid exception handling, so we'll have to
// stop them from being thrown in the first place.
// The destructor will put the regular error handler back when we leave
// this scope.
struct SuppressCOMErrorsRAII {
static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {}
SuppressCOMErrorsRAII() { _set_com_error_handler(handler); }
~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); }
} COMErrorSuppressor;
ISetupConfigurationPtr Query;
HR = Query.CreateInstance(__uuidof(SetupConfiguration));
if (FAILED(HR))
return false;
IEnumSetupInstancesPtr EnumInstances;
HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances);
if (FAILED(HR))
return false;
ISetupInstancePtr Instance;
HR = EnumInstances->Next(1, &Instance, nullptr);
if (HR != S_OK)
return false;
ISetupInstancePtr NewestInstance;
Optional<uint64_t> NewestVersionNum;
do {
bstr_t VersionString;
uint64_t VersionNum;
HR = Instance->GetInstallationVersion(VersionString.GetAddress());
if (FAILED(HR))
continue;
HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum);
if (FAILED(HR))
continue;
if (!NewestVersionNum || (VersionNum > NewestVersionNum)) {
NewestInstance = Instance;
NewestVersionNum = VersionNum;
}
} while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK);
if (!NewestInstance)
return false;
bstr_t VCPathWide;
HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress());
if (FAILED(HR))
return false;
std::string VCRootPath;
convertWideToUTF8(std::wstring(VCPathWide), VCRootPath);
SmallString<256> ToolsVersionFilePath(VCRootPath);
sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build",
"Microsoft.VCToolsVersion.default.txt");
auto ToolsVersionFile = MemoryBuffer::getFile(ToolsVersionFilePath);
if (!ToolsVersionFile)
return false;
SmallString<256> ToolchainPath(VCRootPath);
sys::path::append(ToolchainPath, "Tools", "MSVC",
ToolsVersionFile->get()->getBuffer().rtrim());
auto Status = VFS.status(ToolchainPath);
if (!Status || !Status->isDirectory())
return false;
Path = std::string(ToolchainPath.str());
VSLayout = ToolsetLayout::VS2017OrNewer;
return true;
#endif
}
bool findVCToolChainViaRegistry(std::string &Path, ToolsetLayout &VSLayout) {
std::string VSInstallPath;
if (getSystemRegistryString(R"(SOFTWARE\Microsoft\VisualStudio\$VERSION)",
"InstallDir", VSInstallPath, nullptr) ||
getSystemRegistryString(R"(SOFTWARE\Microsoft\VCExpress\$VERSION)",
"InstallDir", VSInstallPath, nullptr)) {
if (!VSInstallPath.empty()) {
SmallString<256> VCPath(StringRef(VSInstallPath.c_str(),
VSInstallPath.find(R"(\Common7\IDE)")));
sys::path::append(VCPath, "VC");
Path = std::string(VCPath.str());
VSLayout = ToolsetLayout::OlderVS;
return true;
}
}
return false;
}
} // namespace llvm

View File

@ -98,7 +98,6 @@ static_library("Support") {
"MD5.cpp",
"MSP430AttributeParser.cpp",
"MSP430Attributes.cpp",
"MSVCPaths.cpp",
"ManagedStatic.cpp",
"MathExtras.cpp",
"MemAlloc.cpp",

View File

@ -1310,6 +1310,9 @@ cc_library(
"lib/Driver/ToolChains/Arch/*.cpp",
"lib/Driver/ToolChains/Arch/*.h",
],
exclude = [
"lib/Driver/ToolChains/MSVCSetupApi.h",
],
),
hdrs = glob([
"include/clang/Driver/*.h",