xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/Driver/ToolChains/MSVC.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
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