123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991 |
- //===-- 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/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
- using namespace clang::driver;
- using namespace clang::driver::toolchains;
- using namespace clang::driver::tools;
- using namespace clang;
- using namespace llvm::opt;
- 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;
- }
- // 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(llvm::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() && !C.getDriver().IsFlangMode()) {
- 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",
- llvm::archToLegacyVCArch(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(llvm::SubDirectoryType::Lib)));
- CmdArgs.push_back(Args.MakeArgString(
- Twine("-libpath:") +
- TC.getSubDirectoryPath(llvm::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));
- }
- if (C.getDriver().IsFlangMode()) {
- addFortranRuntimeLibraryPath(TC, Args, CmdArgs);
- addFortranRuntimeLibs(TC, CmdArgs);
- // Inform the MSVC linker that we're generating a console application, i.e.
- // one with `main` as the "user-defined" entry point. The `main` function is
- // defined in flang's runtime libraries.
- CmdArgs.push_back("/subsystem:console");
- }
- // 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);
- }
- addHIPRuntimeLibArgs(TC, 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 llvm::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=")) {
- constexpr size_t PrefixLen = 5; // strlen("path=")
- Environment.push_back(Args.MakeArgString(
- EnvVar.substr(0, PrefixLen) +
- TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin) +
- llvm::Twine(llvm::sys::EnvPathSeparator) +
- TC.getSubDirectoryPath(llvm::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);
- std::optional<llvm::StringRef> VCToolsDir, VCToolsVersion;
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir))
- VCToolsDir = A->getValue();
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion))
- VCToolsVersion = A->getValue();
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir))
- WinSdkDir = A->getValue();
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion))
- WinSdkVersion = A->getValue();
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsysroot))
- WinSysRoot = A->getValue();
- // Check the command line first, that's the user explicitly telling us what to
- // use. Check the environment next, in case we're being invoked from a VS
- // command prompt. Failing that, just try to find the newest Visual Studio
- // version we can and use its default VC toolchain.
- llvm::findVCToolChainViaCommandLine(getVFS(), VCToolsDir, VCToolsVersion,
- WinSysRoot, VCToolChainPath, VSLayout) ||
- llvm::findVCToolChainViaEnvironment(getVFS(), VCToolChainPath,
- VSLayout) ||
- llvm::findVCToolChainViaSetupConfig(getVFS(), VCToolChainPath,
- VSLayout) ||
- llvm::findVCToolChainViaRegistry(VCToolChainPath, VSLayout);
- }
- 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;
- }
- ToolChain::UnwindTableLevel
- MSVCToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const {
- // Don't emit unwind tables by default for MachO targets.
- if (getTriple().isOSBinFormatMachO())
- return UnwindTableLevel::None;
- // 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.
- if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm ||
- getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64)
- return UnwindTableLevel::Asynchronous;
- return UnwindTableLevel::None;
- }
- 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::AddHIPRuntimeLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- CmdArgs.append({Args.MakeArgString(StringRef("-libpath:") +
- RocmInstallation.getLibPath()),
- "amdhip64.lib"});
- }
- void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const {
- CudaInstallation.print(OS);
- RocmInstallation.print(OS);
- }
- std::string
- MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type,
- llvm::StringRef SubdirParent) const {
- return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, getArch(),
- SubdirParent);
- }
- std::string
- MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type,
- llvm::Triple::ArchType TargetArch) const {
- return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, TargetArch,
- "");
- }
- // 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.
- // 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 (!llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot,
- sdkPath, sdkMajor, windowsSDKIncludeVersion,
- windowsSDKLibVersion))
- return false;
- llvm::SmallString<128> libPath(sdkPath);
- llvm::sys::path::append(libPath, "Lib");
- if (sdkMajor >= 8)
- llvm::sys::path::append(libPath, windowsSDKLibVersion, "um");
- return llvm::appendArchToWindowsSDKLibPath(sdkMajor, libPath, getArch(),
- path);
- }
- bool MSVCToolChain::useUniversalCRT() const {
- return llvm::useUniversalCRT(VSLayout, VCToolChainPath, getArch(), getVFS());
- }
- bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args,
- std::string &Path) const {
- std::string UniversalCRTSdkPath;
- std::string UCRTVersion;
- Path.clear();
- if (!llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion,
- WinSysRoot, UniversalCRTSdkPath,
- UCRTVersion))
- return false;
- StringRef ArchName = llvm::archToWindowsSDKArch(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(llvm::SubDirectoryType::Include));
- addSystemInclude(
- DriverArgs, CC1Args,
- getSubDirectoryPath(llvm::SubDirectoryType::Include, "atlmfc"));
- if (useUniversalCRT()) {
- std::string UniversalCRTSdkPath;
- std::string UCRTVersion;
- if (llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion,
- WinSysRoot, UniversalCRTSdkPath,
- UCRTVersion)) {
- AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath,
- "Include", UCRTVersion, "ucrt");
- }
- }
- std::string WindowsSDKDir;
- int major = 0;
- std::string windowsSDKIncludeVersion;
- std::string windowsSDKLibVersion;
- if (llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot,
- 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().value_or(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(llvm::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().value_or(0),
- MSVT.getSubminor().value_or(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.hasFlag(options::OPT_fno_rtti, options::OPT_frtti,
- /*Default=*/false))
- CC1Args.push_back("-D_HAS_STATIC_RTTI=0");
- }
|