forked from OSchip/llvm-project
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:
parent
d5c314cdf4
commit
baac665adf
|
@ -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
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
|
@ -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
|
|
@ -175,7 +175,6 @@ add_llvm_component_library(LLVMSupport
|
|||
MD5.cpp
|
||||
MSP430Attributes.cpp
|
||||
MSP430AttributeParser.cpp
|
||||
MSVCPaths.cpp
|
||||
NativeFormatting.cpp
|
||||
OptimizedStructLayout.cpp
|
||||
Optional.cpp
|
||||
|
|
|
@ -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
|
|
@ -98,7 +98,6 @@ static_library("Support") {
|
|||
"MD5.cpp",
|
||||
"MSP430AttributeParser.cpp",
|
||||
"MSP430Attributes.cpp",
|
||||
"MSVCPaths.cpp",
|
||||
"ManagedStatic.cpp",
|
||||
"MathExtras.cpp",
|
||||
"MemAlloc.cpp",
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue