Author: Adrian Prantl Date: 2022-02-11T13:07:23-08:00 New Revision: baac665adf324672802dcc7037a25468e9569c95
URL: https://github.com/llvm/llvm-project/commit/baac665adf324672802dcc7037a25468e9569c95 DIFF: https://github.com/llvm/llvm-project/commit/baac665adf324672802dcc7037a25468e9569c95.diff LOG: Revert "[lld/coff] Make lld-link work in a non-MSVC shell, add /winsysroot:" This reverts commit b3b2538df100ec7f6587b0ee70819a3c8ee2c27e, it introduced a cycklic module depenency that broke the -DLLVM_ENABLE_MODULES=1 build. Added: clang/lib/Driver/ToolChains/MSVCSetupApi.h Modified: clang/docs/tools/clang-formatted-files.txt clang/lib/Driver/ToolChains/MSVC.cpp clang/lib/Driver/ToolChains/MSVC.h lld/COFF/Driver.cpp lld/COFF/Driver.h lld/COFF/Options.td lld/COFF/SymbolTable.cpp lld/docs/ReleaseNotes.rst llvm/lib/Support/CMakeLists.txt llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn utils/bazel/llvm-project-overlay/clang/BUILD.bazel Removed: lld/test/COFF/winsysroot.test llvm/include/llvm/Support/MSVCPaths.h llvm/include/llvm/Support/MSVCSetupApi.h llvm/lib/Support/MSVCPaths.cpp ################################################################################ diff --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt index 5666ad499d791..c7defa9cd88c6 100644 --- a/clang/docs/tools/clang-formatted-files.txt +++ b/clang/docs/tools/clang-formatted-files.txt @@ -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 diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 36e190f69154b..9f4751167ac12 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.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 diff erent + // 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)) { diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h index fa22919dd1e70..c842773996eda 100644 --- a/clang/lib/Driver/ToolChains/MSVC.h +++ b/clang/lib/Driver/ToolChains/MSVC.h @@ -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 @@ class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain { 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 @@ class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain { 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; }; diff --git a/llvm/include/llvm/Support/MSVCSetupApi.h b/clang/lib/Driver/ToolChains/MSVCSetupApi.h similarity index 100% rename from llvm/include/llvm/Support/MSVCSetupApi.h rename to clang/lib/Driver/ToolChains/MSVCSetupApi.h diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index cbe6979dab76b..1546291e16c6b 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -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( diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h index 17c0c72281985..518ec1470677d 100644 --- a/lld/COFF/Driver.h +++ b/lld/COFF/Driver.h @@ -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 @@ class LinkerDriver { 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 @@ class LinkerDriver { 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 @@ class LinkerDriver { 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. diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td index 7593b99dc05a7..7189088f8be6f 100644 --- a/lld/COFF/Options.td +++ b/lld/COFF/Options.td @@ -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>; diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp index 9bd93a2ff1a7d..db2db9c9272eb 100644 --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -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)); diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst index af09e1e539b87..1a31c13eb8905 100644 --- a/lld/docs/ReleaseNotes.rst +++ b/lld/docs/ReleaseNotes.rst @@ -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 diff --git a/lld/test/COFF/winsysroot.test b/lld/test/COFF/winsysroot.test deleted file mode 100644 index 5abcbce3548e9..0000000000000 --- a/lld/test/COFF/winsysroot.test +++ /dev/null @@ -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' diff --git a/llvm/include/llvm/Support/MSVCPaths.h b/llvm/include/llvm/Support/MSVCPaths.h deleted file mode 100644 index cadc872654b9e..0000000000000 --- a/llvm/include/llvm/Support/MSVCPaths.h +++ /dev/null @@ -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 diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt index d7fc4d2fac1fc..4d9099554192d 100644 --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -175,7 +175,6 @@ add_llvm_component_library(LLVMSupport MD5.cpp MSP430Attributes.cpp MSP430AttributeParser.cpp - MSVCPaths.cpp NativeFormatting.cpp OptimizedStructLayout.cpp Optional.cpp diff --git a/llvm/lib/Support/MSVCPaths.cpp b/llvm/lib/Support/MSVCPaths.cpp deleted file mode 100644 index b0a46ca3bc7b4..0000000000000 --- a/llvm/lib/Support/MSVCPaths.cpp +++ /dev/null @@ -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 diff erent - // 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 diff --git a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn index 254d464ef022c..461b7498978f4 100644 --- a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn @@ -98,7 +98,6 @@ static_library("Support") { "MD5.cpp", "MSP430AttributeParser.cpp", "MSP430Attributes.cpp", - "MSVCPaths.cpp", "ManagedStatic.cpp", "MathExtras.cpp", "MemAlloc.cpp", diff --git a/utils/bazel/llvm-project-overlay/clang/BUILD.bazel b/utils/bazel/llvm-project-overlay/clang/BUILD.bazel index 7fe7cb8553540..43462d77d00ed 100644 --- a/utils/bazel/llvm-project-overlay/clang/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/clang/BUILD.bazel @@ -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", _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits