17330f729Sjoerg //===-- MSVC.cpp - MSVC ToolChain Implementations -------------------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg
97330f729Sjoerg #include "MSVC.h"
107330f729Sjoerg #include "CommonArgs.h"
117330f729Sjoerg #include "Darwin.h"
127330f729Sjoerg #include "clang/Basic/CharInfo.h"
137330f729Sjoerg #include "clang/Basic/Version.h"
14*e038c9c4Sjoerg #include "clang/Config/config.h"
157330f729Sjoerg #include "clang/Driver/Compilation.h"
167330f729Sjoerg #include "clang/Driver/Driver.h"
177330f729Sjoerg #include "clang/Driver/DriverDiagnostic.h"
187330f729Sjoerg #include "clang/Driver/Options.h"
197330f729Sjoerg #include "clang/Driver/SanitizerArgs.h"
207330f729Sjoerg #include "llvm/ADT/StringExtras.h"
217330f729Sjoerg #include "llvm/ADT/StringSwitch.h"
227330f729Sjoerg #include "llvm/Option/Arg.h"
237330f729Sjoerg #include "llvm/Option/ArgList.h"
247330f729Sjoerg #include "llvm/Support/ConvertUTF.h"
257330f729Sjoerg #include "llvm/Support/ErrorHandling.h"
267330f729Sjoerg #include "llvm/Support/FileSystem.h"
277330f729Sjoerg #include "llvm/Support/Host.h"
287330f729Sjoerg #include "llvm/Support/MemoryBuffer.h"
297330f729Sjoerg #include "llvm/Support/Path.h"
307330f729Sjoerg #include "llvm/Support/Process.h"
31*e038c9c4Sjoerg #include "llvm/Support/VirtualFileSystem.h"
327330f729Sjoerg #include <cstdio>
337330f729Sjoerg
347330f729Sjoerg #ifdef _WIN32
357330f729Sjoerg #define WIN32_LEAN_AND_MEAN
367330f729Sjoerg #define NOGDI
377330f729Sjoerg #ifndef NOMINMAX
387330f729Sjoerg #define NOMINMAX
397330f729Sjoerg #endif
407330f729Sjoerg #include <windows.h>
417330f729Sjoerg #endif
427330f729Sjoerg
437330f729Sjoerg #ifdef _MSC_VER
447330f729Sjoerg // Don't support SetupApi on MinGW.
457330f729Sjoerg #define USE_MSVC_SETUP_API
467330f729Sjoerg
477330f729Sjoerg // Make sure this comes before MSVCSetupApi.h
487330f729Sjoerg #include <comdef.h>
497330f729Sjoerg
507330f729Sjoerg #include "MSVCSetupApi.h"
517330f729Sjoerg #include "llvm/Support/COM.h"
527330f729Sjoerg _COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration));
537330f729Sjoerg _COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2));
547330f729Sjoerg _COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper));
557330f729Sjoerg _COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances));
567330f729Sjoerg _COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance));
577330f729Sjoerg _COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2));
587330f729Sjoerg #endif
597330f729Sjoerg
607330f729Sjoerg using namespace clang::driver;
617330f729Sjoerg using namespace clang::driver::toolchains;
627330f729Sjoerg using namespace clang::driver::tools;
637330f729Sjoerg using namespace clang;
647330f729Sjoerg using namespace llvm::opt;
657330f729Sjoerg
canExecute(llvm::vfs::FileSystem & VFS,StringRef Path)66*e038c9c4Sjoerg static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) {
67*e038c9c4Sjoerg auto Status = VFS.status(Path);
68*e038c9c4Sjoerg if (!Status)
69*e038c9c4Sjoerg return false;
70*e038c9c4Sjoerg return (Status->getPermissions() & llvm::sys::fs::perms::all_exe) != 0;
71*e038c9c4Sjoerg }
72*e038c9c4Sjoerg
737330f729Sjoerg // Defined below.
747330f729Sjoerg // Forward declare this so there aren't too many things above the constructor.
757330f729Sjoerg static bool getSystemRegistryString(const char *keyPath, const char *valueName,
767330f729Sjoerg std::string &value, std::string *phValue);
777330f729Sjoerg
getHighestNumericTupleInDirectory(llvm::vfs::FileSystem & VFS,StringRef Directory)78*e038c9c4Sjoerg static std::string getHighestNumericTupleInDirectory(llvm::vfs::FileSystem &VFS,
79*e038c9c4Sjoerg StringRef Directory) {
80*e038c9c4Sjoerg std::string Highest;
81*e038c9c4Sjoerg llvm::VersionTuple HighestTuple;
82*e038c9c4Sjoerg
83*e038c9c4Sjoerg std::error_code EC;
84*e038c9c4Sjoerg for (llvm::vfs::directory_iterator DirIt = VFS.dir_begin(Directory, EC),
85*e038c9c4Sjoerg DirEnd;
86*e038c9c4Sjoerg !EC && DirIt != DirEnd; DirIt.increment(EC)) {
87*e038c9c4Sjoerg auto Status = VFS.status(DirIt->path());
88*e038c9c4Sjoerg if (!Status || !Status->isDirectory())
89*e038c9c4Sjoerg continue;
90*e038c9c4Sjoerg StringRef CandidateName = llvm::sys::path::filename(DirIt->path());
91*e038c9c4Sjoerg llvm::VersionTuple Tuple;
92*e038c9c4Sjoerg if (Tuple.tryParse(CandidateName)) // tryParse() returns true on error.
93*e038c9c4Sjoerg continue;
94*e038c9c4Sjoerg if (Tuple > HighestTuple) {
95*e038c9c4Sjoerg HighestTuple = Tuple;
96*e038c9c4Sjoerg Highest = CandidateName.str();
97*e038c9c4Sjoerg }
98*e038c9c4Sjoerg }
99*e038c9c4Sjoerg
100*e038c9c4Sjoerg return Highest;
101*e038c9c4Sjoerg }
102*e038c9c4Sjoerg
103*e038c9c4Sjoerg // Check command line arguments to try and find a toolchain.
104*e038c9c4Sjoerg static bool
findVCToolChainViaCommandLine(llvm::vfs::FileSystem & VFS,const ArgList & Args,std::string & Path,MSVCToolChain::ToolsetLayout & VSLayout)105*e038c9c4Sjoerg findVCToolChainViaCommandLine(llvm::vfs::FileSystem &VFS, const ArgList &Args,
106*e038c9c4Sjoerg std::string &Path,
107*e038c9c4Sjoerg MSVCToolChain::ToolsetLayout &VSLayout) {
108*e038c9c4Sjoerg // Don't validate the input; trust the value supplied by the user.
109*e038c9c4Sjoerg // The primary motivation is to prevent unnecessary file and registry access.
110*e038c9c4Sjoerg if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir,
111*e038c9c4Sjoerg options::OPT__SLASH_winsysroot)) {
112*e038c9c4Sjoerg if (A->getOption().getID() == options::OPT__SLASH_winsysroot) {
113*e038c9c4Sjoerg llvm::SmallString<128> ToolsPath(A->getValue());
114*e038c9c4Sjoerg llvm::sys::path::append(ToolsPath, "VC", "Tools", "MSVC");
115*e038c9c4Sjoerg std::string VCToolsVersion;
116*e038c9c4Sjoerg if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion))
117*e038c9c4Sjoerg VCToolsVersion = A->getValue();
118*e038c9c4Sjoerg else
119*e038c9c4Sjoerg VCToolsVersion = getHighestNumericTupleInDirectory(VFS, ToolsPath);
120*e038c9c4Sjoerg llvm::sys::path::append(ToolsPath, VCToolsVersion);
121*e038c9c4Sjoerg Path = std::string(ToolsPath.str());
122*e038c9c4Sjoerg } else {
123*e038c9c4Sjoerg Path = A->getValue();
124*e038c9c4Sjoerg }
125*e038c9c4Sjoerg VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
126*e038c9c4Sjoerg return true;
127*e038c9c4Sjoerg }
128*e038c9c4Sjoerg return false;
129*e038c9c4Sjoerg }
130*e038c9c4Sjoerg
1317330f729Sjoerg // Check various environment variables to try and find a toolchain.
132*e038c9c4Sjoerg static bool
findVCToolChainViaEnvironment(llvm::vfs::FileSystem & VFS,std::string & Path,MSVCToolChain::ToolsetLayout & VSLayout)133*e038c9c4Sjoerg findVCToolChainViaEnvironment(llvm::vfs::FileSystem &VFS, std::string &Path,
1347330f729Sjoerg MSVCToolChain::ToolsetLayout &VSLayout) {
1357330f729Sjoerg // These variables are typically set by vcvarsall.bat
1367330f729Sjoerg // when launching a developer command prompt.
1377330f729Sjoerg if (llvm::Optional<std::string> VCToolsInstallDir =
1387330f729Sjoerg llvm::sys::Process::GetEnv("VCToolsInstallDir")) {
1397330f729Sjoerg // This is only set by newer Visual Studios, and it leads straight to
1407330f729Sjoerg // the toolchain directory.
1417330f729Sjoerg Path = std::move(*VCToolsInstallDir);
1427330f729Sjoerg VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
1437330f729Sjoerg return true;
1447330f729Sjoerg }
1457330f729Sjoerg if (llvm::Optional<std::string> VCInstallDir =
1467330f729Sjoerg llvm::sys::Process::GetEnv("VCINSTALLDIR")) {
1477330f729Sjoerg // If the previous variable isn't set but this one is, then we've found
1487330f729Sjoerg // an older Visual Studio. This variable is set by newer Visual Studios too,
1497330f729Sjoerg // so this check has to appear second.
1507330f729Sjoerg // In older Visual Studios, the VC directory is the toolchain.
1517330f729Sjoerg Path = std::move(*VCInstallDir);
1527330f729Sjoerg VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
1537330f729Sjoerg return true;
1547330f729Sjoerg }
1557330f729Sjoerg
1567330f729Sjoerg // We couldn't find any VC environment variables. Let's walk through PATH and
1577330f729Sjoerg // see if it leads us to a VC toolchain bin directory. If it does, pick the
1587330f729Sjoerg // first one that we find.
1597330f729Sjoerg if (llvm::Optional<std::string> PathEnv =
1607330f729Sjoerg llvm::sys::Process::GetEnv("PATH")) {
1617330f729Sjoerg llvm::SmallVector<llvm::StringRef, 8> PathEntries;
1627330f729Sjoerg llvm::StringRef(*PathEnv).split(PathEntries, llvm::sys::EnvPathSeparator);
1637330f729Sjoerg for (llvm::StringRef PathEntry : PathEntries) {
1647330f729Sjoerg if (PathEntry.empty())
1657330f729Sjoerg continue;
1667330f729Sjoerg
1677330f729Sjoerg llvm::SmallString<256> ExeTestPath;
1687330f729Sjoerg
1697330f729Sjoerg // If cl.exe doesn't exist, then this definitely isn't a VC toolchain.
1707330f729Sjoerg ExeTestPath = PathEntry;
1717330f729Sjoerg llvm::sys::path::append(ExeTestPath, "cl.exe");
172*e038c9c4Sjoerg if (!VFS.exists(ExeTestPath))
1737330f729Sjoerg continue;
1747330f729Sjoerg
1757330f729Sjoerg // cl.exe existing isn't a conclusive test for a VC toolchain; clang also
1767330f729Sjoerg // has a cl.exe. So let's check for link.exe too.
1777330f729Sjoerg ExeTestPath = PathEntry;
1787330f729Sjoerg llvm::sys::path::append(ExeTestPath, "link.exe");
179*e038c9c4Sjoerg if (!VFS.exists(ExeTestPath))
1807330f729Sjoerg continue;
1817330f729Sjoerg
1827330f729Sjoerg // whatever/VC/bin --> old toolchain, VC dir is toolchain dir.
1837330f729Sjoerg llvm::StringRef TestPath = PathEntry;
1847330f729Sjoerg bool IsBin = llvm::sys::path::filename(TestPath).equals_lower("bin");
1857330f729Sjoerg if (!IsBin) {
1867330f729Sjoerg // Strip any architecture subdir like "amd64".
1877330f729Sjoerg TestPath = llvm::sys::path::parent_path(TestPath);
1887330f729Sjoerg IsBin = llvm::sys::path::filename(TestPath).equals_lower("bin");
1897330f729Sjoerg }
1907330f729Sjoerg if (IsBin) {
1917330f729Sjoerg llvm::StringRef ParentPath = llvm::sys::path::parent_path(TestPath);
1927330f729Sjoerg llvm::StringRef ParentFilename = llvm::sys::path::filename(ParentPath);
193*e038c9c4Sjoerg if (ParentFilename.equals_lower("VC")) {
194*e038c9c4Sjoerg Path = std::string(ParentPath);
1957330f729Sjoerg VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
1967330f729Sjoerg return true;
1977330f729Sjoerg }
198*e038c9c4Sjoerg if (ParentFilename.equals_lower("x86ret") ||
199*e038c9c4Sjoerg ParentFilename.equals_lower("x86chk") ||
200*e038c9c4Sjoerg ParentFilename.equals_lower("amd64ret") ||
201*e038c9c4Sjoerg ParentFilename.equals_lower("amd64chk")) {
202*e038c9c4Sjoerg Path = std::string(ParentPath);
2037330f729Sjoerg VSLayout = MSVCToolChain::ToolsetLayout::DevDivInternal;
2047330f729Sjoerg return true;
2057330f729Sjoerg }
2067330f729Sjoerg
2077330f729Sjoerg } else {
2087330f729Sjoerg // This could be a new (>=VS2017) toolchain. If it is, we should find
2097330f729Sjoerg // path components with these prefixes when walking backwards through
2107330f729Sjoerg // the path.
2117330f729Sjoerg // Note: empty strings match anything.
2127330f729Sjoerg llvm::StringRef ExpectedPrefixes[] = {"", "Host", "bin", "",
2137330f729Sjoerg "MSVC", "Tools", "VC"};
2147330f729Sjoerg
2157330f729Sjoerg auto It = llvm::sys::path::rbegin(PathEntry);
2167330f729Sjoerg auto End = llvm::sys::path::rend(PathEntry);
2177330f729Sjoerg for (llvm::StringRef Prefix : ExpectedPrefixes) {
2187330f729Sjoerg if (It == End)
2197330f729Sjoerg goto NotAToolChain;
220*e038c9c4Sjoerg if (!It->startswith_lower(Prefix))
2217330f729Sjoerg goto NotAToolChain;
2227330f729Sjoerg ++It;
2237330f729Sjoerg }
2247330f729Sjoerg
2257330f729Sjoerg // We've found a new toolchain!
2267330f729Sjoerg // Back up 3 times (/bin/Host/arch) to get the root path.
2277330f729Sjoerg llvm::StringRef ToolChainPath(PathEntry);
2287330f729Sjoerg for (int i = 0; i < 3; ++i)
2297330f729Sjoerg ToolChainPath = llvm::sys::path::parent_path(ToolChainPath);
2307330f729Sjoerg
231*e038c9c4Sjoerg Path = std::string(ToolChainPath);
2327330f729Sjoerg VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
2337330f729Sjoerg return true;
2347330f729Sjoerg }
2357330f729Sjoerg
2367330f729Sjoerg NotAToolChain:
2377330f729Sjoerg continue;
2387330f729Sjoerg }
2397330f729Sjoerg }
2407330f729Sjoerg return false;
2417330f729Sjoerg }
2427330f729Sjoerg
2437330f729Sjoerg // Query the Setup Config server for installs, then pick the newest version
2447330f729Sjoerg // and find its default VC toolchain.
2457330f729Sjoerg // This is the preferred way to discover new Visual Studios, as they're no
2467330f729Sjoerg // longer listed in the registry.
247*e038c9c4Sjoerg static bool
findVCToolChainViaSetupConfig(llvm::vfs::FileSystem & VFS,std::string & Path,MSVCToolChain::ToolsetLayout & VSLayout)248*e038c9c4Sjoerg findVCToolChainViaSetupConfig(llvm::vfs::FileSystem &VFS, std::string &Path,
2497330f729Sjoerg MSVCToolChain::ToolsetLayout &VSLayout) {
2507330f729Sjoerg #if !defined(USE_MSVC_SETUP_API)
2517330f729Sjoerg return false;
2527330f729Sjoerg #else
2537330f729Sjoerg // FIXME: This really should be done once in the top-level program's main
2547330f729Sjoerg // function, as it may have already been initialized with a different
2557330f729Sjoerg // threading model otherwise.
2567330f729Sjoerg llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::SingleThreaded);
2577330f729Sjoerg HRESULT HR;
2587330f729Sjoerg
2597330f729Sjoerg // _com_ptr_t will throw a _com_error if a COM calls fail.
2607330f729Sjoerg // The LLVM coding standards forbid exception handling, so we'll have to
2617330f729Sjoerg // stop them from being thrown in the first place.
2627330f729Sjoerg // The destructor will put the regular error handler back when we leave
2637330f729Sjoerg // this scope.
2647330f729Sjoerg struct SuppressCOMErrorsRAII {
2657330f729Sjoerg static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {}
2667330f729Sjoerg
2677330f729Sjoerg SuppressCOMErrorsRAII() { _set_com_error_handler(handler); }
2687330f729Sjoerg
2697330f729Sjoerg ~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); }
2707330f729Sjoerg
2717330f729Sjoerg } COMErrorSuppressor;
2727330f729Sjoerg
2737330f729Sjoerg ISetupConfigurationPtr Query;
2747330f729Sjoerg HR = Query.CreateInstance(__uuidof(SetupConfiguration));
2757330f729Sjoerg if (FAILED(HR))
2767330f729Sjoerg return false;
2777330f729Sjoerg
2787330f729Sjoerg IEnumSetupInstancesPtr EnumInstances;
2797330f729Sjoerg HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances);
2807330f729Sjoerg if (FAILED(HR))
2817330f729Sjoerg return false;
2827330f729Sjoerg
2837330f729Sjoerg ISetupInstancePtr Instance;
2847330f729Sjoerg HR = EnumInstances->Next(1, &Instance, nullptr);
2857330f729Sjoerg if (HR != S_OK)
2867330f729Sjoerg return false;
2877330f729Sjoerg
2887330f729Sjoerg ISetupInstancePtr NewestInstance;
2897330f729Sjoerg Optional<uint64_t> NewestVersionNum;
2907330f729Sjoerg do {
2917330f729Sjoerg bstr_t VersionString;
2927330f729Sjoerg uint64_t VersionNum;
2937330f729Sjoerg HR = Instance->GetInstallationVersion(VersionString.GetAddress());
2947330f729Sjoerg if (FAILED(HR))
2957330f729Sjoerg continue;
2967330f729Sjoerg HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum);
2977330f729Sjoerg if (FAILED(HR))
2987330f729Sjoerg continue;
2997330f729Sjoerg if (!NewestVersionNum || (VersionNum > NewestVersionNum)) {
3007330f729Sjoerg NewestInstance = Instance;
3017330f729Sjoerg NewestVersionNum = VersionNum;
3027330f729Sjoerg }
3037330f729Sjoerg } while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK);
3047330f729Sjoerg
3057330f729Sjoerg if (!NewestInstance)
3067330f729Sjoerg return false;
3077330f729Sjoerg
3087330f729Sjoerg bstr_t VCPathWide;
3097330f729Sjoerg HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress());
3107330f729Sjoerg if (FAILED(HR))
3117330f729Sjoerg return false;
3127330f729Sjoerg
3137330f729Sjoerg std::string VCRootPath;
3147330f729Sjoerg llvm::convertWideToUTF8(std::wstring(VCPathWide), VCRootPath);
3157330f729Sjoerg
3167330f729Sjoerg llvm::SmallString<256> ToolsVersionFilePath(VCRootPath);
3177330f729Sjoerg llvm::sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build",
3187330f729Sjoerg "Microsoft.VCToolsVersion.default.txt");
3197330f729Sjoerg
3207330f729Sjoerg auto ToolsVersionFile = llvm::MemoryBuffer::getFile(ToolsVersionFilePath);
3217330f729Sjoerg if (!ToolsVersionFile)
3227330f729Sjoerg return false;
3237330f729Sjoerg
3247330f729Sjoerg llvm::SmallString<256> ToolchainPath(VCRootPath);
3257330f729Sjoerg llvm::sys::path::append(ToolchainPath, "Tools", "MSVC",
3267330f729Sjoerg ToolsVersionFile->get()->getBuffer().rtrim());
327*e038c9c4Sjoerg auto Status = VFS.status(ToolchainPath);
328*e038c9c4Sjoerg if (!Status || !Status->isDirectory())
3297330f729Sjoerg return false;
3307330f729Sjoerg
331*e038c9c4Sjoerg Path = std::string(ToolchainPath.str());
3327330f729Sjoerg VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
3337330f729Sjoerg return true;
3347330f729Sjoerg #endif
3357330f729Sjoerg }
3367330f729Sjoerg
3377330f729Sjoerg // Look in the registry for Visual Studio installs, and use that to get
3387330f729Sjoerg // a toolchain path. VS2017 and newer don't get added to the registry.
3397330f729Sjoerg // So if we find something here, we know that it's an older version.
findVCToolChainViaRegistry(std::string & Path,MSVCToolChain::ToolsetLayout & VSLayout)3407330f729Sjoerg static bool findVCToolChainViaRegistry(std::string &Path,
3417330f729Sjoerg MSVCToolChain::ToolsetLayout &VSLayout) {
3427330f729Sjoerg std::string VSInstallPath;
3437330f729Sjoerg if (getSystemRegistryString(R"(SOFTWARE\Microsoft\VisualStudio\$VERSION)",
3447330f729Sjoerg "InstallDir", VSInstallPath, nullptr) ||
3457330f729Sjoerg getSystemRegistryString(R"(SOFTWARE\Microsoft\VCExpress\$VERSION)",
3467330f729Sjoerg "InstallDir", VSInstallPath, nullptr)) {
3477330f729Sjoerg if (!VSInstallPath.empty()) {
3487330f729Sjoerg llvm::SmallString<256> VCPath(llvm::StringRef(
3497330f729Sjoerg VSInstallPath.c_str(), VSInstallPath.find(R"(\Common7\IDE)")));
3507330f729Sjoerg llvm::sys::path::append(VCPath, "VC");
3517330f729Sjoerg
352*e038c9c4Sjoerg Path = std::string(VCPath.str());
3537330f729Sjoerg VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
3547330f729Sjoerg return true;
3557330f729Sjoerg }
3567330f729Sjoerg }
3577330f729Sjoerg return false;
3587330f729Sjoerg }
3597330f729Sjoerg
3607330f729Sjoerg // Try to find Exe from a Visual Studio distribution. This first tries to find
3617330f729Sjoerg // an installed copy of Visual Studio and, failing that, looks in the PATH,
3627330f729Sjoerg // making sure that whatever executable that's found is not a same-named exe
3637330f729Sjoerg // from clang itself to prevent clang from falling back to itself.
FindVisualStudioExecutable(const ToolChain & TC,const char * Exe)3647330f729Sjoerg static std::string FindVisualStudioExecutable(const ToolChain &TC,
3657330f729Sjoerg const char *Exe) {
3667330f729Sjoerg const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);
3677330f729Sjoerg SmallString<128> FilePath(MSVC.getSubDirectoryPath(
3687330f729Sjoerg toolchains::MSVCToolChain::SubDirectoryType::Bin));
3697330f729Sjoerg llvm::sys::path::append(FilePath, Exe);
370*e038c9c4Sjoerg return std::string(canExecute(TC.getVFS(), FilePath) ? FilePath.str() : Exe);
3717330f729Sjoerg }
3727330f729Sjoerg
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const3737330f729Sjoerg void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
3747330f729Sjoerg const InputInfo &Output,
3757330f729Sjoerg const InputInfoList &Inputs,
3767330f729Sjoerg const ArgList &Args,
3777330f729Sjoerg const char *LinkingOutput) const {
3787330f729Sjoerg ArgStringList CmdArgs;
3797330f729Sjoerg
3807330f729Sjoerg auto &TC = static_cast<const toolchains::MSVCToolChain &>(getToolChain());
3817330f729Sjoerg
3827330f729Sjoerg assert((Output.isFilename() || Output.isNothing()) && "invalid output");
3837330f729Sjoerg if (Output.isFilename())
3847330f729Sjoerg CmdArgs.push_back(
3857330f729Sjoerg Args.MakeArgString(std::string("-out:") + Output.getFilename()));
3867330f729Sjoerg
3877330f729Sjoerg if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) &&
388*e038c9c4Sjoerg !C.getDriver().IsCLMode()) {
3897330f729Sjoerg CmdArgs.push_back("-defaultlib:libcmt");
390*e038c9c4Sjoerg CmdArgs.push_back("-defaultlib:oldnames");
391*e038c9c4Sjoerg }
3927330f729Sjoerg
3937330f729Sjoerg // If the VC environment hasn't been configured (perhaps because the user
3947330f729Sjoerg // did not run vcvarsall), try to build a consistent link environment. If
3957330f729Sjoerg // the environment variable is set however, assume the user knows what
396*e038c9c4Sjoerg // they're doing. If the user passes /vctoolsdir or /winsdkdir, trust that
397*e038c9c4Sjoerg // over env vars.
398*e038c9c4Sjoerg if (!llvm::sys::Process::GetEnv("LIB") ||
399*e038c9c4Sjoerg Args.getLastArg(options::OPT__SLASH_vctoolsdir,
400*e038c9c4Sjoerg options::OPT__SLASH_winsysroot)) {
4017330f729Sjoerg CmdArgs.push_back(Args.MakeArgString(
4027330f729Sjoerg Twine("-libpath:") +
4037330f729Sjoerg TC.getSubDirectoryPath(
4047330f729Sjoerg toolchains::MSVCToolChain::SubDirectoryType::Lib)));
4057330f729Sjoerg CmdArgs.push_back(Args.MakeArgString(
4067330f729Sjoerg Twine("-libpath:") +
4077330f729Sjoerg TC.getSubDirectoryPath(toolchains::MSVCToolChain::SubDirectoryType::Lib,
4087330f729Sjoerg "atlmfc")));
409*e038c9c4Sjoerg }
410*e038c9c4Sjoerg if (!llvm::sys::Process::GetEnv("LIB") ||
411*e038c9c4Sjoerg Args.getLastArg(options::OPT__SLASH_winsdkdir,
412*e038c9c4Sjoerg options::OPT__SLASH_winsysroot)) {
4137330f729Sjoerg if (TC.useUniversalCRT()) {
4147330f729Sjoerg std::string UniversalCRTLibPath;
415*e038c9c4Sjoerg if (TC.getUniversalCRTLibraryPath(Args, UniversalCRTLibPath))
4167330f729Sjoerg CmdArgs.push_back(
4177330f729Sjoerg Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath));
4187330f729Sjoerg }
4197330f729Sjoerg std::string WindowsSdkLibPath;
420*e038c9c4Sjoerg if (TC.getWindowsSDKLibraryPath(Args, WindowsSdkLibPath))
4217330f729Sjoerg CmdArgs.push_back(
4227330f729Sjoerg Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
4237330f729Sjoerg }
4247330f729Sjoerg
425*e038c9c4Sjoerg // Add the compiler-rt library directories to libpath if they exist to help
426*e038c9c4Sjoerg // the linker find the various sanitizer, builtin, and profiling runtimes.
427*e038c9c4Sjoerg for (const auto &LibPath : TC.getLibraryPaths()) {
428*e038c9c4Sjoerg if (TC.getVFS().exists(LibPath))
429*e038c9c4Sjoerg CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));
430*e038c9c4Sjoerg }
431*e038c9c4Sjoerg auto CRTPath = TC.getCompilerRTPath();
432*e038c9c4Sjoerg if (TC.getVFS().exists(CRTPath))
433*e038c9c4Sjoerg CmdArgs.push_back(Args.MakeArgString("-libpath:" + CRTPath));
434*e038c9c4Sjoerg
4357330f729Sjoerg if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L))
4367330f729Sjoerg for (const auto &LibPath : Args.getAllArgValues(options::OPT_L))
4377330f729Sjoerg CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));
4387330f729Sjoerg
4397330f729Sjoerg CmdArgs.push_back("-nologo");
4407330f729Sjoerg
441*e038c9c4Sjoerg if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7))
4427330f729Sjoerg CmdArgs.push_back("-debug");
4437330f729Sjoerg
4447330f729Sjoerg // Pass on /Brepro if it was passed to the compiler.
4457330f729Sjoerg // Note that /Brepro maps to -mno-incremental-linker-compatible.
4467330f729Sjoerg bool DefaultIncrementalLinkerCompatible =
4477330f729Sjoerg C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment();
4487330f729Sjoerg if (!Args.hasFlag(options::OPT_mincremental_linker_compatible,
4497330f729Sjoerg options::OPT_mno_incremental_linker_compatible,
4507330f729Sjoerg DefaultIncrementalLinkerCompatible))
4517330f729Sjoerg CmdArgs.push_back("-Brepro");
4527330f729Sjoerg
4537330f729Sjoerg bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd,
4547330f729Sjoerg options::OPT_shared);
4557330f729Sjoerg if (DLL) {
4567330f729Sjoerg CmdArgs.push_back(Args.MakeArgString("-dll"));
4577330f729Sjoerg
4587330f729Sjoerg SmallString<128> ImplibName(Output.getFilename());
4597330f729Sjoerg llvm::sys::path::replace_extension(ImplibName, "lib");
4607330f729Sjoerg CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName));
4617330f729Sjoerg }
4627330f729Sjoerg
4637330f729Sjoerg if (TC.getSanitizerArgs().needsFuzzer()) {
4647330f729Sjoerg if (!Args.hasArg(options::OPT_shared))
4657330f729Sjoerg CmdArgs.push_back(
4667330f729Sjoerg Args.MakeArgString(std::string("-wholearchive:") +
4677330f729Sjoerg TC.getCompilerRTArgString(Args, "fuzzer")));
4687330f729Sjoerg CmdArgs.push_back(Args.MakeArgString("-debug"));
4697330f729Sjoerg // Prevent the linker from padding sections we use for instrumentation
4707330f729Sjoerg // arrays.
4717330f729Sjoerg CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
4727330f729Sjoerg }
4737330f729Sjoerg
4747330f729Sjoerg if (TC.getSanitizerArgs().needsAsanRt()) {
4757330f729Sjoerg CmdArgs.push_back(Args.MakeArgString("-debug"));
4767330f729Sjoerg CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
4777330f729Sjoerg if (TC.getSanitizerArgs().needsSharedRt() ||
4787330f729Sjoerg Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) {
4797330f729Sjoerg for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"})
4807330f729Sjoerg CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
4817330f729Sjoerg // Make sure the dynamic runtime thunk is not optimized out at link time
4827330f729Sjoerg // to ensure proper SEH handling.
4837330f729Sjoerg CmdArgs.push_back(Args.MakeArgString(
4847330f729Sjoerg TC.getArch() == llvm::Triple::x86
4857330f729Sjoerg ? "-include:___asan_seh_interceptor"
4867330f729Sjoerg : "-include:__asan_seh_interceptor"));
4877330f729Sjoerg // Make sure the linker consider all object files from the dynamic runtime
4887330f729Sjoerg // thunk.
4897330f729Sjoerg CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") +
4907330f729Sjoerg TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk")));
4917330f729Sjoerg } else if (DLL) {
4927330f729Sjoerg CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk"));
4937330f729Sjoerg } else {
4947330f729Sjoerg for (const auto &Lib : {"asan", "asan_cxx"}) {
4957330f729Sjoerg CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
4967330f729Sjoerg // Make sure the linker consider all object files from the static lib.
4977330f729Sjoerg // This is necessary because instrumented dlls need access to all the
4987330f729Sjoerg // interface exported by the static lib in the main executable.
4997330f729Sjoerg CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") +
5007330f729Sjoerg TC.getCompilerRT(Args, Lib)));
5017330f729Sjoerg }
5027330f729Sjoerg }
5037330f729Sjoerg }
5047330f729Sjoerg
5057330f729Sjoerg Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);
5067330f729Sjoerg
5077330f729Sjoerg // Control Flow Guard checks
5087330f729Sjoerg if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) {
5097330f729Sjoerg StringRef GuardArgs = A->getValue();
5107330f729Sjoerg if (GuardArgs.equals_lower("cf") || GuardArgs.equals_lower("cf,nochecks")) {
5117330f729Sjoerg // MSVC doesn't yet support the "nochecks" modifier.
5127330f729Sjoerg CmdArgs.push_back("-guard:cf");
5137330f729Sjoerg } else if (GuardArgs.equals_lower("cf-")) {
5147330f729Sjoerg CmdArgs.push_back("-guard:cf-");
515*e038c9c4Sjoerg } else if (GuardArgs.equals_lower("ehcont")) {
516*e038c9c4Sjoerg CmdArgs.push_back("-guard:ehcont");
517*e038c9c4Sjoerg } else if (GuardArgs.equals_lower("ehcont-")) {
518*e038c9c4Sjoerg CmdArgs.push_back("-guard:ehcont-");
5197330f729Sjoerg }
5207330f729Sjoerg }
5217330f729Sjoerg
5227330f729Sjoerg if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
5237330f729Sjoerg options::OPT_fno_openmp, false)) {
5247330f729Sjoerg CmdArgs.push_back("-nodefaultlib:vcomp.lib");
5257330f729Sjoerg CmdArgs.push_back("-nodefaultlib:vcompd.lib");
5267330f729Sjoerg CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") +
5277330f729Sjoerg TC.getDriver().Dir + "/../lib"));
5287330f729Sjoerg switch (TC.getDriver().getOpenMPRuntime(Args)) {
5297330f729Sjoerg case Driver::OMPRT_OMP:
5307330f729Sjoerg CmdArgs.push_back("-defaultlib:libomp.lib");
5317330f729Sjoerg break;
5327330f729Sjoerg case Driver::OMPRT_IOMP5:
5337330f729Sjoerg CmdArgs.push_back("-defaultlib:libiomp5md.lib");
5347330f729Sjoerg break;
5357330f729Sjoerg case Driver::OMPRT_GOMP:
5367330f729Sjoerg break;
5377330f729Sjoerg case Driver::OMPRT_Unknown:
5387330f729Sjoerg // Already diagnosed.
5397330f729Sjoerg break;
5407330f729Sjoerg }
5417330f729Sjoerg }
5427330f729Sjoerg
5437330f729Sjoerg // Add compiler-rt lib in case if it was explicitly
5447330f729Sjoerg // specified as an argument for --rtlib option.
5457330f729Sjoerg if (!Args.hasArg(options::OPT_nostdlib)) {
5467330f729Sjoerg AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args);
5477330f729Sjoerg }
5487330f729Sjoerg
5497330f729Sjoerg // Add filenames, libraries, and other linker inputs.
5507330f729Sjoerg for (const auto &Input : Inputs) {
5517330f729Sjoerg if (Input.isFilename()) {
5527330f729Sjoerg CmdArgs.push_back(Input.getFilename());
5537330f729Sjoerg continue;
5547330f729Sjoerg }
5557330f729Sjoerg
5567330f729Sjoerg const Arg &A = Input.getInputArg();
5577330f729Sjoerg
5587330f729Sjoerg // Render -l options differently for the MSVC linker.
5597330f729Sjoerg if (A.getOption().matches(options::OPT_l)) {
5607330f729Sjoerg StringRef Lib = A.getValue();
5617330f729Sjoerg const char *LinkLibArg;
5627330f729Sjoerg if (Lib.endswith(".lib"))
5637330f729Sjoerg LinkLibArg = Args.MakeArgString(Lib);
5647330f729Sjoerg else
5657330f729Sjoerg LinkLibArg = Args.MakeArgString(Lib + ".lib");
5667330f729Sjoerg CmdArgs.push_back(LinkLibArg);
5677330f729Sjoerg continue;
5687330f729Sjoerg }
5697330f729Sjoerg
5707330f729Sjoerg // Otherwise, this is some other kind of linker input option like -Wl, -z,
5717330f729Sjoerg // or -L. Render it, even if MSVC doesn't understand it.
5727330f729Sjoerg A.renderAsInput(Args, CmdArgs);
5737330f729Sjoerg }
5747330f729Sjoerg
5757330f729Sjoerg TC.addProfileRTLibs(Args, CmdArgs);
5767330f729Sjoerg
5777330f729Sjoerg std::vector<const char *> Environment;
5787330f729Sjoerg
5797330f729Sjoerg // We need to special case some linker paths. In the case of lld, we need to
5807330f729Sjoerg // translate 'lld' into 'lld-link', and in the case of the regular msvc
5817330f729Sjoerg // linker, we need to use a special search algorithm.
5827330f729Sjoerg llvm::SmallString<128> linkPath;
583*e038c9c4Sjoerg StringRef Linker
584*e038c9c4Sjoerg = Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER);
585*e038c9c4Sjoerg if (Linker.empty())
586*e038c9c4Sjoerg Linker = "link";
5877330f729Sjoerg if (Linker.equals_lower("lld"))
5887330f729Sjoerg Linker = "lld-link";
5897330f729Sjoerg
5907330f729Sjoerg if (Linker.equals_lower("link")) {
5917330f729Sjoerg // If we're using the MSVC linker, it's not sufficient to just use link
5927330f729Sjoerg // from the program PATH, because other environments like GnuWin32 install
5937330f729Sjoerg // their own link.exe which may come first.
5947330f729Sjoerg linkPath = FindVisualStudioExecutable(TC, "link.exe");
5957330f729Sjoerg
596*e038c9c4Sjoerg if (!TC.FoundMSVCInstall() && !canExecute(TC.getVFS(), linkPath)) {
5977330f729Sjoerg llvm::SmallString<128> ClPath;
5987330f729Sjoerg ClPath = TC.GetProgramPath("cl.exe");
599*e038c9c4Sjoerg if (canExecute(TC.getVFS(), ClPath)) {
6007330f729Sjoerg linkPath = llvm::sys::path::parent_path(ClPath);
6017330f729Sjoerg llvm::sys::path::append(linkPath, "link.exe");
602*e038c9c4Sjoerg if (!canExecute(TC.getVFS(), linkPath))
6037330f729Sjoerg C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found);
6047330f729Sjoerg } else {
6057330f729Sjoerg C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found);
6067330f729Sjoerg }
6077330f729Sjoerg }
6087330f729Sjoerg
6097330f729Sjoerg #ifdef _WIN32
6107330f729Sjoerg // When cross-compiling with VS2017 or newer, link.exe expects to have
6117330f729Sjoerg // its containing bin directory at the top of PATH, followed by the
6127330f729Sjoerg // native target bin directory.
6137330f729Sjoerg // e.g. when compiling for x86 on an x64 host, PATH should start with:
6147330f729Sjoerg // /bin/Hostx64/x86;/bin/Hostx64/x64
6157330f729Sjoerg // This doesn't attempt to handle ToolsetLayout::DevDivInternal.
6167330f729Sjoerg if (TC.getIsVS2017OrNewer() &&
6177330f729Sjoerg llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) {
6187330f729Sjoerg auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch();
6197330f729Sjoerg
6207330f729Sjoerg auto EnvBlockWide =
6217330f729Sjoerg std::unique_ptr<wchar_t[], decltype(&FreeEnvironmentStringsW)>(
6227330f729Sjoerg GetEnvironmentStringsW(), FreeEnvironmentStringsW);
6237330f729Sjoerg if (!EnvBlockWide)
6247330f729Sjoerg goto SkipSettingEnvironment;
6257330f729Sjoerg
6267330f729Sjoerg size_t EnvCount = 0;
6277330f729Sjoerg size_t EnvBlockLen = 0;
6287330f729Sjoerg while (EnvBlockWide[EnvBlockLen] != L'\0') {
6297330f729Sjoerg ++EnvCount;
6307330f729Sjoerg EnvBlockLen += std::wcslen(&EnvBlockWide[EnvBlockLen]) +
6317330f729Sjoerg 1 /*string null-terminator*/;
6327330f729Sjoerg }
6337330f729Sjoerg ++EnvBlockLen; // add the block null-terminator
6347330f729Sjoerg
6357330f729Sjoerg std::string EnvBlock;
6367330f729Sjoerg if (!llvm::convertUTF16ToUTF8String(
6377330f729Sjoerg llvm::ArrayRef<char>(reinterpret_cast<char *>(EnvBlockWide.get()),
6387330f729Sjoerg EnvBlockLen * sizeof(EnvBlockWide[0])),
6397330f729Sjoerg EnvBlock))
6407330f729Sjoerg goto SkipSettingEnvironment;
6417330f729Sjoerg
6427330f729Sjoerg Environment.reserve(EnvCount);
6437330f729Sjoerg
6447330f729Sjoerg // Now loop over each string in the block and copy them into the
6457330f729Sjoerg // environment vector, adjusting the PATH variable as needed when we
6467330f729Sjoerg // find it.
6477330f729Sjoerg for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) {
6487330f729Sjoerg llvm::StringRef EnvVar(Cursor);
6497330f729Sjoerg if (EnvVar.startswith_lower("path=")) {
6507330f729Sjoerg using SubDirectoryType = toolchains::MSVCToolChain::SubDirectoryType;
6517330f729Sjoerg constexpr size_t PrefixLen = 5; // strlen("path=")
6527330f729Sjoerg Environment.push_back(Args.MakeArgString(
6537330f729Sjoerg EnvVar.substr(0, PrefixLen) +
6547330f729Sjoerg TC.getSubDirectoryPath(SubDirectoryType::Bin) +
6557330f729Sjoerg llvm::Twine(llvm::sys::EnvPathSeparator) +
6567330f729Sjoerg TC.getSubDirectoryPath(SubDirectoryType::Bin, "", HostArch) +
6577330f729Sjoerg (EnvVar.size() > PrefixLen
6587330f729Sjoerg ? llvm::Twine(llvm::sys::EnvPathSeparator) +
6597330f729Sjoerg EnvVar.substr(PrefixLen)
6607330f729Sjoerg : "")));
6617330f729Sjoerg } else {
6627330f729Sjoerg Environment.push_back(Args.MakeArgString(EnvVar));
6637330f729Sjoerg }
6647330f729Sjoerg Cursor += EnvVar.size() + 1 /*null-terminator*/;
6657330f729Sjoerg }
6667330f729Sjoerg }
6677330f729Sjoerg SkipSettingEnvironment:;
6687330f729Sjoerg #endif
6697330f729Sjoerg } else {
6707330f729Sjoerg linkPath = TC.GetProgramPath(Linker.str().c_str());
6717330f729Sjoerg }
6727330f729Sjoerg
6737330f729Sjoerg auto LinkCmd = std::make_unique<Command>(
674*e038c9c4Sjoerg JA, *this, ResponseFileSupport::AtFileUTF16(),
675*e038c9c4Sjoerg Args.MakeArgString(linkPath), CmdArgs, Inputs, Output);
6767330f729Sjoerg if (!Environment.empty())
6777330f729Sjoerg LinkCmd->setEnvironment(Environment);
6787330f729Sjoerg C.addCommand(std::move(LinkCmd));
6797330f729Sjoerg }
6807330f729Sjoerg
MSVCToolChain(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)6817330f729Sjoerg MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
6827330f729Sjoerg const ArgList &Args)
683*e038c9c4Sjoerg : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args),
684*e038c9c4Sjoerg RocmInstallation(D, Triple, Args) {
6857330f729Sjoerg getProgramPaths().push_back(getDriver().getInstalledDir());
6867330f729Sjoerg if (getDriver().getInstalledDir() != getDriver().Dir)
6877330f729Sjoerg getProgramPaths().push_back(getDriver().Dir);
6887330f729Sjoerg
689*e038c9c4Sjoerg // Check the command line first, that's the user explicitly telling us what to
690*e038c9c4Sjoerg // use. Check the environment next, in case we're being invoked from a VS
691*e038c9c4Sjoerg // command prompt. Failing that, just try to find the newest Visual Studio
692*e038c9c4Sjoerg // version we can and use its default VC toolchain.
693*e038c9c4Sjoerg findVCToolChainViaCommandLine(getVFS(), Args, VCToolChainPath, VSLayout) ||
694*e038c9c4Sjoerg findVCToolChainViaEnvironment(getVFS(), VCToolChainPath, VSLayout) ||
695*e038c9c4Sjoerg findVCToolChainViaSetupConfig(getVFS(), VCToolChainPath, VSLayout) ||
6967330f729Sjoerg findVCToolChainViaRegistry(VCToolChainPath, VSLayout);
6977330f729Sjoerg }
6987330f729Sjoerg
buildLinker() const6997330f729Sjoerg Tool *MSVCToolChain::buildLinker() const {
7007330f729Sjoerg return new tools::visualstudio::Linker(*this);
7017330f729Sjoerg }
7027330f729Sjoerg
buildAssembler() const7037330f729Sjoerg Tool *MSVCToolChain::buildAssembler() const {
7047330f729Sjoerg if (getTriple().isOSBinFormatMachO())
7057330f729Sjoerg return new tools::darwin::Assembler(*this);
7067330f729Sjoerg getDriver().Diag(clang::diag::err_no_external_assembler);
7077330f729Sjoerg return nullptr;
7087330f729Sjoerg }
7097330f729Sjoerg
IsIntegratedAssemblerDefault() const7107330f729Sjoerg bool MSVCToolChain::IsIntegratedAssemblerDefault() const {
7117330f729Sjoerg return true;
7127330f729Sjoerg }
7137330f729Sjoerg
IsUnwindTablesDefault(const ArgList & Args) const7147330f729Sjoerg bool MSVCToolChain::IsUnwindTablesDefault(const ArgList &Args) const {
7157330f729Sjoerg // Don't emit unwind tables by default for MachO targets.
7167330f729Sjoerg if (getTriple().isOSBinFormatMachO())
7177330f729Sjoerg return false;
7187330f729Sjoerg
7197330f729Sjoerg // All non-x86_32 Windows targets require unwind tables. However, LLVM
7207330f729Sjoerg // doesn't know how to generate them for all targets, so only enable
7217330f729Sjoerg // the ones that are actually implemented.
7227330f729Sjoerg return getArch() == llvm::Triple::x86_64 ||
7237330f729Sjoerg getArch() == llvm::Triple::aarch64;
7247330f729Sjoerg }
7257330f729Sjoerg
isPICDefault() const7267330f729Sjoerg bool MSVCToolChain::isPICDefault() const {
7277330f729Sjoerg return getArch() == llvm::Triple::x86_64;
7287330f729Sjoerg }
7297330f729Sjoerg
isPIEDefault() const7307330f729Sjoerg bool MSVCToolChain::isPIEDefault() const {
7317330f729Sjoerg return false;
7327330f729Sjoerg }
7337330f729Sjoerg
isPICDefaultForced() const7347330f729Sjoerg bool MSVCToolChain::isPICDefaultForced() const {
7357330f729Sjoerg return getArch() == llvm::Triple::x86_64;
7367330f729Sjoerg }
7377330f729Sjoerg
AddCudaIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const7387330f729Sjoerg void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
7397330f729Sjoerg ArgStringList &CC1Args) const {
7407330f729Sjoerg CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
7417330f729Sjoerg }
7427330f729Sjoerg
AddHIPIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const743*e038c9c4Sjoerg void MSVCToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
744*e038c9c4Sjoerg ArgStringList &CC1Args) const {
745*e038c9c4Sjoerg RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args);
746*e038c9c4Sjoerg }
747*e038c9c4Sjoerg
printVerboseInfo(raw_ostream & OS) const7487330f729Sjoerg void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const {
7497330f729Sjoerg CudaInstallation.print(OS);
750*e038c9c4Sjoerg RocmInstallation.print(OS);
7517330f729Sjoerg }
7527330f729Sjoerg
7537330f729Sjoerg // Windows SDKs and VC Toolchains group their contents into subdirectories based
7547330f729Sjoerg // on the target architecture. This function converts an llvm::Triple::ArchType
7557330f729Sjoerg // to the corresponding subdirectory name.
llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch)7567330f729Sjoerg static const char *llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch) {
7577330f729Sjoerg using ArchType = llvm::Triple::ArchType;
7587330f729Sjoerg switch (Arch) {
7597330f729Sjoerg case ArchType::x86:
7607330f729Sjoerg return "x86";
7617330f729Sjoerg case ArchType::x86_64:
7627330f729Sjoerg return "x64";
7637330f729Sjoerg case ArchType::arm:
7647330f729Sjoerg return "arm";
7657330f729Sjoerg case ArchType::aarch64:
7667330f729Sjoerg return "arm64";
7677330f729Sjoerg default:
7687330f729Sjoerg return "";
7697330f729Sjoerg }
7707330f729Sjoerg }
7717330f729Sjoerg
7727330f729Sjoerg // Similar to the above function, but for Visual Studios before VS2017.
llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch)7737330f729Sjoerg static const char *llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch) {
7747330f729Sjoerg using ArchType = llvm::Triple::ArchType;
7757330f729Sjoerg switch (Arch) {
7767330f729Sjoerg case ArchType::x86:
7777330f729Sjoerg // x86 is default in legacy VC toolchains.
7787330f729Sjoerg // e.g. x86 libs are directly in /lib as opposed to /lib/x86.
7797330f729Sjoerg return "";
7807330f729Sjoerg case ArchType::x86_64:
7817330f729Sjoerg return "amd64";
7827330f729Sjoerg case ArchType::arm:
7837330f729Sjoerg return "arm";
7847330f729Sjoerg case ArchType::aarch64:
7857330f729Sjoerg return "arm64";
7867330f729Sjoerg default:
7877330f729Sjoerg return "";
7887330f729Sjoerg }
7897330f729Sjoerg }
7907330f729Sjoerg
7917330f729Sjoerg // Similar to the above function, but for DevDiv internal builds.
llvmArchToDevDivInternalArch(llvm::Triple::ArchType Arch)7927330f729Sjoerg static const char *llvmArchToDevDivInternalArch(llvm::Triple::ArchType Arch) {
7937330f729Sjoerg using ArchType = llvm::Triple::ArchType;
7947330f729Sjoerg switch (Arch) {
7957330f729Sjoerg case ArchType::x86:
7967330f729Sjoerg return "i386";
7977330f729Sjoerg case ArchType::x86_64:
7987330f729Sjoerg return "amd64";
7997330f729Sjoerg case ArchType::arm:
8007330f729Sjoerg return "arm";
8017330f729Sjoerg case ArchType::aarch64:
8027330f729Sjoerg return "arm64";
8037330f729Sjoerg default:
8047330f729Sjoerg return "";
8057330f729Sjoerg }
8067330f729Sjoerg }
8077330f729Sjoerg
8087330f729Sjoerg // Get the path to a specific subdirectory in the current toolchain for
8097330f729Sjoerg // a given target architecture.
8107330f729Sjoerg // VS2017 changed the VC toolchain layout, so this should be used instead
8117330f729Sjoerg // of hardcoding paths.
8127330f729Sjoerg std::string
getSubDirectoryPath(SubDirectoryType Type,llvm::StringRef SubdirParent,llvm::Triple::ArchType TargetArch) const8137330f729Sjoerg MSVCToolChain::getSubDirectoryPath(SubDirectoryType Type,
8147330f729Sjoerg llvm::StringRef SubdirParent,
8157330f729Sjoerg llvm::Triple::ArchType TargetArch) const {
8167330f729Sjoerg const char *SubdirName;
8177330f729Sjoerg const char *IncludeName;
8187330f729Sjoerg switch (VSLayout) {
8197330f729Sjoerg case ToolsetLayout::OlderVS:
8207330f729Sjoerg SubdirName = llvmArchToLegacyVCArch(TargetArch);
8217330f729Sjoerg IncludeName = "include";
8227330f729Sjoerg break;
8237330f729Sjoerg case ToolsetLayout::VS2017OrNewer:
8247330f729Sjoerg SubdirName = llvmArchToWindowsSDKArch(TargetArch);
8257330f729Sjoerg IncludeName = "include";
8267330f729Sjoerg break;
8277330f729Sjoerg case ToolsetLayout::DevDivInternal:
8287330f729Sjoerg SubdirName = llvmArchToDevDivInternalArch(TargetArch);
8297330f729Sjoerg IncludeName = "inc";
8307330f729Sjoerg break;
8317330f729Sjoerg }
8327330f729Sjoerg
8337330f729Sjoerg llvm::SmallString<256> Path(VCToolChainPath);
8347330f729Sjoerg if (!SubdirParent.empty())
8357330f729Sjoerg llvm::sys::path::append(Path, SubdirParent);
8367330f729Sjoerg
8377330f729Sjoerg switch (Type) {
8387330f729Sjoerg case SubDirectoryType::Bin:
8397330f729Sjoerg if (VSLayout == ToolsetLayout::VS2017OrNewer) {
8407330f729Sjoerg const bool HostIsX64 =
8417330f729Sjoerg llvm::Triple(llvm::sys::getProcessTriple()).isArch64Bit();
8427330f729Sjoerg const char *const HostName = HostIsX64 ? "Hostx64" : "Hostx86";
8437330f729Sjoerg llvm::sys::path::append(Path, "bin", HostName, SubdirName);
8447330f729Sjoerg } else { // OlderVS or DevDivInternal
8457330f729Sjoerg llvm::sys::path::append(Path, "bin", SubdirName);
8467330f729Sjoerg }
8477330f729Sjoerg break;
8487330f729Sjoerg case SubDirectoryType::Include:
8497330f729Sjoerg llvm::sys::path::append(Path, IncludeName);
8507330f729Sjoerg break;
8517330f729Sjoerg case SubDirectoryType::Lib:
8527330f729Sjoerg llvm::sys::path::append(Path, "lib", SubdirName);
8537330f729Sjoerg break;
8547330f729Sjoerg }
855*e038c9c4Sjoerg return std::string(Path.str());
8567330f729Sjoerg }
8577330f729Sjoerg
8587330f729Sjoerg #ifdef _WIN32
readFullStringValue(HKEY hkey,const char * valueName,std::string & value)8597330f729Sjoerg static bool readFullStringValue(HKEY hkey, const char *valueName,
8607330f729Sjoerg std::string &value) {
8617330f729Sjoerg std::wstring WideValueName;
8627330f729Sjoerg if (!llvm::ConvertUTF8toWide(valueName, WideValueName))
8637330f729Sjoerg return false;
8647330f729Sjoerg
8657330f729Sjoerg DWORD result = 0;
8667330f729Sjoerg DWORD valueSize = 0;
8677330f729Sjoerg DWORD type = 0;
8687330f729Sjoerg // First just query for the required size.
8697330f729Sjoerg result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, &type, NULL,
8707330f729Sjoerg &valueSize);
8717330f729Sjoerg if (result != ERROR_SUCCESS || type != REG_SZ || !valueSize)
8727330f729Sjoerg return false;
8737330f729Sjoerg std::vector<BYTE> buffer(valueSize);
8747330f729Sjoerg result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, NULL, &buffer[0],
8757330f729Sjoerg &valueSize);
8767330f729Sjoerg if (result == ERROR_SUCCESS) {
8777330f729Sjoerg std::wstring WideValue(reinterpret_cast<const wchar_t *>(buffer.data()),
8787330f729Sjoerg valueSize / sizeof(wchar_t));
8797330f729Sjoerg if (valueSize && WideValue.back() == L'\0') {
8807330f729Sjoerg WideValue.pop_back();
8817330f729Sjoerg }
8827330f729Sjoerg // The destination buffer must be empty as an invariant of the conversion
8837330f729Sjoerg // function; but this function is sometimes called in a loop that passes in
8847330f729Sjoerg // the same buffer, however. Simply clear it out so we can overwrite it.
8857330f729Sjoerg value.clear();
8867330f729Sjoerg return llvm::convertWideToUTF8(WideValue, value);
8877330f729Sjoerg }
8887330f729Sjoerg return false;
8897330f729Sjoerg }
8907330f729Sjoerg #endif
8917330f729Sjoerg
8927330f729Sjoerg /// Read registry string.
8937330f729Sjoerg /// This also supports a means to look for high-versioned keys by use
8947330f729Sjoerg /// of a $VERSION placeholder in the key path.
8957330f729Sjoerg /// $VERSION in the key path is a placeholder for the version number,
8967330f729Sjoerg /// causing the highest value path to be searched for and used.
8977330f729Sjoerg /// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
8987330f729Sjoerg /// There can be additional characters in the component. Only the numeric
8997330f729Sjoerg /// characters are compared. This function only searches HKLM.
getSystemRegistryString(const char * keyPath,const char * valueName,std::string & value,std::string * phValue)9007330f729Sjoerg static bool getSystemRegistryString(const char *keyPath, const char *valueName,
9017330f729Sjoerg std::string &value, std::string *phValue) {
9027330f729Sjoerg #ifndef _WIN32
9037330f729Sjoerg return false;
9047330f729Sjoerg #else
9057330f729Sjoerg HKEY hRootKey = HKEY_LOCAL_MACHINE;
9067330f729Sjoerg HKEY hKey = NULL;
9077330f729Sjoerg long lResult;
9087330f729Sjoerg bool returnValue = false;
9097330f729Sjoerg
9107330f729Sjoerg const char *placeHolder = strstr(keyPath, "$VERSION");
9117330f729Sjoerg std::string bestName;
9127330f729Sjoerg // If we have a $VERSION placeholder, do the highest-version search.
9137330f729Sjoerg if (placeHolder) {
9147330f729Sjoerg const char *keyEnd = placeHolder - 1;
9157330f729Sjoerg const char *nextKey = placeHolder;
9167330f729Sjoerg // Find end of previous key.
9177330f729Sjoerg while ((keyEnd > keyPath) && (*keyEnd != '\\'))
9187330f729Sjoerg keyEnd--;
9197330f729Sjoerg // Find end of key containing $VERSION.
9207330f729Sjoerg while (*nextKey && (*nextKey != '\\'))
9217330f729Sjoerg nextKey++;
9227330f729Sjoerg size_t partialKeyLength = keyEnd - keyPath;
9237330f729Sjoerg char partialKey[256];
9247330f729Sjoerg if (partialKeyLength >= sizeof(partialKey))
9257330f729Sjoerg partialKeyLength = sizeof(partialKey) - 1;
9267330f729Sjoerg strncpy(partialKey, keyPath, partialKeyLength);
9277330f729Sjoerg partialKey[partialKeyLength] = '\0';
9287330f729Sjoerg HKEY hTopKey = NULL;
9297330f729Sjoerg lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY,
9307330f729Sjoerg &hTopKey);
9317330f729Sjoerg if (lResult == ERROR_SUCCESS) {
9327330f729Sjoerg char keyName[256];
9337330f729Sjoerg double bestValue = 0.0;
9347330f729Sjoerg DWORD index, size = sizeof(keyName) - 1;
9357330f729Sjoerg for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, NULL,
9367330f729Sjoerg NULL, NULL) == ERROR_SUCCESS;
9377330f729Sjoerg index++) {
9387330f729Sjoerg const char *sp = keyName;
9397330f729Sjoerg while (*sp && !isDigit(*sp))
9407330f729Sjoerg sp++;
9417330f729Sjoerg if (!*sp)
9427330f729Sjoerg continue;
9437330f729Sjoerg const char *ep = sp + 1;
9447330f729Sjoerg while (*ep && (isDigit(*ep) || (*ep == '.')))
9457330f729Sjoerg ep++;
9467330f729Sjoerg char numBuf[32];
9477330f729Sjoerg strncpy(numBuf, sp, sizeof(numBuf) - 1);
9487330f729Sjoerg numBuf[sizeof(numBuf) - 1] = '\0';
9497330f729Sjoerg double dvalue = strtod(numBuf, NULL);
9507330f729Sjoerg if (dvalue > bestValue) {
9517330f729Sjoerg // Test that InstallDir is indeed there before keeping this index.
9527330f729Sjoerg // Open the chosen key path remainder.
9537330f729Sjoerg bestName = keyName;
9547330f729Sjoerg // Append rest of key.
9557330f729Sjoerg bestName.append(nextKey);
9567330f729Sjoerg lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0,
9577330f729Sjoerg KEY_READ | KEY_WOW64_32KEY, &hKey);
9587330f729Sjoerg if (lResult == ERROR_SUCCESS) {
9597330f729Sjoerg if (readFullStringValue(hKey, valueName, value)) {
9607330f729Sjoerg bestValue = dvalue;
9617330f729Sjoerg if (phValue)
9627330f729Sjoerg *phValue = bestName;
9637330f729Sjoerg returnValue = true;
9647330f729Sjoerg }
9657330f729Sjoerg RegCloseKey(hKey);
9667330f729Sjoerg }
9677330f729Sjoerg }
9687330f729Sjoerg size = sizeof(keyName) - 1;
9697330f729Sjoerg }
9707330f729Sjoerg RegCloseKey(hTopKey);
9717330f729Sjoerg }
9727330f729Sjoerg } else {
9737330f729Sjoerg lResult =
9747330f729Sjoerg RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey);
9757330f729Sjoerg if (lResult == ERROR_SUCCESS) {
9767330f729Sjoerg if (readFullStringValue(hKey, valueName, value))
9777330f729Sjoerg returnValue = true;
9787330f729Sjoerg if (phValue)
9797330f729Sjoerg phValue->clear();
9807330f729Sjoerg RegCloseKey(hKey);
9817330f729Sjoerg }
9827330f729Sjoerg }
9837330f729Sjoerg return returnValue;
9847330f729Sjoerg #endif // _WIN32
9857330f729Sjoerg }
9867330f729Sjoerg
9877330f729Sjoerg // Find the most recent version of Universal CRT or Windows 10 SDK.
9887330f729Sjoerg // vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include
9897330f729Sjoerg // directory by name and uses the last one of the list.
9907330f729Sjoerg // So we compare entry names lexicographically to find the greatest one.
getWindows10SDKVersionFromPath(llvm::vfs::FileSystem & VFS,const std::string & SDKPath,std::string & SDKVersion)991*e038c9c4Sjoerg static bool getWindows10SDKVersionFromPath(llvm::vfs::FileSystem &VFS,
992*e038c9c4Sjoerg const std::string &SDKPath,
9937330f729Sjoerg std::string &SDKVersion) {
9947330f729Sjoerg llvm::SmallString<128> IncludePath(SDKPath);
9957330f729Sjoerg llvm::sys::path::append(IncludePath, "Include");
996*e038c9c4Sjoerg SDKVersion = getHighestNumericTupleInDirectory(VFS, IncludePath);
9977330f729Sjoerg return !SDKVersion.empty();
9987330f729Sjoerg }
9997330f729Sjoerg
getWindowsSDKDirViaCommandLine(llvm::vfs::FileSystem & VFS,const ArgList & Args,std::string & Path,int & Major,std::string & Version)1000*e038c9c4Sjoerg static bool getWindowsSDKDirViaCommandLine(llvm::vfs::FileSystem &VFS,
1001*e038c9c4Sjoerg const ArgList &Args,
1002*e038c9c4Sjoerg std::string &Path, int &Major,
1003*e038c9c4Sjoerg std::string &Version) {
1004*e038c9c4Sjoerg if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir,
1005*e038c9c4Sjoerg options::OPT__SLASH_winsysroot)) {
1006*e038c9c4Sjoerg // Don't validate the input; trust the value supplied by the user.
1007*e038c9c4Sjoerg // The motivation is to prevent unnecessary file and registry access.
1008*e038c9c4Sjoerg llvm::VersionTuple SDKVersion;
1009*e038c9c4Sjoerg if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion))
1010*e038c9c4Sjoerg SDKVersion.tryParse(A->getValue());
1011*e038c9c4Sjoerg
1012*e038c9c4Sjoerg if (A->getOption().getID() == options::OPT__SLASH_winsysroot) {
1013*e038c9c4Sjoerg llvm::SmallString<128> SDKPath(A->getValue());
1014*e038c9c4Sjoerg llvm::sys::path::append(SDKPath, "Windows Kits");
1015*e038c9c4Sjoerg if (!SDKVersion.empty())
1016*e038c9c4Sjoerg llvm::sys::path::append(SDKPath, Twine(SDKVersion.getMajor()));
1017*e038c9c4Sjoerg else
1018*e038c9c4Sjoerg llvm::sys::path::append(
1019*e038c9c4Sjoerg SDKPath, getHighestNumericTupleInDirectory(VFS, SDKPath));
1020*e038c9c4Sjoerg Path = std::string(SDKPath.str());
1021*e038c9c4Sjoerg } else {
1022*e038c9c4Sjoerg Path = A->getValue();
1023*e038c9c4Sjoerg }
1024*e038c9c4Sjoerg
1025*e038c9c4Sjoerg if (!SDKVersion.empty()) {
1026*e038c9c4Sjoerg Major = SDKVersion.getMajor();
1027*e038c9c4Sjoerg Version = SDKVersion.getAsString();
1028*e038c9c4Sjoerg } else if (getWindows10SDKVersionFromPath(VFS, Path, Version)) {
1029*e038c9c4Sjoerg Major = 10;
1030*e038c9c4Sjoerg }
1031*e038c9c4Sjoerg return true;
1032*e038c9c4Sjoerg }
1033*e038c9c4Sjoerg return false;
1034*e038c9c4Sjoerg }
1035*e038c9c4Sjoerg
10367330f729Sjoerg /// Get Windows SDK installation directory.
getWindowsSDKDir(llvm::vfs::FileSystem & VFS,const ArgList & Args,std::string & Path,int & Major,std::string & WindowsSDKIncludeVersion,std::string & WindowsSDKLibVersion)1037*e038c9c4Sjoerg static bool getWindowsSDKDir(llvm::vfs::FileSystem &VFS, const ArgList &Args,
1038*e038c9c4Sjoerg std::string &Path, int &Major,
10397330f729Sjoerg std::string &WindowsSDKIncludeVersion,
10407330f729Sjoerg std::string &WindowsSDKLibVersion) {
1041*e038c9c4Sjoerg // Trust /winsdkdir and /winsdkversion if present.
1042*e038c9c4Sjoerg if (getWindowsSDKDirViaCommandLine(VFS, Args, Path, Major,
1043*e038c9c4Sjoerg WindowsSDKIncludeVersion)) {
1044*e038c9c4Sjoerg WindowsSDKLibVersion = WindowsSDKIncludeVersion;
1045*e038c9c4Sjoerg return true;
1046*e038c9c4Sjoerg }
1047*e038c9c4Sjoerg
1048*e038c9c4Sjoerg // FIXME: Try env vars (%WindowsSdkDir%, %UCRTVersion%) before going to registry.
1049*e038c9c4Sjoerg
10507330f729Sjoerg // Try the Windows registry.
1051*e038c9c4Sjoerg std::string RegistrySDKVersion;
10527330f729Sjoerg if (!getSystemRegistryString(
10537330f729Sjoerg "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
10547330f729Sjoerg "InstallationFolder", Path, &RegistrySDKVersion))
10557330f729Sjoerg return false;
10567330f729Sjoerg if (Path.empty() || RegistrySDKVersion.empty())
10577330f729Sjoerg return false;
10587330f729Sjoerg
10597330f729Sjoerg WindowsSDKIncludeVersion.clear();
10607330f729Sjoerg WindowsSDKLibVersion.clear();
10617330f729Sjoerg Major = 0;
10627330f729Sjoerg std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major);
10637330f729Sjoerg if (Major <= 7)
10647330f729Sjoerg return true;
10657330f729Sjoerg if (Major == 8) {
10667330f729Sjoerg // Windows SDK 8.x installs libraries in a folder whose names depend on the
10677330f729Sjoerg // version of the OS you're targeting. By default choose the newest, which
10687330f729Sjoerg // usually corresponds to the version of the OS you've installed the SDK on.
10697330f729Sjoerg const char *Tests[] = {"winv6.3", "win8", "win7"};
10707330f729Sjoerg for (const char *Test : Tests) {
10717330f729Sjoerg llvm::SmallString<128> TestPath(Path);
10727330f729Sjoerg llvm::sys::path::append(TestPath, "Lib", Test);
1073*e038c9c4Sjoerg if (VFS.exists(TestPath)) {
10747330f729Sjoerg WindowsSDKLibVersion = Test;
10757330f729Sjoerg break;
10767330f729Sjoerg }
10777330f729Sjoerg }
10787330f729Sjoerg return !WindowsSDKLibVersion.empty();
10797330f729Sjoerg }
10807330f729Sjoerg if (Major == 10) {
1081*e038c9c4Sjoerg if (!getWindows10SDKVersionFromPath(VFS, Path, WindowsSDKIncludeVersion))
10827330f729Sjoerg return false;
10837330f729Sjoerg WindowsSDKLibVersion = WindowsSDKIncludeVersion;
10847330f729Sjoerg return true;
10857330f729Sjoerg }
10867330f729Sjoerg // Unsupported SDK version
10877330f729Sjoerg return false;
10887330f729Sjoerg }
10897330f729Sjoerg
10907330f729Sjoerg // Gets the library path required to link against the Windows SDK.
getWindowsSDKLibraryPath(const ArgList & Args,std::string & path) const1091*e038c9c4Sjoerg bool MSVCToolChain::getWindowsSDKLibraryPath(
1092*e038c9c4Sjoerg const ArgList &Args, std::string &path) const {
10937330f729Sjoerg std::string sdkPath;
10947330f729Sjoerg int sdkMajor = 0;
10957330f729Sjoerg std::string windowsSDKIncludeVersion;
10967330f729Sjoerg std::string windowsSDKLibVersion;
10977330f729Sjoerg
10987330f729Sjoerg path.clear();
1099*e038c9c4Sjoerg if (!getWindowsSDKDir(getVFS(), Args, sdkPath, sdkMajor,
1100*e038c9c4Sjoerg windowsSDKIncludeVersion, windowsSDKLibVersion))
11017330f729Sjoerg return false;
11027330f729Sjoerg
11037330f729Sjoerg llvm::SmallString<128> libPath(sdkPath);
11047330f729Sjoerg llvm::sys::path::append(libPath, "Lib");
11057330f729Sjoerg if (sdkMajor >= 8) {
11067330f729Sjoerg llvm::sys::path::append(libPath, windowsSDKLibVersion, "um",
11077330f729Sjoerg llvmArchToWindowsSDKArch(getArch()));
11087330f729Sjoerg } else {
11097330f729Sjoerg switch (getArch()) {
11107330f729Sjoerg // In Windows SDK 7.x, x86 libraries are directly in the Lib folder.
11117330f729Sjoerg case llvm::Triple::x86:
11127330f729Sjoerg break;
11137330f729Sjoerg case llvm::Triple::x86_64:
11147330f729Sjoerg llvm::sys::path::append(libPath, "x64");
11157330f729Sjoerg break;
11167330f729Sjoerg case llvm::Triple::arm:
11177330f729Sjoerg // It is not necessary to link against Windows SDK 7.x when targeting ARM.
11187330f729Sjoerg return false;
11197330f729Sjoerg default:
11207330f729Sjoerg return false;
11217330f729Sjoerg }
11227330f729Sjoerg }
11237330f729Sjoerg
1124*e038c9c4Sjoerg path = std::string(libPath.str());
11257330f729Sjoerg return true;
11267330f729Sjoerg }
11277330f729Sjoerg
11287330f729Sjoerg // Check if the Include path of a specified version of Visual Studio contains
11297330f729Sjoerg // specific header files. If not, they are probably shipped with Universal CRT.
useUniversalCRT() const11307330f729Sjoerg bool MSVCToolChain::useUniversalCRT() const {
11317330f729Sjoerg llvm::SmallString<128> TestPath(
11327330f729Sjoerg getSubDirectoryPath(SubDirectoryType::Include));
11337330f729Sjoerg llvm::sys::path::append(TestPath, "stdlib.h");
1134*e038c9c4Sjoerg return !getVFS().exists(TestPath);
11357330f729Sjoerg }
11367330f729Sjoerg
getUniversalCRTSdkDir(llvm::vfs::FileSystem & VFS,const ArgList & Args,std::string & Path,std::string & UCRTVersion)1137*e038c9c4Sjoerg static bool getUniversalCRTSdkDir(llvm::vfs::FileSystem &VFS,
1138*e038c9c4Sjoerg const ArgList &Args, std::string &Path,
1139*e038c9c4Sjoerg std::string &UCRTVersion) {
1140*e038c9c4Sjoerg // If /winsdkdir is passed, use it as location for the UCRT too.
1141*e038c9c4Sjoerg // FIXME: Should there be a dedicated /ucrtdir to override /winsdkdir?
1142*e038c9c4Sjoerg int Major;
1143*e038c9c4Sjoerg if (getWindowsSDKDirViaCommandLine(VFS, Args, Path, Major, UCRTVersion))
1144*e038c9c4Sjoerg return true;
1145*e038c9c4Sjoerg
1146*e038c9c4Sjoerg // FIXME: Try env vars (%UniversalCRTSdkDir%, %UCRTVersion%) before going to
1147*e038c9c4Sjoerg // registry.
1148*e038c9c4Sjoerg
11497330f729Sjoerg // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry
11507330f729Sjoerg // for the specific key "KitsRoot10". So do we.
11517330f729Sjoerg if (!getSystemRegistryString(
11527330f729Sjoerg "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10",
11537330f729Sjoerg Path, nullptr))
11547330f729Sjoerg return false;
11557330f729Sjoerg
1156*e038c9c4Sjoerg return getWindows10SDKVersionFromPath(VFS, Path, UCRTVersion);
11577330f729Sjoerg }
11587330f729Sjoerg
getUniversalCRTLibraryPath(const ArgList & Args,std::string & Path) const1159*e038c9c4Sjoerg bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args,
1160*e038c9c4Sjoerg std::string &Path) const {
11617330f729Sjoerg std::string UniversalCRTSdkPath;
11627330f729Sjoerg std::string UCRTVersion;
11637330f729Sjoerg
11647330f729Sjoerg Path.clear();
1165*e038c9c4Sjoerg if (!getUniversalCRTSdkDir(getVFS(), Args, UniversalCRTSdkPath, UCRTVersion))
11667330f729Sjoerg return false;
11677330f729Sjoerg
11687330f729Sjoerg StringRef ArchName = llvmArchToWindowsSDKArch(getArch());
11697330f729Sjoerg if (ArchName.empty())
11707330f729Sjoerg return false;
11717330f729Sjoerg
11727330f729Sjoerg llvm::SmallString<128> LibPath(UniversalCRTSdkPath);
11737330f729Sjoerg llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName);
11747330f729Sjoerg
1175*e038c9c4Sjoerg Path = std::string(LibPath.str());
11767330f729Sjoerg return true;
11777330f729Sjoerg }
11787330f729Sjoerg
getMSVCVersionFromTriple(const llvm::Triple & Triple)11797330f729Sjoerg static VersionTuple getMSVCVersionFromTriple(const llvm::Triple &Triple) {
11807330f729Sjoerg unsigned Major, Minor, Micro;
11817330f729Sjoerg Triple.getEnvironmentVersion(Major, Minor, Micro);
11827330f729Sjoerg if (Major || Minor || Micro)
11837330f729Sjoerg return VersionTuple(Major, Minor, Micro);
11847330f729Sjoerg return VersionTuple();
11857330f729Sjoerg }
11867330f729Sjoerg
getMSVCVersionFromExe(const std::string & BinDir)11877330f729Sjoerg static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) {
11887330f729Sjoerg VersionTuple Version;
11897330f729Sjoerg #ifdef _WIN32
11907330f729Sjoerg SmallString<128> ClExe(BinDir);
11917330f729Sjoerg llvm::sys::path::append(ClExe, "cl.exe");
11927330f729Sjoerg
11937330f729Sjoerg std::wstring ClExeWide;
11947330f729Sjoerg if (!llvm::ConvertUTF8toWide(ClExe.c_str(), ClExeWide))
11957330f729Sjoerg return Version;
11967330f729Sjoerg
11977330f729Sjoerg const DWORD VersionSize = ::GetFileVersionInfoSizeW(ClExeWide.c_str(),
11987330f729Sjoerg nullptr);
11997330f729Sjoerg if (VersionSize == 0)
12007330f729Sjoerg return Version;
12017330f729Sjoerg
12027330f729Sjoerg SmallVector<uint8_t, 4 * 1024> VersionBlock(VersionSize);
12037330f729Sjoerg if (!::GetFileVersionInfoW(ClExeWide.c_str(), 0, VersionSize,
12047330f729Sjoerg VersionBlock.data()))
12057330f729Sjoerg return Version;
12067330f729Sjoerg
12077330f729Sjoerg VS_FIXEDFILEINFO *FileInfo = nullptr;
12087330f729Sjoerg UINT FileInfoSize = 0;
12097330f729Sjoerg if (!::VerQueryValueW(VersionBlock.data(), L"\\",
12107330f729Sjoerg reinterpret_cast<LPVOID *>(&FileInfo), &FileInfoSize) ||
12117330f729Sjoerg FileInfoSize < sizeof(*FileInfo))
12127330f729Sjoerg return Version;
12137330f729Sjoerg
12147330f729Sjoerg const unsigned Major = (FileInfo->dwFileVersionMS >> 16) & 0xFFFF;
12157330f729Sjoerg const unsigned Minor = (FileInfo->dwFileVersionMS ) & 0xFFFF;
12167330f729Sjoerg const unsigned Micro = (FileInfo->dwFileVersionLS >> 16) & 0xFFFF;
12177330f729Sjoerg
12187330f729Sjoerg Version = VersionTuple(Major, Minor, Micro);
12197330f729Sjoerg #endif
12207330f729Sjoerg return Version;
12217330f729Sjoerg }
12227330f729Sjoerg
AddSystemIncludeWithSubfolder(const ArgList & DriverArgs,ArgStringList & CC1Args,const std::string & folder,const Twine & subfolder1,const Twine & subfolder2,const Twine & subfolder3) const12237330f729Sjoerg void MSVCToolChain::AddSystemIncludeWithSubfolder(
12247330f729Sjoerg const ArgList &DriverArgs, ArgStringList &CC1Args,
12257330f729Sjoerg const std::string &folder, const Twine &subfolder1, const Twine &subfolder2,
12267330f729Sjoerg const Twine &subfolder3) const {
12277330f729Sjoerg llvm::SmallString<128> path(folder);
12287330f729Sjoerg llvm::sys::path::append(path, subfolder1, subfolder2, subfolder3);
12297330f729Sjoerg addSystemInclude(DriverArgs, CC1Args, path);
12307330f729Sjoerg }
12317330f729Sjoerg
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const12327330f729Sjoerg void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
12337330f729Sjoerg ArgStringList &CC1Args) const {
12347330f729Sjoerg if (DriverArgs.hasArg(options::OPT_nostdinc))
12357330f729Sjoerg return;
12367330f729Sjoerg
12377330f729Sjoerg if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
12387330f729Sjoerg AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, getDriver().ResourceDir,
12397330f729Sjoerg "include");
12407330f729Sjoerg }
12417330f729Sjoerg
12427330f729Sjoerg // Add %INCLUDE%-like directories from the -imsvc flag.
12437330f729Sjoerg for (const auto &Path : DriverArgs.getAllArgValues(options::OPT__SLASH_imsvc))
12447330f729Sjoerg addSystemInclude(DriverArgs, CC1Args, Path);
12457330f729Sjoerg
12467330f729Sjoerg if (DriverArgs.hasArg(options::OPT_nostdlibinc))
12477330f729Sjoerg return;
12487330f729Sjoerg
12497330f729Sjoerg // Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat.
1250*e038c9c4Sjoerg // Skip if the user expressly set a vctoolsdir
1251*e038c9c4Sjoerg if (!DriverArgs.getLastArg(options::OPT__SLASH_vctoolsdir,
1252*e038c9c4Sjoerg options::OPT__SLASH_winsysroot)) {
12537330f729Sjoerg if (llvm::Optional<std::string> cl_include_dir =
12547330f729Sjoerg llvm::sys::Process::GetEnv("INCLUDE")) {
12557330f729Sjoerg SmallVector<StringRef, 8> Dirs;
12567330f729Sjoerg StringRef(*cl_include_dir)
12577330f729Sjoerg .split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
12587330f729Sjoerg for (StringRef Dir : Dirs)
12597330f729Sjoerg addSystemInclude(DriverArgs, CC1Args, Dir);
12607330f729Sjoerg if (!Dirs.empty())
12617330f729Sjoerg return;
12627330f729Sjoerg }
1263*e038c9c4Sjoerg }
12647330f729Sjoerg
12657330f729Sjoerg // When built with access to the proper Windows APIs, try to actually find
12667330f729Sjoerg // the correct include paths first.
12677330f729Sjoerg if (!VCToolChainPath.empty()) {
12687330f729Sjoerg addSystemInclude(DriverArgs, CC1Args,
12697330f729Sjoerg getSubDirectoryPath(SubDirectoryType::Include));
12707330f729Sjoerg addSystemInclude(DriverArgs, CC1Args,
12717330f729Sjoerg getSubDirectoryPath(SubDirectoryType::Include, "atlmfc"));
12727330f729Sjoerg
12737330f729Sjoerg if (useUniversalCRT()) {
12747330f729Sjoerg std::string UniversalCRTSdkPath;
12757330f729Sjoerg std::string UCRTVersion;
1276*e038c9c4Sjoerg if (getUniversalCRTSdkDir(getVFS(), DriverArgs, UniversalCRTSdkPath,
1277*e038c9c4Sjoerg UCRTVersion)) {
12787330f729Sjoerg AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath,
12797330f729Sjoerg "Include", UCRTVersion, "ucrt");
12807330f729Sjoerg }
12817330f729Sjoerg }
12827330f729Sjoerg
12837330f729Sjoerg std::string WindowsSDKDir;
12847330f729Sjoerg int major;
12857330f729Sjoerg std::string windowsSDKIncludeVersion;
12867330f729Sjoerg std::string windowsSDKLibVersion;
1287*e038c9c4Sjoerg if (getWindowsSDKDir(getVFS(), DriverArgs, WindowsSDKDir, major,
1288*e038c9c4Sjoerg windowsSDKIncludeVersion, windowsSDKLibVersion)) {
12897330f729Sjoerg if (major >= 8) {
12907330f729Sjoerg // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10.
12917330f729Sjoerg // Anyway, llvm::sys::path::append is able to manage it.
12927330f729Sjoerg AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
1293*e038c9c4Sjoerg "Include", windowsSDKIncludeVersion,
12947330f729Sjoerg "shared");
12957330f729Sjoerg AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
1296*e038c9c4Sjoerg "Include", windowsSDKIncludeVersion,
12977330f729Sjoerg "um");
12987330f729Sjoerg AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
1299*e038c9c4Sjoerg "Include", windowsSDKIncludeVersion,
13007330f729Sjoerg "winrt");
13017330f729Sjoerg } else {
13027330f729Sjoerg AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
1303*e038c9c4Sjoerg "Include");
13047330f729Sjoerg }
13057330f729Sjoerg }
13067330f729Sjoerg
13077330f729Sjoerg return;
13087330f729Sjoerg }
13097330f729Sjoerg
13107330f729Sjoerg #if defined(_WIN32)
13117330f729Sjoerg // As a fallback, select default install paths.
13127330f729Sjoerg // FIXME: Don't guess drives and paths like this on Windows.
13137330f729Sjoerg const StringRef Paths[] = {
13147330f729Sjoerg "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
13157330f729Sjoerg "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
13167330f729Sjoerg "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
13177330f729Sjoerg "C:/Program Files/Microsoft Visual Studio 8/VC/include",
13187330f729Sjoerg "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
13197330f729Sjoerg };
13207330f729Sjoerg addSystemIncludes(DriverArgs, CC1Args, Paths);
13217330f729Sjoerg #endif
13227330f729Sjoerg }
13237330f729Sjoerg
AddClangCXXStdlibIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const13247330f729Sjoerg void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
13257330f729Sjoerg ArgStringList &CC1Args) const {
13267330f729Sjoerg // FIXME: There should probably be logic here to find libc++ on Windows.
13277330f729Sjoerg }
13287330f729Sjoerg
computeMSVCVersion(const Driver * D,const ArgList & Args) const13297330f729Sjoerg VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D,
13307330f729Sjoerg const ArgList &Args) const {
13317330f729Sjoerg bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment();
13327330f729Sjoerg VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args);
13337330f729Sjoerg if (MSVT.empty())
13347330f729Sjoerg MSVT = getMSVCVersionFromTriple(getTriple());
13357330f729Sjoerg if (MSVT.empty() && IsWindowsMSVC)
13367330f729Sjoerg MSVT = getMSVCVersionFromExe(getSubDirectoryPath(SubDirectoryType::Bin));
13377330f729Sjoerg if (MSVT.empty() &&
13387330f729Sjoerg Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
13397330f729Sjoerg IsWindowsMSVC)) {
13407330f729Sjoerg // -fms-compatibility-version=19.11 is default, aka 2017, 15.3
13417330f729Sjoerg MSVT = VersionTuple(19, 11);
13427330f729Sjoerg }
13437330f729Sjoerg return MSVT;
13447330f729Sjoerg }
13457330f729Sjoerg
13467330f729Sjoerg std::string
ComputeEffectiveClangTriple(const ArgList & Args,types::ID InputType) const13477330f729Sjoerg MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
13487330f729Sjoerg types::ID InputType) const {
13497330f729Sjoerg // The MSVC version doesn't care about the architecture, even though it
13507330f729Sjoerg // may look at the triple internally.
13517330f729Sjoerg VersionTuple MSVT = computeMSVCVersion(/*D=*/nullptr, Args);
13527330f729Sjoerg MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().getValueOr(0),
13537330f729Sjoerg MSVT.getSubminor().getValueOr(0));
13547330f729Sjoerg
13557330f729Sjoerg // For the rest of the triple, however, a computed architecture name may
13567330f729Sjoerg // be needed.
13577330f729Sjoerg llvm::Triple Triple(ToolChain::ComputeEffectiveClangTriple(Args, InputType));
13587330f729Sjoerg if (Triple.getEnvironment() == llvm::Triple::MSVC) {
13597330f729Sjoerg StringRef ObjFmt = Triple.getEnvironmentName().split('-').second;
13607330f729Sjoerg if (ObjFmt.empty())
13617330f729Sjoerg Triple.setEnvironmentName((Twine("msvc") + MSVT.getAsString()).str());
13627330f729Sjoerg else
13637330f729Sjoerg Triple.setEnvironmentName(
13647330f729Sjoerg (Twine("msvc") + MSVT.getAsString() + Twine('-') + ObjFmt).str());
13657330f729Sjoerg }
13667330f729Sjoerg return Triple.getTriple();
13677330f729Sjoerg }
13687330f729Sjoerg
getSupportedSanitizers() const13697330f729Sjoerg SanitizerMask MSVCToolChain::getSupportedSanitizers() const {
13707330f729Sjoerg SanitizerMask Res = ToolChain::getSupportedSanitizers();
13717330f729Sjoerg Res |= SanitizerKind::Address;
13727330f729Sjoerg Res |= SanitizerKind::PointerCompare;
13737330f729Sjoerg Res |= SanitizerKind::PointerSubtract;
13747330f729Sjoerg Res |= SanitizerKind::Fuzzer;
13757330f729Sjoerg Res |= SanitizerKind::FuzzerNoLink;
13767330f729Sjoerg Res &= ~SanitizerKind::CFIMFCall;
13777330f729Sjoerg return Res;
13787330f729Sjoerg }
13797330f729Sjoerg
TranslateOptArg(Arg * A,llvm::opt::DerivedArgList & DAL,bool SupportsForcingFramePointer,const char * ExpandChar,const OptTable & Opts)13807330f729Sjoerg static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL,
13817330f729Sjoerg bool SupportsForcingFramePointer,
13827330f729Sjoerg const char *ExpandChar, const OptTable &Opts) {
13837330f729Sjoerg assert(A->getOption().matches(options::OPT__SLASH_O));
13847330f729Sjoerg
13857330f729Sjoerg StringRef OptStr = A->getValue();
13867330f729Sjoerg for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
13877330f729Sjoerg const char &OptChar = *(OptStr.data() + I);
13887330f729Sjoerg switch (OptChar) {
13897330f729Sjoerg default:
13907330f729Sjoerg break;
13917330f729Sjoerg case '1':
13927330f729Sjoerg case '2':
13937330f729Sjoerg case 'x':
13947330f729Sjoerg case 'd':
13957330f729Sjoerg // Ignore /O[12xd] flags that aren't the last one on the command line.
13967330f729Sjoerg // Only the last one gets expanded.
13977330f729Sjoerg if (&OptChar != ExpandChar) {
13987330f729Sjoerg A->claim();
13997330f729Sjoerg break;
14007330f729Sjoerg }
14017330f729Sjoerg if (OptChar == 'd') {
14027330f729Sjoerg DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0));
14037330f729Sjoerg } else {
14047330f729Sjoerg if (OptChar == '1') {
14057330f729Sjoerg DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
14067330f729Sjoerg } else if (OptChar == '2' || OptChar == 'x') {
14077330f729Sjoerg DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
14087330f729Sjoerg DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
14097330f729Sjoerg }
14107330f729Sjoerg if (SupportsForcingFramePointer &&
14117330f729Sjoerg !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer))
14127330f729Sjoerg DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer));
14137330f729Sjoerg if (OptChar == '1' || OptChar == '2')
14147330f729Sjoerg DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections));
14157330f729Sjoerg }
14167330f729Sjoerg break;
14177330f729Sjoerg case 'b':
14187330f729Sjoerg if (I + 1 != E && isdigit(OptStr[I + 1])) {
14197330f729Sjoerg switch (OptStr[I + 1]) {
14207330f729Sjoerg case '0':
14217330f729Sjoerg DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline));
14227330f729Sjoerg break;
14237330f729Sjoerg case '1':
14247330f729Sjoerg DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions));
14257330f729Sjoerg break;
14267330f729Sjoerg case '2':
14277330f729Sjoerg DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions));
14287330f729Sjoerg break;
14297330f729Sjoerg }
14307330f729Sjoerg ++I;
14317330f729Sjoerg }
14327330f729Sjoerg break;
14337330f729Sjoerg case 'g':
14347330f729Sjoerg A->claim();
14357330f729Sjoerg break;
14367330f729Sjoerg case 'i':
14377330f729Sjoerg if (I + 1 != E && OptStr[I + 1] == '-') {
14387330f729Sjoerg ++I;
14397330f729Sjoerg DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin));
14407330f729Sjoerg } else {
14417330f729Sjoerg DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
14427330f729Sjoerg }
14437330f729Sjoerg break;
14447330f729Sjoerg case 's':
14457330f729Sjoerg DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
14467330f729Sjoerg break;
14477330f729Sjoerg case 't':
14487330f729Sjoerg DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
14497330f729Sjoerg break;
14507330f729Sjoerg case 'y': {
14517330f729Sjoerg bool OmitFramePointer = true;
14527330f729Sjoerg if (I + 1 != E && OptStr[I + 1] == '-') {
14537330f729Sjoerg OmitFramePointer = false;
14547330f729Sjoerg ++I;
14557330f729Sjoerg }
14567330f729Sjoerg if (SupportsForcingFramePointer) {
14577330f729Sjoerg if (OmitFramePointer)
14587330f729Sjoerg DAL.AddFlagArg(A,
14597330f729Sjoerg Opts.getOption(options::OPT_fomit_frame_pointer));
14607330f729Sjoerg else
14617330f729Sjoerg DAL.AddFlagArg(
14627330f729Sjoerg A, Opts.getOption(options::OPT_fno_omit_frame_pointer));
14637330f729Sjoerg } else {
14647330f729Sjoerg // Don't warn about /Oy- in x86-64 builds (where
14657330f729Sjoerg // SupportsForcingFramePointer is false). The flag having no effect
14667330f729Sjoerg // there is a compiler-internal optimization, and people shouldn't have
14677330f729Sjoerg // to special-case their build files for x86-64 clang-cl.
14687330f729Sjoerg A->claim();
14697330f729Sjoerg }
14707330f729Sjoerg break;
14717330f729Sjoerg }
14727330f729Sjoerg }
14737330f729Sjoerg }
14747330f729Sjoerg }
14757330f729Sjoerg
TranslateDArg(Arg * A,llvm::opt::DerivedArgList & DAL,const OptTable & Opts)14767330f729Sjoerg static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL,
14777330f729Sjoerg const OptTable &Opts) {
14787330f729Sjoerg assert(A->getOption().matches(options::OPT_D));
14797330f729Sjoerg
14807330f729Sjoerg StringRef Val = A->getValue();
14817330f729Sjoerg size_t Hash = Val.find('#');
14827330f729Sjoerg if (Hash == StringRef::npos || Hash > Val.find('=')) {
14837330f729Sjoerg DAL.append(A);
14847330f729Sjoerg return;
14857330f729Sjoerg }
14867330f729Sjoerg
1487*e038c9c4Sjoerg std::string NewVal = std::string(Val);
14887330f729Sjoerg NewVal[Hash] = '=';
14897330f729Sjoerg DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal);
14907330f729Sjoerg }
14917330f729Sjoerg
14927330f729Sjoerg llvm::opt::DerivedArgList *
TranslateArgs(const llvm::opt::DerivedArgList & Args,StringRef BoundArch,Action::OffloadKind OFK) const14937330f729Sjoerg MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
1494*e038c9c4Sjoerg StringRef BoundArch,
1495*e038c9c4Sjoerg Action::OffloadKind OFK) const {
14967330f729Sjoerg DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
14977330f729Sjoerg const OptTable &Opts = getDriver().getOpts();
14987330f729Sjoerg
14997330f729Sjoerg // /Oy and /Oy- don't have an effect on X86-64
15007330f729Sjoerg bool SupportsForcingFramePointer = getArch() != llvm::Triple::x86_64;
15017330f729Sjoerg
15027330f729Sjoerg // The -O[12xd] flag actually expands to several flags. We must desugar the
15037330f729Sjoerg // flags so that options embedded can be negated. For example, the '-O2' flag
15047330f729Sjoerg // enables '-Oy'. Expanding '-O2' into its constituent flags allows us to
15057330f729Sjoerg // correctly handle '-O2 -Oy-' where the trailing '-Oy-' disables a single
15067330f729Sjoerg // aspect of '-O2'.
15077330f729Sjoerg //
15087330f729Sjoerg // Note that this expansion logic only applies to the *last* of '[12xd]'.
15097330f729Sjoerg
15107330f729Sjoerg // First step is to search for the character we'd like to expand.
15117330f729Sjoerg const char *ExpandChar = nullptr;
15127330f729Sjoerg for (Arg *A : Args.filtered(options::OPT__SLASH_O)) {
15137330f729Sjoerg StringRef OptStr = A->getValue();
15147330f729Sjoerg for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
15157330f729Sjoerg char OptChar = OptStr[I];
15167330f729Sjoerg char PrevChar = I > 0 ? OptStr[I - 1] : '0';
15177330f729Sjoerg if (PrevChar == 'b') {
15187330f729Sjoerg // OptChar does not expand; it's an argument to the previous char.
15197330f729Sjoerg continue;
15207330f729Sjoerg }
15217330f729Sjoerg if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd')
15227330f729Sjoerg ExpandChar = OptStr.data() + I;
15237330f729Sjoerg }
15247330f729Sjoerg }
15257330f729Sjoerg
15267330f729Sjoerg for (Arg *A : Args) {
15277330f729Sjoerg if (A->getOption().matches(options::OPT__SLASH_O)) {
15287330f729Sjoerg // The -O flag actually takes an amalgam of other options. For example,
15297330f729Sjoerg // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'.
15307330f729Sjoerg TranslateOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, Opts);
15317330f729Sjoerg } else if (A->getOption().matches(options::OPT_D)) {
15327330f729Sjoerg // Translate -Dfoo#bar into -Dfoo=bar.
15337330f729Sjoerg TranslateDArg(A, *DAL, Opts);
1534*e038c9c4Sjoerg } else if (OFK != Action::OFK_HIP) {
1535*e038c9c4Sjoerg // HIP Toolchain translates input args by itself.
15367330f729Sjoerg DAL->append(A);
15377330f729Sjoerg }
15387330f729Sjoerg }
15397330f729Sjoerg
15407330f729Sjoerg return DAL;
15417330f729Sjoerg }
1542