12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625 |
- //===-- MSVC.cpp - MSVC ToolChain Implementations -------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "MSVC.h"
- #include "CommonArgs.h"
- #include "Darwin.h"
- #include "clang/Basic/CharInfo.h"
- #include "clang/Basic/Version.h"
- #include "clang/Config/config.h"
- #include "clang/Driver/Compilation.h"
- #include "clang/Driver/Driver.h"
- #include "clang/Driver/DriverDiagnostic.h"
- #include "clang/Driver/Options.h"
- #include "clang/Driver/SanitizerArgs.h"
- #include "llvm/ADT/StringExtras.h"
- #include "llvm/ADT/StringSwitch.h"
- #include "llvm/Option/Arg.h"
- #include "llvm/Option/ArgList.h"
- #include "llvm/Support/ConvertUTF.h"
- #include "llvm/Support/ErrorHandling.h"
- #include "llvm/Support/FileSystem.h"
- #include "llvm/Support/Host.h"
- #include "llvm/Support/MemoryBuffer.h"
- #include "llvm/Support/Path.h"
- #include "llvm/Support/Process.h"
- #include "llvm/Support/VirtualFileSystem.h"
- #include <cstdio>
- #ifdef _WIN32
- #define WIN32_LEAN_AND_MEAN
- #define NOGDI
- #ifndef NOMINMAX
- #define NOMINMAX
- #endif
- #include <windows.h>
- #endif
- #ifdef _MSC_VER
- // Don't support SetupApi on MinGW.
- #define USE_MSVC_SETUP_API
- // Make sure this comes before MSVCSetupApi.h
- #include <comdef.h>
- #ifdef __clang__
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wnon-virtual-dtor"
- #endif
- #include "MSVCSetupApi.h"
- #ifdef __clang__
- #pragma clang diagnostic pop
- #endif
- #include "llvm/Support/COM.h"
- _COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration));
- _COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2));
- _COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper));
- _COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances));
- _COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance));
- _COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2));
- #endif
- using namespace clang::driver;
- using namespace clang::driver::toolchains;
- using namespace clang::driver::tools;
- using namespace clang;
- using namespace llvm::opt;
- // Windows SDKs and VC Toolchains group their contents into subdirectories based
- // on the target architecture. This function converts an llvm::Triple::ArchType
- // to the corresponding subdirectory name.
- static const char *llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch) {
- using ArchType = llvm::Triple::ArchType;
- switch (Arch) {
- case ArchType::x86:
- return "x86";
- case ArchType::x86_64:
- return "x64";
- case ArchType::arm:
- return "arm";
- case ArchType::aarch64:
- return "arm64";
- default:
- return "";
- }
- }
- // Similar to the above function, but for Visual Studios before VS2017.
- static const char *llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch) {
- using ArchType = llvm::Triple::ArchType;
- switch (Arch) {
- case ArchType::x86:
- // x86 is default in legacy VC toolchains.
- // e.g. x86 libs are directly in /lib as opposed to /lib/x86.
- return "";
- case ArchType::x86_64:
- return "amd64";
- case ArchType::arm:
- return "arm";
- case ArchType::aarch64:
- return "arm64";
- default:
- return "";
- }
- }
- // Similar to the above function, but for DevDiv internal builds.
- static const char *llvmArchToDevDivInternalArch(llvm::Triple::ArchType Arch) {
- using ArchType = llvm::Triple::ArchType;
- switch (Arch) {
- case ArchType::x86:
- return "i386";
- case ArchType::x86_64:
- return "amd64";
- case ArchType::arm:
- return "arm";
- case ArchType::aarch64:
- return "arm64";
- default:
- return "";
- }
- }
- static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) {
- auto Status = VFS.status(Path);
- if (!Status)
- return false;
- return (Status->getPermissions() & llvm::sys::fs::perms::all_exe) != 0;
- }
- // Defined below.
- // Forward declare this so there aren't too many things above the constructor.
- static bool getSystemRegistryString(const char *keyPath, const char *valueName,
- std::string &value, std::string *phValue);
- static std::string getHighestNumericTupleInDirectory(llvm::vfs::FileSystem &VFS,
- StringRef Directory) {
- std::string Highest;
- llvm::VersionTuple HighestTuple;
- std::error_code EC;
- for (llvm::vfs::directory_iterator DirIt = VFS.dir_begin(Directory, EC),
- DirEnd;
- !EC && DirIt != DirEnd; DirIt.increment(EC)) {
- auto Status = VFS.status(DirIt->path());
- if (!Status || !Status->isDirectory())
- continue;
- StringRef CandidateName = llvm::sys::path::filename(DirIt->path());
- llvm::VersionTuple Tuple;
- if (Tuple.tryParse(CandidateName)) // tryParse() returns true on error.
- continue;
- if (Tuple > HighestTuple) {
- HighestTuple = Tuple;
- Highest = CandidateName.str();
- }
- }
- return Highest;
- }
- // Check command line arguments to try and find a toolchain.
- static bool
- findVCToolChainViaCommandLine(llvm::vfs::FileSystem &VFS, const ArgList &Args,
- std::string &Path,
- MSVCToolChain::ToolsetLayout &VSLayout) {
- // Don't validate the input; trust the value supplied by the user.
- // The primary motivation is to prevent unnecessary file and registry access.
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir,
- options::OPT__SLASH_winsysroot)) {
- if (A->getOption().getID() == options::OPT__SLASH_winsysroot) {
- llvm::SmallString<128> ToolsPath(A->getValue());
- llvm::sys::path::append(ToolsPath, "VC", "Tools", "MSVC");
- std::string VCToolsVersion;
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion))
- VCToolsVersion = A->getValue();
- else
- VCToolsVersion = getHighestNumericTupleInDirectory(VFS, ToolsPath);
- llvm::sys::path::append(ToolsPath, VCToolsVersion);
- Path = std::string(ToolsPath.str());
- } else {
- Path = A->getValue();
- }
- VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
- return true;
- }
- return false;
- }
- // Check various environment variables to try and find a toolchain.
- static bool
- findVCToolChainViaEnvironment(llvm::vfs::FileSystem &VFS, std::string &Path,
- MSVCToolChain::ToolsetLayout &VSLayout) {
- // These variables are typically set by vcvarsall.bat
- // when launching a developer command prompt.
- if (llvm::Optional<std::string> VCToolsInstallDir =
- llvm::sys::Process::GetEnv("VCToolsInstallDir")) {
- // This is only set by newer Visual Studios, and it leads straight to
- // the toolchain directory.
- Path = std::move(*VCToolsInstallDir);
- VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
- return true;
- }
- if (llvm::Optional<std::string> VCInstallDir =
- llvm::sys::Process::GetEnv("VCINSTALLDIR")) {
- // If the previous variable isn't set but this one is, then we've found
- // an older Visual Studio. This variable is set by newer Visual Studios too,
- // so this check has to appear second.
- // In older Visual Studios, the VC directory is the toolchain.
- Path = std::move(*VCInstallDir);
- VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
- return true;
- }
- // We couldn't find any VC environment variables. Let's walk through PATH and
- // see if it leads us to a VC toolchain bin directory. If it does, pick the
- // first one that we find.
- if (llvm::Optional<std::string> PathEnv =
- llvm::sys::Process::GetEnv("PATH")) {
- llvm::SmallVector<llvm::StringRef, 8> PathEntries;
- llvm::StringRef(*PathEnv).split(PathEntries, llvm::sys::EnvPathSeparator);
- for (llvm::StringRef PathEntry : PathEntries) {
- if (PathEntry.empty())
- continue;
- llvm::SmallString<256> ExeTestPath;
- // If cl.exe doesn't exist, then this definitely isn't a VC toolchain.
- ExeTestPath = PathEntry;
- llvm::sys::path::append(ExeTestPath, "cl.exe");
- if (!VFS.exists(ExeTestPath))
- continue;
- // cl.exe existing isn't a conclusive test for a VC toolchain; clang also
- // has a cl.exe. So let's check for link.exe too.
- ExeTestPath = PathEntry;
- llvm::sys::path::append(ExeTestPath, "link.exe");
- if (!VFS.exists(ExeTestPath))
- continue;
- // whatever/VC/bin --> old toolchain, VC dir is toolchain dir.
- llvm::StringRef TestPath = PathEntry;
- bool IsBin =
- llvm::sys::path::filename(TestPath).equals_insensitive("bin");
- if (!IsBin) {
- // Strip any architecture subdir like "amd64".
- TestPath = llvm::sys::path::parent_path(TestPath);
- IsBin = llvm::sys::path::filename(TestPath).equals_insensitive("bin");
- }
- if (IsBin) {
- llvm::StringRef ParentPath = llvm::sys::path::parent_path(TestPath);
- llvm::StringRef ParentFilename = llvm::sys::path::filename(ParentPath);
- if (ParentFilename.equals_insensitive("VC")) {
- Path = std::string(ParentPath);
- VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
- return true;
- }
- if (ParentFilename.equals_insensitive("x86ret") ||
- ParentFilename.equals_insensitive("x86chk") ||
- ParentFilename.equals_insensitive("amd64ret") ||
- ParentFilename.equals_insensitive("amd64chk")) {
- Path = std::string(ParentPath);
- VSLayout = MSVCToolChain::ToolsetLayout::DevDivInternal;
- return true;
- }
- } else {
- // This could be a new (>=VS2017) toolchain. If it is, we should find
- // path components with these prefixes when walking backwards through
- // the path.
- // Note: empty strings match anything.
- llvm::StringRef ExpectedPrefixes[] = {"", "Host", "bin", "",
- "MSVC", "Tools", "VC"};
- auto It = llvm::sys::path::rbegin(PathEntry);
- auto End = llvm::sys::path::rend(PathEntry);
- for (llvm::StringRef Prefix : ExpectedPrefixes) {
- if (It == End)
- goto NotAToolChain;
- if (!It->startswith_insensitive(Prefix))
- goto NotAToolChain;
- ++It;
- }
- // We've found a new toolchain!
- // Back up 3 times (/bin/Host/arch) to get the root path.
- llvm::StringRef ToolChainPath(PathEntry);
- for (int i = 0; i < 3; ++i)
- ToolChainPath = llvm::sys::path::parent_path(ToolChainPath);
- Path = std::string(ToolChainPath);
- VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
- return true;
- }
- NotAToolChain:
- continue;
- }
- }
- return false;
- }
- // Query the Setup Config server for installs, then pick the newest version
- // and find its default VC toolchain.
- // This is the preferred way to discover new Visual Studios, as they're no
- // longer listed in the registry.
- static bool
- findVCToolChainViaSetupConfig(llvm::vfs::FileSystem &VFS, std::string &Path,
- MSVCToolChain::ToolsetLayout &VSLayout) {
- #if !defined(USE_MSVC_SETUP_API)
- return false;
- #else
- // FIXME: This really should be done once in the top-level program's main
- // function, as it may have already been initialized with a different
- // threading model otherwise.
- llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::SingleThreaded);
- HRESULT HR;
- // _com_ptr_t will throw a _com_error if a COM calls fail.
- // The LLVM coding standards forbid exception handling, so we'll have to
- // stop them from being thrown in the first place.
- // The destructor will put the regular error handler back when we leave
- // this scope.
- struct SuppressCOMErrorsRAII {
- static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {}
- SuppressCOMErrorsRAII() { _set_com_error_handler(handler); }
- ~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); }
- } COMErrorSuppressor;
- ISetupConfigurationPtr Query;
- HR = Query.CreateInstance(__uuidof(SetupConfiguration));
- if (FAILED(HR))
- return false;
- IEnumSetupInstancesPtr EnumInstances;
- HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances);
- if (FAILED(HR))
- return false;
- ISetupInstancePtr Instance;
- HR = EnumInstances->Next(1, &Instance, nullptr);
- if (HR != S_OK)
- return false;
- ISetupInstancePtr NewestInstance;
- Optional<uint64_t> NewestVersionNum;
- do {
- bstr_t VersionString;
- uint64_t VersionNum;
- HR = Instance->GetInstallationVersion(VersionString.GetAddress());
- if (FAILED(HR))
- continue;
- HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum);
- if (FAILED(HR))
- continue;
- if (!NewestVersionNum || (VersionNum > NewestVersionNum)) {
- NewestInstance = Instance;
- NewestVersionNum = VersionNum;
- }
- } while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK);
- if (!NewestInstance)
- return false;
- bstr_t VCPathWide;
- HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress());
- if (FAILED(HR))
- return false;
- std::string VCRootPath;
- llvm::convertWideToUTF8(std::wstring(VCPathWide), VCRootPath);
- llvm::SmallString<256> ToolsVersionFilePath(VCRootPath);
- llvm::sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build",
- "Microsoft.VCToolsVersion.default.txt");
- auto ToolsVersionFile = llvm::MemoryBuffer::getFile(ToolsVersionFilePath);
- if (!ToolsVersionFile)
- return false;
- llvm::SmallString<256> ToolchainPath(VCRootPath);
- llvm::sys::path::append(ToolchainPath, "Tools", "MSVC",
- ToolsVersionFile->get()->getBuffer().rtrim());
- auto Status = VFS.status(ToolchainPath);
- if (!Status || !Status->isDirectory())
- return false;
- Path = std::string(ToolchainPath.str());
- VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
- return true;
- #endif
- }
- // Look in the registry for Visual Studio installs, and use that to get
- // a toolchain path. VS2017 and newer don't get added to the registry.
- // So if we find something here, we know that it's an older version.
- static bool findVCToolChainViaRegistry(std::string &Path,
- MSVCToolChain::ToolsetLayout &VSLayout) {
- std::string VSInstallPath;
- if (getSystemRegistryString(R"(SOFTWARE\Microsoft\VisualStudio\$VERSION)",
- "InstallDir", VSInstallPath, nullptr) ||
- getSystemRegistryString(R"(SOFTWARE\Microsoft\VCExpress\$VERSION)",
- "InstallDir", VSInstallPath, nullptr)) {
- if (!VSInstallPath.empty()) {
- llvm::SmallString<256> VCPath(llvm::StringRef(
- VSInstallPath.c_str(), VSInstallPath.find(R"(\Common7\IDE)")));
- llvm::sys::path::append(VCPath, "VC");
- Path = std::string(VCPath.str());
- VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
- return true;
- }
- }
- return false;
- }
- // Try to find Exe from a Visual Studio distribution. This first tries to find
- // an installed copy of Visual Studio and, failing that, looks in the PATH,
- // making sure that whatever executable that's found is not a same-named exe
- // from clang itself to prevent clang from falling back to itself.
- static std::string FindVisualStudioExecutable(const ToolChain &TC,
- const char *Exe) {
- const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);
- SmallString<128> FilePath(MSVC.getSubDirectoryPath(
- toolchains::MSVCToolChain::SubDirectoryType::Bin));
- llvm::sys::path::append(FilePath, Exe);
- return std::string(canExecute(TC.getVFS(), FilePath) ? FilePath.str() : Exe);
- }
- void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
- auto &TC = static_cast<const toolchains::MSVCToolChain &>(getToolChain());
- assert((Output.isFilename() || Output.isNothing()) && "invalid output");
- if (Output.isFilename())
- CmdArgs.push_back(
- Args.MakeArgString(std::string("-out:") + Output.getFilename()));
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) &&
- !C.getDriver().IsCLMode()) {
- CmdArgs.push_back("-defaultlib:libcmt");
- CmdArgs.push_back("-defaultlib:oldnames");
- }
- // If the VC environment hasn't been configured (perhaps because the user
- // did not run vcvarsall), try to build a consistent link environment. If
- // the environment variable is set however, assume the user knows what
- // they're doing. If the user passes /vctoolsdir or /winsdkdir, trust that
- // over env vars.
- if (const Arg *A = Args.getLastArg(options::OPT__SLASH_diasdkdir,
- options::OPT__SLASH_winsysroot)) {
- // cl.exe doesn't find the DIA SDK automatically, so this too requires
- // explicit flags and doesn't automatically look in "DIA SDK" relative
- // to the path we found for VCToolChainPath.
- llvm::SmallString<128> DIAPath(A->getValue());
- if (A->getOption().getID() == options::OPT__SLASH_winsysroot)
- llvm::sys::path::append(DIAPath, "DIA SDK");
- // The DIA SDK always uses the legacy vc arch, even in new MSVC versions.
- llvm::sys::path::append(DIAPath, "lib",
- llvmArchToLegacyVCArch(TC.getArch()));
- CmdArgs.push_back(Args.MakeArgString(Twine("-libpath:") + DIAPath));
- }
- if (!llvm::sys::Process::GetEnv("LIB") ||
- Args.getLastArg(options::OPT__SLASH_vctoolsdir,
- options::OPT__SLASH_winsysroot)) {
- CmdArgs.push_back(Args.MakeArgString(
- Twine("-libpath:") +
- TC.getSubDirectoryPath(
- toolchains::MSVCToolChain::SubDirectoryType::Lib)));
- CmdArgs.push_back(Args.MakeArgString(
- Twine("-libpath:") +
- TC.getSubDirectoryPath(toolchains::MSVCToolChain::SubDirectoryType::Lib,
- "atlmfc")));
- }
- if (!llvm::sys::Process::GetEnv("LIB") ||
- Args.getLastArg(options::OPT__SLASH_winsdkdir,
- options::OPT__SLASH_winsysroot)) {
- if (TC.useUniversalCRT()) {
- std::string UniversalCRTLibPath;
- if (TC.getUniversalCRTLibraryPath(Args, UniversalCRTLibPath))
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath));
- }
- std::string WindowsSdkLibPath;
- if (TC.getWindowsSDKLibraryPath(Args, WindowsSdkLibPath))
- CmdArgs.push_back(
- Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
- }
- // Add the compiler-rt library directories to libpath if they exist to help
- // the linker find the various sanitizer, builtin, and profiling runtimes.
- for (const auto &LibPath : TC.getLibraryPaths()) {
- if (TC.getVFS().exists(LibPath))
- CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));
- }
- auto CRTPath = TC.getCompilerRTPath();
- if (TC.getVFS().exists(CRTPath))
- CmdArgs.push_back(Args.MakeArgString("-libpath:" + CRTPath));
- if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L))
- for (const auto &LibPath : Args.getAllArgValues(options::OPT_L))
- CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));
- CmdArgs.push_back("-nologo");
- if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7))
- CmdArgs.push_back("-debug");
- // If we specify /hotpatch, let the linker add padding in front of each
- // function, like MSVC does.
- if (Args.hasArg(options::OPT_fms_hotpatch, options::OPT__SLASH_hotpatch))
- CmdArgs.push_back("-functionpadmin");
- // Pass on /Brepro if it was passed to the compiler.
- // Note that /Brepro maps to -mno-incremental-linker-compatible.
- bool DefaultIncrementalLinkerCompatible =
- C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment();
- if (!Args.hasFlag(options::OPT_mincremental_linker_compatible,
- options::OPT_mno_incremental_linker_compatible,
- DefaultIncrementalLinkerCompatible))
- CmdArgs.push_back("-Brepro");
- bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd,
- options::OPT_shared);
- if (DLL) {
- CmdArgs.push_back(Args.MakeArgString("-dll"));
- SmallString<128> ImplibName(Output.getFilename());
- llvm::sys::path::replace_extension(ImplibName, "lib");
- CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName));
- }
- if (TC.getSanitizerArgs(Args).needsFuzzer()) {
- if (!Args.hasArg(options::OPT_shared))
- CmdArgs.push_back(
- Args.MakeArgString(std::string("-wholearchive:") +
- TC.getCompilerRTArgString(Args, "fuzzer")));
- CmdArgs.push_back(Args.MakeArgString("-debug"));
- // Prevent the linker from padding sections we use for instrumentation
- // arrays.
- CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
- }
- if (TC.getSanitizerArgs(Args).needsAsanRt()) {
- CmdArgs.push_back(Args.MakeArgString("-debug"));
- CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
- if (TC.getSanitizerArgs(Args).needsSharedRt() ||
- Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) {
- for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"})
- CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
- // Make sure the dynamic runtime thunk is not optimized out at link time
- // to ensure proper SEH handling.
- CmdArgs.push_back(Args.MakeArgString(
- TC.getArch() == llvm::Triple::x86
- ? "-include:___asan_seh_interceptor"
- : "-include:__asan_seh_interceptor"));
- // Make sure the linker consider all object files from the dynamic runtime
- // thunk.
- CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") +
- TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk")));
- } else if (DLL) {
- CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk"));
- } else {
- for (const auto &Lib : {"asan", "asan_cxx"}) {
- CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
- // Make sure the linker consider all object files from the static lib.
- // This is necessary because instrumented dlls need access to all the
- // interface exported by the static lib in the main executable.
- CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") +
- TC.getCompilerRT(Args, Lib)));
- }
- }
- }
- Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);
- // Control Flow Guard checks
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) {
- StringRef GuardArgs = A->getValue();
- if (GuardArgs.equals_insensitive("cf") ||
- GuardArgs.equals_insensitive("cf,nochecks")) {
- // MSVC doesn't yet support the "nochecks" modifier.
- CmdArgs.push_back("-guard:cf");
- } else if (GuardArgs.equals_insensitive("cf-")) {
- CmdArgs.push_back("-guard:cf-");
- } else if (GuardArgs.equals_insensitive("ehcont")) {
- CmdArgs.push_back("-guard:ehcont");
- } else if (GuardArgs.equals_insensitive("ehcont-")) {
- CmdArgs.push_back("-guard:ehcont-");
- }
- }
- if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
- options::OPT_fno_openmp, false)) {
- CmdArgs.push_back("-nodefaultlib:vcomp.lib");
- CmdArgs.push_back("-nodefaultlib:vcompd.lib");
- CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") +
- TC.getDriver().Dir + "/../lib"));
- switch (TC.getDriver().getOpenMPRuntime(Args)) {
- case Driver::OMPRT_OMP:
- CmdArgs.push_back("-defaultlib:libomp.lib");
- break;
- case Driver::OMPRT_IOMP5:
- CmdArgs.push_back("-defaultlib:libiomp5md.lib");
- break;
- case Driver::OMPRT_GOMP:
- break;
- case Driver::OMPRT_Unknown:
- // Already diagnosed.
- break;
- }
- }
- // Add compiler-rt lib in case if it was explicitly
- // specified as an argument for --rtlib option.
- if (!Args.hasArg(options::OPT_nostdlib)) {
- AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args);
- }
- // Add filenames, libraries, and other linker inputs.
- for (const auto &Input : Inputs) {
- if (Input.isFilename()) {
- CmdArgs.push_back(Input.getFilename());
- continue;
- }
- const Arg &A = Input.getInputArg();
- // Render -l options differently for the MSVC linker.
- if (A.getOption().matches(options::OPT_l)) {
- StringRef Lib = A.getValue();
- const char *LinkLibArg;
- if (Lib.endswith(".lib"))
- LinkLibArg = Args.MakeArgString(Lib);
- else
- LinkLibArg = Args.MakeArgString(Lib + ".lib");
- CmdArgs.push_back(LinkLibArg);
- continue;
- }
- // Otherwise, this is some other kind of linker input option like -Wl, -z,
- // or -L. Render it, even if MSVC doesn't understand it.
- A.renderAsInput(Args, CmdArgs);
- }
- TC.addProfileRTLibs(Args, CmdArgs);
- std::vector<const char *> Environment;
- // We need to special case some linker paths. In the case of lld, we need to
- // translate 'lld' into 'lld-link', and in the case of the regular msvc
- // linker, we need to use a special search algorithm.
- llvm::SmallString<128> linkPath;
- StringRef Linker
- = Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER);
- if (Linker.empty())
- Linker = "link";
- if (Linker.equals_insensitive("lld"))
- Linker = "lld-link";
- if (Linker.equals_insensitive("link")) {
- // If we're using the MSVC linker, it's not sufficient to just use link
- // from the program PATH, because other environments like GnuWin32 install
- // their own link.exe which may come first.
- linkPath = FindVisualStudioExecutable(TC, "link.exe");
- if (!TC.FoundMSVCInstall() && !canExecute(TC.getVFS(), linkPath)) {
- llvm::SmallString<128> ClPath;
- ClPath = TC.GetProgramPath("cl.exe");
- if (canExecute(TC.getVFS(), ClPath)) {
- linkPath = llvm::sys::path::parent_path(ClPath);
- llvm::sys::path::append(linkPath, "link.exe");
- if (!canExecute(TC.getVFS(), linkPath))
- C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found);
- } else {
- C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found);
- }
- }
- #ifdef _WIN32
- // When cross-compiling with VS2017 or newer, link.exe expects to have
- // its containing bin directory at the top of PATH, followed by the
- // native target bin directory.
- // e.g. when compiling for x86 on an x64 host, PATH should start with:
- // /bin/Hostx64/x86;/bin/Hostx64/x64
- // This doesn't attempt to handle ToolsetLayout::DevDivInternal.
- if (TC.getIsVS2017OrNewer() &&
- llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) {
- auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch();
- auto EnvBlockWide =
- std::unique_ptr<wchar_t[], decltype(&FreeEnvironmentStringsW)>(
- GetEnvironmentStringsW(), FreeEnvironmentStringsW);
- if (!EnvBlockWide)
- goto SkipSettingEnvironment;
- size_t EnvCount = 0;
- size_t EnvBlockLen = 0;
- while (EnvBlockWide[EnvBlockLen] != L'\0') {
- ++EnvCount;
- EnvBlockLen += std::wcslen(&EnvBlockWide[EnvBlockLen]) +
- 1 /*string null-terminator*/;
- }
- ++EnvBlockLen; // add the block null-terminator
- std::string EnvBlock;
- if (!llvm::convertUTF16ToUTF8String(
- llvm::ArrayRef<char>(reinterpret_cast<char *>(EnvBlockWide.get()),
- EnvBlockLen * sizeof(EnvBlockWide[0])),
- EnvBlock))
- goto SkipSettingEnvironment;
- Environment.reserve(EnvCount);
- // Now loop over each string in the block and copy them into the
- // environment vector, adjusting the PATH variable as needed when we
- // find it.
- for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) {
- llvm::StringRef EnvVar(Cursor);
- if (EnvVar.startswith_insensitive("path=")) {
- using SubDirectoryType = toolchains::MSVCToolChain::SubDirectoryType;
- constexpr size_t PrefixLen = 5; // strlen("path=")
- Environment.push_back(Args.MakeArgString(
- EnvVar.substr(0, PrefixLen) +
- TC.getSubDirectoryPath(SubDirectoryType::Bin) +
- llvm::Twine(llvm::sys::EnvPathSeparator) +
- TC.getSubDirectoryPath(SubDirectoryType::Bin, "", HostArch) +
- (EnvVar.size() > PrefixLen
- ? llvm::Twine(llvm::sys::EnvPathSeparator) +
- EnvVar.substr(PrefixLen)
- : "")));
- } else {
- Environment.push_back(Args.MakeArgString(EnvVar));
- }
- Cursor += EnvVar.size() + 1 /*null-terminator*/;
- }
- }
- SkipSettingEnvironment:;
- #endif
- } else {
- linkPath = TC.GetProgramPath(Linker.str().c_str());
- }
- auto LinkCmd = std::make_unique<Command>(
- JA, *this, ResponseFileSupport::AtFileUTF16(),
- Args.MakeArgString(linkPath), CmdArgs, Inputs, Output);
- if (!Environment.empty())
- LinkCmd->setEnvironment(Environment);
- C.addCommand(std::move(LinkCmd));
- }
- MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args),
- RocmInstallation(D, Triple, Args) {
- getProgramPaths().push_back(getDriver().getInstalledDir());
- if (getDriver().getInstalledDir() != getDriver().Dir)
- getProgramPaths().push_back(getDriver().Dir);
- // Check the command line first, that's the user explicitly telling us what to
- // use. Check the environment next, in case we're being invoked from a VS
- // command prompt. Failing that, just try to find the newest Visual Studio
- // version we can and use its default VC toolchain.
- findVCToolChainViaCommandLine(getVFS(), Args, VCToolChainPath, VSLayout) ||
- findVCToolChainViaEnvironment(getVFS(), VCToolChainPath, VSLayout) ||
- findVCToolChainViaSetupConfig(getVFS(), VCToolChainPath, VSLayout) ||
- findVCToolChainViaRegistry(VCToolChainPath, VSLayout);
- }
- Tool *MSVCToolChain::buildLinker() const {
- return new tools::visualstudio::Linker(*this);
- }
- Tool *MSVCToolChain::buildAssembler() const {
- if (getTriple().isOSBinFormatMachO())
- return new tools::darwin::Assembler(*this);
- getDriver().Diag(clang::diag::err_no_external_assembler);
- return nullptr;
- }
- bool MSVCToolChain::IsIntegratedAssemblerDefault() const {
- return true;
- }
- bool MSVCToolChain::IsUnwindTablesDefault(const ArgList &Args) const {
- // Don't emit unwind tables by default for MachO targets.
- if (getTriple().isOSBinFormatMachO())
- return false;
- // All non-x86_32 Windows targets require unwind tables. However, LLVM
- // doesn't know how to generate them for all targets, so only enable
- // the ones that are actually implemented.
- return getArch() == llvm::Triple::x86_64 ||
- getArch() == llvm::Triple::aarch64;
- }
- bool MSVCToolChain::isPICDefault() const {
- return getArch() == llvm::Triple::x86_64 ||
- getArch() == llvm::Triple::aarch64;
- }
- bool MSVCToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const {
- return false;
- }
- bool MSVCToolChain::isPICDefaultForced() const {
- return getArch() == llvm::Triple::x86_64 ||
- getArch() == llvm::Triple::aarch64;
- }
- void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
- }
- void MSVCToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args);
- }
- void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const {
- CudaInstallation.print(OS);
- RocmInstallation.print(OS);
- }
- // Get the path to a specific subdirectory in the current toolchain for
- // a given target architecture.
- // VS2017 changed the VC toolchain layout, so this should be used instead
- // of hardcoding paths.
- std::string
- MSVCToolChain::getSubDirectoryPath(SubDirectoryType Type,
- llvm::StringRef SubdirParent,
- llvm::Triple::ArchType TargetArch) const {
- const char *SubdirName;
- const char *IncludeName;
- switch (VSLayout) {
- case ToolsetLayout::OlderVS:
- SubdirName = llvmArchToLegacyVCArch(TargetArch);
- IncludeName = "include";
- break;
- case ToolsetLayout::VS2017OrNewer:
- SubdirName = llvmArchToWindowsSDKArch(TargetArch);
- IncludeName = "include";
- break;
- case ToolsetLayout::DevDivInternal:
- SubdirName = llvmArchToDevDivInternalArch(TargetArch);
- IncludeName = "inc";
- break;
- }
- llvm::SmallString<256> Path(VCToolChainPath);
- if (!SubdirParent.empty())
- llvm::sys::path::append(Path, SubdirParent);
- switch (Type) {
- case SubDirectoryType::Bin:
- if (VSLayout == ToolsetLayout::VS2017OrNewer) {
- const bool HostIsX64 =
- llvm::Triple(llvm::sys::getProcessTriple()).isArch64Bit();
- const char *const HostName = HostIsX64 ? "Hostx64" : "Hostx86";
- llvm::sys::path::append(Path, "bin", HostName, SubdirName);
- } else { // OlderVS or DevDivInternal
- llvm::sys::path::append(Path, "bin", SubdirName);
- }
- break;
- case SubDirectoryType::Include:
- llvm::sys::path::append(Path, IncludeName);
- break;
- case SubDirectoryType::Lib:
- llvm::sys::path::append(Path, "lib", SubdirName);
- break;
- }
- return std::string(Path.str());
- }
- #ifdef _WIN32
- static bool readFullStringValue(HKEY hkey, const char *valueName,
- std::string &value) {
- std::wstring WideValueName;
- if (!llvm::ConvertUTF8toWide(valueName, WideValueName))
- return false;
- DWORD result = 0;
- DWORD valueSize = 0;
- DWORD type = 0;
- // First just query for the required size.
- result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, &type, NULL,
- &valueSize);
- if (result != ERROR_SUCCESS || type != REG_SZ || !valueSize)
- return false;
- std::vector<BYTE> buffer(valueSize);
- result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, NULL, &buffer[0],
- &valueSize);
- if (result == ERROR_SUCCESS) {
- std::wstring WideValue(reinterpret_cast<const wchar_t *>(buffer.data()),
- valueSize / sizeof(wchar_t));
- if (valueSize && WideValue.back() == L'\0') {
- WideValue.pop_back();
- }
- // The destination buffer must be empty as an invariant of the conversion
- // function; but this function is sometimes called in a loop that passes in
- // the same buffer, however. Simply clear it out so we can overwrite it.
- value.clear();
- return llvm::convertWideToUTF8(WideValue, value);
- }
- return false;
- }
- #endif
- /// Read registry string.
- /// This also supports a means to look for high-versioned keys by use
- /// of a $VERSION placeholder in the key path.
- /// $VERSION in the key path is a placeholder for the version number,
- /// causing the highest value path to be searched for and used.
- /// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
- /// There can be additional characters in the component. Only the numeric
- /// characters are compared. This function only searches HKLM.
- static bool getSystemRegistryString(const char *keyPath, const char *valueName,
- std::string &value, std::string *phValue) {
- #ifndef _WIN32
- return false;
- #else
- HKEY hRootKey = HKEY_LOCAL_MACHINE;
- HKEY hKey = NULL;
- long lResult;
- bool returnValue = false;
- const char *placeHolder = strstr(keyPath, "$VERSION");
- std::string bestName;
- // If we have a $VERSION placeholder, do the highest-version search.
- if (placeHolder) {
- const char *keyEnd = placeHolder - 1;
- const char *nextKey = placeHolder;
- // Find end of previous key.
- while ((keyEnd > keyPath) && (*keyEnd != '\\'))
- keyEnd--;
- // Find end of key containing $VERSION.
- while (*nextKey && (*nextKey != '\\'))
- nextKey++;
- size_t partialKeyLength = keyEnd - keyPath;
- char partialKey[256];
- if (partialKeyLength >= sizeof(partialKey))
- partialKeyLength = sizeof(partialKey) - 1;
- strncpy(partialKey, keyPath, partialKeyLength);
- partialKey[partialKeyLength] = '\0';
- HKEY hTopKey = NULL;
- lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY,
- &hTopKey);
- if (lResult == ERROR_SUCCESS) {
- char keyName[256];
- double bestValue = 0.0;
- DWORD index, size = sizeof(keyName) - 1;
- for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, NULL,
- NULL, NULL) == ERROR_SUCCESS;
- index++) {
- const char *sp = keyName;
- while (*sp && !isDigit(*sp))
- sp++;
- if (!*sp)
- continue;
- const char *ep = sp + 1;
- while (*ep && (isDigit(*ep) || (*ep == '.')))
- ep++;
- char numBuf[32];
- strncpy(numBuf, sp, sizeof(numBuf) - 1);
- numBuf[sizeof(numBuf) - 1] = '\0';
- double dvalue = strtod(numBuf, NULL);
- if (dvalue > bestValue) {
- // Test that InstallDir is indeed there before keeping this index.
- // Open the chosen key path remainder.
- bestName = keyName;
- // Append rest of key.
- bestName.append(nextKey);
- lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0,
- KEY_READ | KEY_WOW64_32KEY, &hKey);
- if (lResult == ERROR_SUCCESS) {
- if (readFullStringValue(hKey, valueName, value)) {
- bestValue = dvalue;
- if (phValue)
- *phValue = bestName;
- returnValue = true;
- }
- RegCloseKey(hKey);
- }
- }
- size = sizeof(keyName) - 1;
- }
- RegCloseKey(hTopKey);
- }
- } else {
- lResult =
- RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey);
- if (lResult == ERROR_SUCCESS) {
- if (readFullStringValue(hKey, valueName, value))
- returnValue = true;
- if (phValue)
- phValue->clear();
- RegCloseKey(hKey);
- }
- }
- return returnValue;
- #endif // _WIN32
- }
- // Find the most recent version of Universal CRT or Windows 10 SDK.
- // vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include
- // directory by name and uses the last one of the list.
- // So we compare entry names lexicographically to find the greatest one.
- static bool getWindows10SDKVersionFromPath(llvm::vfs::FileSystem &VFS,
- const std::string &SDKPath,
- std::string &SDKVersion) {
- llvm::SmallString<128> IncludePath(SDKPath);
- llvm::sys::path::append(IncludePath, "Include");
- SDKVersion = getHighestNumericTupleInDirectory(VFS, IncludePath);
- return !SDKVersion.empty();
- }
- static bool getWindowsSDKDirViaCommandLine(llvm::vfs::FileSystem &VFS,
- const ArgList &Args,
- std::string &Path, int &Major,
- std::string &Version) {
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir,
- options::OPT__SLASH_winsysroot)) {
- // Don't validate the input; trust the value supplied by the user.
- // The motivation is to prevent unnecessary file and registry access.
- llvm::VersionTuple SDKVersion;
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion))
- SDKVersion.tryParse(A->getValue());
- if (A->getOption().getID() == options::OPT__SLASH_winsysroot) {
- llvm::SmallString<128> SDKPath(A->getValue());
- llvm::sys::path::append(SDKPath, "Windows Kits");
- if (!SDKVersion.empty())
- llvm::sys::path::append(SDKPath, Twine(SDKVersion.getMajor()));
- else
- llvm::sys::path::append(
- SDKPath, getHighestNumericTupleInDirectory(VFS, SDKPath));
- Path = std::string(SDKPath.str());
- } else {
- Path = A->getValue();
- }
- if (!SDKVersion.empty()) {
- Major = SDKVersion.getMajor();
- Version = SDKVersion.getAsString();
- } else if (getWindows10SDKVersionFromPath(VFS, Path, Version)) {
- Major = 10;
- }
- return true;
- }
- return false;
- }
- /// Get Windows SDK installation directory.
- static bool getWindowsSDKDir(llvm::vfs::FileSystem &VFS, const ArgList &Args,
- std::string &Path, int &Major,
- std::string &WindowsSDKIncludeVersion,
- std::string &WindowsSDKLibVersion) {
- // Trust /winsdkdir and /winsdkversion if present.
- if (getWindowsSDKDirViaCommandLine(VFS, Args, Path, Major,
- WindowsSDKIncludeVersion)) {
- WindowsSDKLibVersion = WindowsSDKIncludeVersion;
- return true;
- }
- // FIXME: Try env vars (%WindowsSdkDir%, %UCRTVersion%) before going to registry.
- // Try the Windows registry.
- std::string RegistrySDKVersion;
- if (!getSystemRegistryString(
- "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
- "InstallationFolder", Path, &RegistrySDKVersion))
- return false;
- if (Path.empty() || RegistrySDKVersion.empty())
- return false;
- WindowsSDKIncludeVersion.clear();
- WindowsSDKLibVersion.clear();
- Major = 0;
- std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major);
- if (Major <= 7)
- return true;
- if (Major == 8) {
- // Windows SDK 8.x installs libraries in a folder whose names depend on the
- // version of the OS you're targeting. By default choose the newest, which
- // usually corresponds to the version of the OS you've installed the SDK on.
- const char *Tests[] = {"winv6.3", "win8", "win7"};
- for (const char *Test : Tests) {
- llvm::SmallString<128> TestPath(Path);
- llvm::sys::path::append(TestPath, "Lib", Test);
- if (VFS.exists(TestPath)) {
- WindowsSDKLibVersion = Test;
- break;
- }
- }
- return !WindowsSDKLibVersion.empty();
- }
- if (Major == 10) {
- if (!getWindows10SDKVersionFromPath(VFS, Path, WindowsSDKIncludeVersion))
- return false;
- WindowsSDKLibVersion = WindowsSDKIncludeVersion;
- return true;
- }
- // Unsupported SDK version
- return false;
- }
- // Gets the library path required to link against the Windows SDK.
- bool MSVCToolChain::getWindowsSDKLibraryPath(
- const ArgList &Args, std::string &path) const {
- std::string sdkPath;
- int sdkMajor = 0;
- std::string windowsSDKIncludeVersion;
- std::string windowsSDKLibVersion;
- path.clear();
- if (!getWindowsSDKDir(getVFS(), Args, sdkPath, sdkMajor,
- windowsSDKIncludeVersion, windowsSDKLibVersion))
- return false;
- llvm::SmallString<128> libPath(sdkPath);
- llvm::sys::path::append(libPath, "Lib");
- if (sdkMajor >= 8) {
- llvm::sys::path::append(libPath, windowsSDKLibVersion, "um",
- llvmArchToWindowsSDKArch(getArch()));
- } else {
- switch (getArch()) {
- // In Windows SDK 7.x, x86 libraries are directly in the Lib folder.
- case llvm::Triple::x86:
- break;
- case llvm::Triple::x86_64:
- llvm::sys::path::append(libPath, "x64");
- break;
- case llvm::Triple::arm:
- // It is not necessary to link against Windows SDK 7.x when targeting ARM.
- return false;
- default:
- return false;
- }
- }
- path = std::string(libPath.str());
- return true;
- }
- // Check if the Include path of a specified version of Visual Studio contains
- // specific header files. If not, they are probably shipped with Universal CRT.
- bool MSVCToolChain::useUniversalCRT() const {
- llvm::SmallString<128> TestPath(
- getSubDirectoryPath(SubDirectoryType::Include));
- llvm::sys::path::append(TestPath, "stdlib.h");
- return !getVFS().exists(TestPath);
- }
- static bool getUniversalCRTSdkDir(llvm::vfs::FileSystem &VFS,
- const ArgList &Args, std::string &Path,
- std::string &UCRTVersion) {
- // If /winsdkdir is passed, use it as location for the UCRT too.
- // FIXME: Should there be a dedicated /ucrtdir to override /winsdkdir?
- int Major;
- if (getWindowsSDKDirViaCommandLine(VFS, Args, Path, Major, UCRTVersion))
- return true;
- // FIXME: Try env vars (%UniversalCRTSdkDir%, %UCRTVersion%) before going to
- // registry.
- // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry
- // for the specific key "KitsRoot10". So do we.
- if (!getSystemRegistryString(
- "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10",
- Path, nullptr))
- return false;
- return getWindows10SDKVersionFromPath(VFS, Path, UCRTVersion);
- }
- bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args,
- std::string &Path) const {
- std::string UniversalCRTSdkPath;
- std::string UCRTVersion;
- Path.clear();
- if (!getUniversalCRTSdkDir(getVFS(), Args, UniversalCRTSdkPath, UCRTVersion))
- return false;
- StringRef ArchName = llvmArchToWindowsSDKArch(getArch());
- if (ArchName.empty())
- return false;
- llvm::SmallString<128> LibPath(UniversalCRTSdkPath);
- llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName);
- Path = std::string(LibPath.str());
- return true;
- }
- static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) {
- VersionTuple Version;
- #ifdef _WIN32
- SmallString<128> ClExe(BinDir);
- llvm::sys::path::append(ClExe, "cl.exe");
- std::wstring ClExeWide;
- if (!llvm::ConvertUTF8toWide(ClExe.c_str(), ClExeWide))
- return Version;
- const DWORD VersionSize = ::GetFileVersionInfoSizeW(ClExeWide.c_str(),
- nullptr);
- if (VersionSize == 0)
- return Version;
- SmallVector<uint8_t, 4 * 1024> VersionBlock(VersionSize);
- if (!::GetFileVersionInfoW(ClExeWide.c_str(), 0, VersionSize,
- VersionBlock.data()))
- return Version;
- VS_FIXEDFILEINFO *FileInfo = nullptr;
- UINT FileInfoSize = 0;
- if (!::VerQueryValueW(VersionBlock.data(), L"\\",
- reinterpret_cast<LPVOID *>(&FileInfo), &FileInfoSize) ||
- FileInfoSize < sizeof(*FileInfo))
- return Version;
- const unsigned Major = (FileInfo->dwFileVersionMS >> 16) & 0xFFFF;
- const unsigned Minor = (FileInfo->dwFileVersionMS ) & 0xFFFF;
- const unsigned Micro = (FileInfo->dwFileVersionLS >> 16) & 0xFFFF;
- Version = VersionTuple(Major, Minor, Micro);
- #endif
- return Version;
- }
- void MSVCToolChain::AddSystemIncludeWithSubfolder(
- const ArgList &DriverArgs, ArgStringList &CC1Args,
- const std::string &folder, const Twine &subfolder1, const Twine &subfolder2,
- const Twine &subfolder3) const {
- llvm::SmallString<128> path(folder);
- llvm::sys::path::append(path, subfolder1, subfolder2, subfolder3);
- addSystemInclude(DriverArgs, CC1Args, path);
- }
- void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdinc))
- return;
- if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
- AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, getDriver().ResourceDir,
- "include");
- }
- // Add %INCLUDE%-like directories from the -imsvc flag.
- for (const auto &Path : DriverArgs.getAllArgValues(options::OPT__SLASH_imsvc))
- addSystemInclude(DriverArgs, CC1Args, Path);
- auto AddSystemIncludesFromEnv = [&](StringRef Var) -> bool {
- if (auto Val = llvm::sys::Process::GetEnv(Var)) {
- SmallVector<StringRef, 8> Dirs;
- StringRef(*Val).split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
- if (!Dirs.empty()) {
- addSystemIncludes(DriverArgs, CC1Args, Dirs);
- return true;
- }
- }
- return false;
- };
- // Add %INCLUDE%-like dirs via /external:env: flags.
- for (const auto &Var :
- DriverArgs.getAllArgValues(options::OPT__SLASH_external_env)) {
- AddSystemIncludesFromEnv(Var);
- }
- // Add DIA SDK include if requested.
- if (const Arg *A = DriverArgs.getLastArg(options::OPT__SLASH_diasdkdir,
- options::OPT__SLASH_winsysroot)) {
- // cl.exe doesn't find the DIA SDK automatically, so this too requires
- // explicit flags and doesn't automatically look in "DIA SDK" relative
- // to the path we found for VCToolChainPath.
- llvm::SmallString<128> DIASDKPath(A->getValue());
- if (A->getOption().getID() == options::OPT__SLASH_winsysroot)
- llvm::sys::path::append(DIASDKPath, "DIA SDK");
- AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, std::string(DIASDKPath),
- "include");
- }
- if (DriverArgs.hasArg(options::OPT_nostdlibinc))
- return;
- // Honor %INCLUDE% and %EXTERNAL_INCLUDE%. It should have essential search
- // paths set by vcvarsall.bat. Skip if the user expressly set a vctoolsdir.
- if (!DriverArgs.getLastArg(options::OPT__SLASH_vctoolsdir,
- options::OPT__SLASH_winsysroot)) {
- bool Found = AddSystemIncludesFromEnv("INCLUDE");
- Found |= AddSystemIncludesFromEnv("EXTERNAL_INCLUDE");
- if (Found)
- return;
- }
- // When built with access to the proper Windows APIs, try to actually find
- // the correct include paths first.
- if (!VCToolChainPath.empty()) {
- addSystemInclude(DriverArgs, CC1Args,
- getSubDirectoryPath(SubDirectoryType::Include));
- addSystemInclude(DriverArgs, CC1Args,
- getSubDirectoryPath(SubDirectoryType::Include, "atlmfc"));
- if (useUniversalCRT()) {
- std::string UniversalCRTSdkPath;
- std::string UCRTVersion;
- if (getUniversalCRTSdkDir(getVFS(), DriverArgs, UniversalCRTSdkPath,
- UCRTVersion)) {
- AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath,
- "Include", UCRTVersion, "ucrt");
- }
- }
- std::string WindowsSDKDir;
- int major = 0;
- std::string windowsSDKIncludeVersion;
- std::string windowsSDKLibVersion;
- if (getWindowsSDKDir(getVFS(), DriverArgs, WindowsSDKDir, major,
- windowsSDKIncludeVersion, windowsSDKLibVersion)) {
- if (major >= 8) {
- // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10.
- // Anyway, llvm::sys::path::append is able to manage it.
- AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
- "Include", windowsSDKIncludeVersion,
- "shared");
- AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
- "Include", windowsSDKIncludeVersion,
- "um");
- AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
- "Include", windowsSDKIncludeVersion,
- "winrt");
- if (major >= 10) {
- llvm::VersionTuple Tuple;
- if (!Tuple.tryParse(windowsSDKIncludeVersion) &&
- Tuple.getSubminor().getValueOr(0) >= 17134) {
- AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
- "Include", windowsSDKIncludeVersion,
- "cppwinrt");
- }
- }
- } else {
- AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
- "Include");
- }
- }
- return;
- }
- #if defined(_WIN32)
- // As a fallback, select default install paths.
- // FIXME: Don't guess drives and paths like this on Windows.
- const StringRef Paths[] = {
- "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
- "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
- "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
- "C:/Program Files/Microsoft Visual Studio 8/VC/include",
- "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
- };
- addSystemIncludes(DriverArgs, CC1Args, Paths);
- #endif
- }
- void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- // FIXME: There should probably be logic here to find libc++ on Windows.
- }
- VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D,
- const ArgList &Args) const {
- bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment();
- VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args);
- if (MSVT.empty())
- MSVT = getTriple().getEnvironmentVersion();
- if (MSVT.empty() && IsWindowsMSVC)
- MSVT = getMSVCVersionFromExe(getSubDirectoryPath(SubDirectoryType::Bin));
- if (MSVT.empty() &&
- Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
- IsWindowsMSVC)) {
- // -fms-compatibility-version=19.20 is default, aka 2019, 16.x
- MSVT = VersionTuple(19, 20);
- }
- return MSVT;
- }
- std::string
- MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
- types::ID InputType) const {
- // The MSVC version doesn't care about the architecture, even though it
- // may look at the triple internally.
- VersionTuple MSVT = computeMSVCVersion(/*D=*/nullptr, Args);
- MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().getValueOr(0),
- MSVT.getSubminor().getValueOr(0));
- // For the rest of the triple, however, a computed architecture name may
- // be needed.
- llvm::Triple Triple(ToolChain::ComputeEffectiveClangTriple(Args, InputType));
- if (Triple.getEnvironment() == llvm::Triple::MSVC) {
- StringRef ObjFmt = Triple.getEnvironmentName().split('-').second;
- if (ObjFmt.empty())
- Triple.setEnvironmentName((Twine("msvc") + MSVT.getAsString()).str());
- else
- Triple.setEnvironmentName(
- (Twine("msvc") + MSVT.getAsString() + Twine('-') + ObjFmt).str());
- }
- return Triple.getTriple();
- }
- SanitizerMask MSVCToolChain::getSupportedSanitizers() const {
- SanitizerMask Res = ToolChain::getSupportedSanitizers();
- Res |= SanitizerKind::Address;
- Res |= SanitizerKind::PointerCompare;
- Res |= SanitizerKind::PointerSubtract;
- Res |= SanitizerKind::Fuzzer;
- Res |= SanitizerKind::FuzzerNoLink;
- Res &= ~SanitizerKind::CFIMFCall;
- return Res;
- }
- static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL,
- bool SupportsForcingFramePointer,
- const char *ExpandChar, const OptTable &Opts) {
- assert(A->getOption().matches(options::OPT__SLASH_O));
- StringRef OptStr = A->getValue();
- for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
- const char &OptChar = *(OptStr.data() + I);
- switch (OptChar) {
- default:
- break;
- case '1':
- case '2':
- case 'x':
- case 'd':
- // Ignore /O[12xd] flags that aren't the last one on the command line.
- // Only the last one gets expanded.
- if (&OptChar != ExpandChar) {
- A->claim();
- break;
- }
- if (OptChar == 'd') {
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0));
- } else {
- if (OptChar == '1') {
- DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
- } else if (OptChar == '2' || OptChar == 'x') {
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
- DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
- }
- if (SupportsForcingFramePointer &&
- !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer))
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer));
- if (OptChar == '1' || OptChar == '2')
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections));
- }
- break;
- case 'b':
- if (I + 1 != E && isdigit(OptStr[I + 1])) {
- switch (OptStr[I + 1]) {
- case '0':
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline));
- break;
- case '1':
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions));
- break;
- case '2':
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions));
- break;
- }
- ++I;
- }
- break;
- case 'g':
- A->claim();
- break;
- case 'i':
- if (I + 1 != E && OptStr[I + 1] == '-') {
- ++I;
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin));
- } else {
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
- }
- break;
- case 's':
- DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
- break;
- case 't':
- DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
- break;
- case 'y': {
- bool OmitFramePointer = true;
- if (I + 1 != E && OptStr[I + 1] == '-') {
- OmitFramePointer = false;
- ++I;
- }
- if (SupportsForcingFramePointer) {
- if (OmitFramePointer)
- DAL.AddFlagArg(A,
- Opts.getOption(options::OPT_fomit_frame_pointer));
- else
- DAL.AddFlagArg(
- A, Opts.getOption(options::OPT_fno_omit_frame_pointer));
- } else {
- // Don't warn about /Oy- in x86-64 builds (where
- // SupportsForcingFramePointer is false). The flag having no effect
- // there is a compiler-internal optimization, and people shouldn't have
- // to special-case their build files for x86-64 clang-cl.
- A->claim();
- }
- break;
- }
- }
- }
- }
- static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL,
- const OptTable &Opts) {
- assert(A->getOption().matches(options::OPT_D));
- StringRef Val = A->getValue();
- size_t Hash = Val.find('#');
- if (Hash == StringRef::npos || Hash > Val.find('=')) {
- DAL.append(A);
- return;
- }
- std::string NewVal = std::string(Val);
- NewVal[Hash] = '=';
- DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal);
- }
- static void TranslatePermissive(Arg *A, llvm::opt::DerivedArgList &DAL,
- const OptTable &Opts) {
- DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase_));
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_operator_names));
- }
- static void TranslatePermissiveMinus(Arg *A, llvm::opt::DerivedArgList &DAL,
- const OptTable &Opts) {
- DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase));
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_foperator_names));
- }
- llvm::opt::DerivedArgList *
- MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
- StringRef BoundArch,
- Action::OffloadKind OFK) const {
- DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
- const OptTable &Opts = getDriver().getOpts();
- // /Oy and /Oy- don't have an effect on X86-64
- bool SupportsForcingFramePointer = getArch() != llvm::Triple::x86_64;
- // The -O[12xd] flag actually expands to several flags. We must desugar the
- // flags so that options embedded can be negated. For example, the '-O2' flag
- // enables '-Oy'. Expanding '-O2' into its constituent flags allows us to
- // correctly handle '-O2 -Oy-' where the trailing '-Oy-' disables a single
- // aspect of '-O2'.
- //
- // Note that this expansion logic only applies to the *last* of '[12xd]'.
- // First step is to search for the character we'd like to expand.
- const char *ExpandChar = nullptr;
- for (Arg *A : Args.filtered(options::OPT__SLASH_O)) {
- StringRef OptStr = A->getValue();
- for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
- char OptChar = OptStr[I];
- char PrevChar = I > 0 ? OptStr[I - 1] : '0';
- if (PrevChar == 'b') {
- // OptChar does not expand; it's an argument to the previous char.
- continue;
- }
- if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd')
- ExpandChar = OptStr.data() + I;
- }
- }
- for (Arg *A : Args) {
- if (A->getOption().matches(options::OPT__SLASH_O)) {
- // The -O flag actually takes an amalgam of other options. For example,
- // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'.
- TranslateOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, Opts);
- } else if (A->getOption().matches(options::OPT_D)) {
- // Translate -Dfoo#bar into -Dfoo=bar.
- TranslateDArg(A, *DAL, Opts);
- } else if (A->getOption().matches(options::OPT__SLASH_permissive)) {
- // Expand /permissive
- TranslatePermissive(A, *DAL, Opts);
- } else if (A->getOption().matches(options::OPT__SLASH_permissive_)) {
- // Expand /permissive-
- TranslatePermissiveMinus(A, *DAL, Opts);
- } else if (OFK != Action::OFK_HIP) {
- // HIP Toolchain translates input args by itself.
- DAL->append(A);
- }
- }
- return DAL;
- }
- void MSVCToolChain::addClangTargetOptions(
- const ArgList &DriverArgs, ArgStringList &CC1Args,
- Action::OffloadKind DeviceOffloadKind) const {
- // MSVC STL kindly allows removing all usages of typeid by defining
- // _HAS_STATIC_RTTI to 0. Do so, when compiling with -fno-rtti
- if (DriverArgs.hasArg(options::OPT_fno_rtti, options::OPT_frtti,
- /*Default=*/false))
- CC1Args.push_back("-D_HAS_STATIC_RTTI=0");
- }
|