brintos

brintos / llvm-project-archived public Read only

0
0
Text · 40.4 KiB · fcae5b7 Raw
1043 lines · cpp
1//===-- MSVC.cpp - MSVC ToolChain Implementations -------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "MSVC.h"10#include "Darwin.h"11#include "clang/Config/config.h"12#include "clang/Driver/CommonArgs.h"13#include "clang/Driver/Compilation.h"14#include "clang/Driver/Driver.h"15#include "clang/Driver/SanitizerArgs.h"16#include "clang/Options/Options.h"17#include "llvm/Option/Arg.h"18#include "llvm/Option/ArgList.h"19#include "llvm/Support/ConvertUTF.h"20#include "llvm/Support/ErrorHandling.h"21#include "llvm/Support/FileSystem.h"22#include "llvm/Support/Path.h"23#include "llvm/Support/Process.h"24#include "llvm/Support/VirtualFileSystem.h"25#include "llvm/TargetParser/Host.h"26#include <cstdio>27 28#ifdef _WIN3229  #define WIN32_LEAN_AND_MEAN30  #define NOGDI31  #ifndef NOMINMAX32    #define NOMINMAX33  #endif34  #include <windows.h>35#endif36 37using namespace clang::driver;38using namespace clang::driver::toolchains;39using namespace clang::driver::tools;40using namespace clang;41using namespace llvm::opt;42 43static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) {44  auto Status = VFS.status(Path);45  if (!Status)46    return false;47  return (Status->getPermissions() & llvm::sys::fs::perms::all_exe) != 0;48}49 50// Try to find Exe from a Visual Studio distribution.  This first tries to find51// an installed copy of Visual Studio and, failing that, looks in the PATH,52// making sure that whatever executable that's found is not a same-named exe53// from clang itself to prevent clang from falling back to itself.54static std::string FindVisualStudioExecutable(const ToolChain &TC,55                                              const char *Exe) {56  const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);57  SmallString<128> FilePath(58      MSVC.getSubDirectoryPath(llvm::SubDirectoryType::Bin));59  llvm::sys::path::append(FilePath, Exe);60  return std::string(canExecute(TC.getVFS(), FilePath) ? FilePath.str() : Exe);61}62 63void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,64                                        const InputInfo &Output,65                                        const InputInfoList &Inputs,66                                        const ArgList &Args,67                                        const char *LinkingOutput) const {68  ArgStringList CmdArgs;69 70  auto &TC = static_cast<const toolchains::MSVCToolChain &>(getToolChain());71 72  assert((Output.isFilename() || Output.isNothing()) && "invalid output");73  if (Output.isFilename())74    CmdArgs.push_back(75        Args.MakeArgString(std::string("-out:") + Output.getFilename()));76 77  if (Args.hasArg(options::OPT_marm64x))78    CmdArgs.push_back("-machine:arm64x");79  else if (TC.getTriple().isWindowsArm64EC())80    CmdArgs.push_back("-machine:arm64ec");81 82  if (const Arg *A = Args.getLastArg(options::OPT_fveclib)) {83    StringRef V = A->getValue();84    if (V == "ArmPL")85      CmdArgs.push_back(Args.MakeArgString("--dependent-lib=amath"));86  }87 88  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) &&89      !C.getDriver().IsCLMode() && !C.getDriver().IsFlangMode()) {90    CmdArgs.push_back("-defaultlib:libcmt");91    CmdArgs.push_back("-defaultlib:oldnames");92  }93 94  // If the VC environment hasn't been configured (perhaps because the user95  // did not run vcvarsall), try to build a consistent link environment.  If96  // the environment variable is set however, assume the user knows what97  // they're doing. If the user passes /vctoolsdir or /winsdkdir, trust that98  // over env vars.99  if (const Arg *A = Args.getLastArg(options::OPT__SLASH_diasdkdir,100                                     options::OPT__SLASH_winsysroot)) {101    // cl.exe doesn't find the DIA SDK automatically, so this too requires102    // explicit flags and doesn't automatically look in "DIA SDK" relative103    // to the path we found for VCToolChainPath.104    llvm::SmallString<128> DIAPath(A->getValue());105    if (A->getOption().getID() == options::OPT__SLASH_winsysroot)106      llvm::sys::path::append(DIAPath, "DIA SDK");107 108    // The DIA SDK always uses the legacy vc arch, even in new MSVC versions.109    llvm::sys::path::append(DIAPath, "lib",110                            llvm::archToLegacyVCArch(TC.getArch()));111    CmdArgs.push_back(Args.MakeArgString(Twine("-libpath:") + DIAPath));112  }113  if (!llvm::sys::Process::GetEnv("LIB") ||114      Args.hasArg(options::OPT__SLASH_vctoolsdir,115                  options::OPT__SLASH_vctoolsversion,116                  options::OPT__SLASH_winsysroot)) {117    CmdArgs.push_back(Args.MakeArgString(118        Twine("-libpath:") +119        TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib)));120    CmdArgs.push_back(Args.MakeArgString(121        Twine("-libpath:") +122        TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib, "atlmfc")));123  }124  if (!llvm::sys::Process::GetEnv("LIB") ||125      Args.hasArg(options::OPT__SLASH_winsdkdir,126                  options::OPT__SLASH_winsdkversion,127                  options::OPT__SLASH_winsysroot)) {128    if (TC.useUniversalCRT()) {129      std::string UniversalCRTLibPath;130      if (TC.getUniversalCRTLibraryPath(Args, UniversalCRTLibPath))131        CmdArgs.push_back(132            Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath));133    }134    std::string WindowsSdkLibPath;135    if (TC.getWindowsSDKLibraryPath(Args, WindowsSdkLibPath))136      CmdArgs.push_back(137          Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));138  }139 140  if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L))141    for (const auto &LibPath : Args.getAllArgValues(options::OPT_L))142      CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));143 144  if (C.getDriver().IsFlangMode() &&145      !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {146    TC.addFortranRuntimeLibraryPath(Args, CmdArgs);147    TC.addFortranRuntimeLibs(Args, CmdArgs);148 149    // Inform the MSVC linker that we're generating a console application, i.e.150    // one with `main` as the "user-defined" entry point. The `main` function is151    // defined in flang's runtime libraries.152    CmdArgs.push_back("/subsystem:console");153  }154 155  // Add the compiler-rt library directories to libpath if they exist to help156  // the linker find the various sanitizer, builtin, and profiling runtimes.157  for (const auto &LibPath : TC.getLibraryPaths()) {158    if (TC.getVFS().exists(LibPath))159      CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));160  }161  auto CRTPath = TC.getCompilerRTPath();162  if (TC.getVFS().exists(CRTPath))163    CmdArgs.push_back(Args.MakeArgString("-libpath:" + CRTPath));164 165  CmdArgs.push_back("-nologo");166 167  if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7))168    CmdArgs.push_back("-debug");169 170  // If we specify /hotpatch, let the linker add padding in front of each171  // function, like MSVC does.172  if (Args.hasArg(options::OPT_fms_hotpatch, options::OPT__SLASH_hotpatch))173    CmdArgs.push_back("-functionpadmin");174 175  // Pass on /Brepro if it was passed to the compiler.176  // Note that /Brepro maps to -mno-incremental-linker-compatible.177  bool DefaultIncrementalLinkerCompatible =178      C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment();179  if (!Args.hasFlag(options::OPT_mincremental_linker_compatible,180                    options::OPT_mno_incremental_linker_compatible,181                    DefaultIncrementalLinkerCompatible))182    CmdArgs.push_back("-Brepro");183 184  bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd,185                         options::OPT_shared);186  if (DLL) {187    CmdArgs.push_back(Args.MakeArgString("-dll"));188 189    SmallString<128> ImplibName(Output.getFilename());190    llvm::sys::path::replace_extension(ImplibName, "lib");191    CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName));192  }193 194  if (TC.getSanitizerArgs(Args).needsFuzzer()) {195    if (!Args.hasArg(options::OPT_shared))196      CmdArgs.push_back(197          Args.MakeArgString(std::string("-wholearchive:") +198                             TC.getCompilerRTArgString(Args, "fuzzer")));199    CmdArgs.push_back(Args.MakeArgString("-debug"));200    // Prevent the linker from padding sections we use for instrumentation201    // arrays.202    CmdArgs.push_back(Args.MakeArgString("-incremental:no"));203  }204 205  if (TC.getSanitizerArgs(Args).needsAsanRt()) {206    CmdArgs.push_back(Args.MakeArgString("-debug"));207    CmdArgs.push_back(Args.MakeArgString("-incremental:no"));208    CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dynamic"));209    auto defines = Args.getAllArgValues(options::OPT_D);210    if (Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd) ||211        llvm::is_contained(defines, "_DLL")) {212      // Make sure the dynamic runtime thunk is not optimized out at link time213      // to ensure proper SEH handling.214      CmdArgs.push_back(Args.MakeArgString(215          TC.getArch() == llvm::Triple::x86216              ? "-include:___asan_seh_interceptor"217              : "-include:__asan_seh_interceptor"));218      // Make sure the linker consider all object files from the dynamic runtime219      // thunk.220      CmdArgs.push_back(Args.MakeArgString(221          std::string("-wholearchive:") +222          TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk")));223    } else {224      // Make sure the linker consider all object files from the static runtime225      // thunk.226      CmdArgs.push_back(Args.MakeArgString(227          std::string("-wholearchive:") +228          TC.getCompilerRT(Args, "asan_static_runtime_thunk")));229    }230  }231 232  if (C.getDriver().isUsingLTO()) {233    if (Arg *A = tools::getLastProfileSampleUseArg(Args))234      CmdArgs.push_back(Args.MakeArgString(std::string("-lto-sample-profile:") +235                                           A->getValue()));236  }237  Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);238 239  // Control Flow Guard checks240  for (const Arg *A : Args.filtered(options::OPT__SLASH_guard)) {241    StringRef GuardArgs = A->getValue();242    if (GuardArgs.equals_insensitive("cf") ||243        GuardArgs.equals_insensitive("cf,nochecks")) {244      // MSVC doesn't yet support the "nochecks" modifier.245      CmdArgs.push_back("-guard:cf");246    } else if (GuardArgs.equals_insensitive("cf-")) {247      CmdArgs.push_back("-guard:cf-");248    } else if (GuardArgs.equals_insensitive("ehcont")) {249      CmdArgs.push_back("-guard:ehcont");250    } else if (GuardArgs.equals_insensitive("ehcont-")) {251      CmdArgs.push_back("-guard:ehcont-");252    }253  }254 255  if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,256                   options::OPT_fno_openmp, false)) {257    CmdArgs.push_back("-nodefaultlib:vcomp.lib");258    CmdArgs.push_back("-nodefaultlib:vcompd.lib");259    CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") +260                                         TC.getDriver().Dir + "/../lib"));261    switch (TC.getDriver().getOpenMPRuntime(Args)) {262    case Driver::OMPRT_OMP:263      CmdArgs.push_back("-defaultlib:libomp.lib");264      break;265    case Driver::OMPRT_IOMP5:266      CmdArgs.push_back("-defaultlib:libiomp5md.lib");267      break;268    case Driver::OMPRT_GOMP:269      break;270    case Driver::OMPRT_Unknown:271      // Already diagnosed.272      break;273    }274  }275 276  // Add compiler-rt lib in case if it was explicitly277  // specified as an argument for --rtlib option.278  if (!Args.hasArg(options::OPT_nostdlib)) {279    AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args);280  }281 282  StringRef Linker = Args.getLastArgValue(options::OPT_fuse_ld_EQ,283                                          TC.getDriver().getPreferredLinker());284  if (Linker.empty())285    Linker = "link";286  // We need to translate 'lld' into 'lld-link'.287  else if (Linker.equals_insensitive("lld"))288    Linker = "lld-link";289 290  if (Linker == "lld-link") {291    for (Arg *A : Args.filtered(options::OPT_vfsoverlay))292      CmdArgs.push_back(293          Args.MakeArgString(std::string("/vfsoverlay:") + A->getValue()));294 295    if (C.getDriver().isUsingLTO() &&296        Args.hasFlag(options::OPT_gsplit_dwarf, options::OPT_gno_split_dwarf,297                     false))298      CmdArgs.push_back(Args.MakeArgString(Twine("/dwodir:") +299                                           Output.getFilename() + "_dwo"));300  }301 302  // Add filenames, libraries, and other linker inputs.303  for (const auto &Input : Inputs) {304    if (Input.isFilename()) {305      CmdArgs.push_back(Input.getFilename());306      continue;307    }308 309    const Arg &A = Input.getInputArg();310 311    // Render -l options differently for the MSVC linker.312    if (A.getOption().matches(options::OPT_l)) {313      StringRef Lib = A.getValue();314      const char *LinkLibArg;315      if (Lib.ends_with(".lib"))316        LinkLibArg = Args.MakeArgString(Lib);317      else318        LinkLibArg = Args.MakeArgString(Lib + ".lib");319      CmdArgs.push_back(LinkLibArg);320      continue;321    }322 323    // Otherwise, this is some other kind of linker input option like -Wl, -z,324    // or -L. Render it, even if MSVC doesn't understand it.325    A.renderAsInput(Args, CmdArgs);326  }327 328  addHIPRuntimeLibArgs(TC, C, Args, CmdArgs);329 330  TC.addProfileRTLibs(Args, CmdArgs);331 332  std::vector<const char *> Environment;333 334  // We need to special case some linker paths. In the case of the regular msvc335  // linker, we need to use a special search algorithm.336  llvm::SmallString<128> linkPath;337  if (Linker.equals_insensitive("link")) {338    // If we're using the MSVC linker, it's not sufficient to just use link339    // from the program PATH, because other environments like GnuWin32 install340    // their own link.exe which may come first.341    linkPath = FindVisualStudioExecutable(TC, "link.exe");342 343    if (!TC.FoundMSVCInstall() && !canExecute(TC.getVFS(), linkPath)) {344      llvm::SmallString<128> ClPath;345      ClPath = TC.GetProgramPath("cl.exe");346      if (canExecute(TC.getVFS(), ClPath)) {347        linkPath = llvm::sys::path::parent_path(ClPath);348        llvm::sys::path::append(linkPath, "link.exe");349        if (!canExecute(TC.getVFS(), linkPath))350          C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found);351      } else {352        C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found);353      }354    }355 356    // Clang handles passing the proper asan libs to the linker, which goes357    // against link.exe's /INFERASANLIBS which automatically finds asan libs.358    if (TC.getSanitizerArgs(Args).needsAsanRt())359      CmdArgs.push_back("/INFERASANLIBS:NO");360 361#ifdef _WIN32362    // When cross-compiling with VS2017 or newer, link.exe expects to have363    // its containing bin directory at the top of PATH, followed by the364    // native target bin directory.365    // e.g. when compiling for x86 on an x64 host, PATH should start with:366    // /bin/Hostx64/x86;/bin/Hostx64/x64367    // This doesn't attempt to handle llvm::ToolsetLayout::DevDivInternal.368    if (TC.getIsVS2017OrNewer() &&369        llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) {370      auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch();371 372      auto EnvBlockWide =373          std::unique_ptr<wchar_t[], decltype(&FreeEnvironmentStringsW)>(374              GetEnvironmentStringsW(), FreeEnvironmentStringsW);375      if (!EnvBlockWide)376        goto SkipSettingEnvironment;377 378      size_t EnvCount = 0;379      size_t EnvBlockLen = 0;380      while (EnvBlockWide[EnvBlockLen] != L'\0') {381        ++EnvCount;382        EnvBlockLen += std::wcslen(&EnvBlockWide[EnvBlockLen]) +383                       1 /*string null-terminator*/;384      }385      ++EnvBlockLen; // add the block null-terminator386 387      std::string EnvBlock;388      if (!llvm::convertUTF16ToUTF8String(389              llvm::ArrayRef<char>(reinterpret_cast<char *>(EnvBlockWide.get()),390                                   EnvBlockLen * sizeof(EnvBlockWide[0])),391              EnvBlock))392        goto SkipSettingEnvironment;393 394      Environment.reserve(EnvCount);395 396      // Now loop over each string in the block and copy them into the397      // environment vector, adjusting the PATH variable as needed when we398      // find it.399      for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) {400        llvm::StringRef EnvVar(Cursor);401        if (EnvVar.starts_with_insensitive("path=")) {402          constexpr size_t PrefixLen = 5; // strlen("path=")403          Environment.push_back(Args.MakeArgString(404              EnvVar.substr(0, PrefixLen) +405              TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin) +406              llvm::Twine(llvm::sys::EnvPathSeparator) +407              TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin, HostArch) +408              (EnvVar.size() > PrefixLen409                   ? llvm::Twine(llvm::sys::EnvPathSeparator) +410                         EnvVar.substr(PrefixLen)411                   : "")));412        } else {413          Environment.push_back(Args.MakeArgString(EnvVar));414        }415        Cursor += EnvVar.size() + 1 /*null-terminator*/;416      }417    }418  SkipSettingEnvironment:;419#endif420  } else {421    linkPath = TC.GetProgramPath(Linker.str().c_str());422  }423 424  auto LinkCmd = std::make_unique<Command>(425      JA, *this, ResponseFileSupport::AtFileUTF16(),426      Args.MakeArgString(linkPath), CmdArgs, Inputs, Output);427  if (!Environment.empty())428    LinkCmd->setEnvironment(Environment);429  C.addCommand(std::move(LinkCmd));430}431 432MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,433                             const ArgList &Args)434    : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args),435      RocmInstallation(D, Triple, Args), SYCLInstallation(D, Triple, Args) {436  getProgramPaths().push_back(getDriver().Dir);437 438  std::optional<llvm::StringRef> VCToolsDir, VCToolsVersion;439  if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir))440    VCToolsDir = A->getValue();441  if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion))442    VCToolsVersion = A->getValue();443  if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir))444    WinSdkDir = A->getValue();445  if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion))446    WinSdkVersion = A->getValue();447  if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsysroot))448    WinSysRoot = A->getValue();449 450  // Check the command line first, that's the user explicitly telling us what to451  // use. Check the environment next, in case we're being invoked from a VS452  // command prompt. Failing that, just try to find the newest Visual Studio453  // version we can and use its default VC toolchain.454  llvm::findVCToolChainViaCommandLine(getVFS(), VCToolsDir, VCToolsVersion,455                                      WinSysRoot, VCToolChainPath, VSLayout) ||456      llvm::findVCToolChainViaEnvironment(getVFS(), VCToolChainPath,457                                          VSLayout) ||458      llvm::findVCToolChainViaSetupConfig(getVFS(), VCToolsVersion,459                                          VCToolChainPath, VSLayout) ||460      llvm::findVCToolChainViaRegistry(VCToolChainPath, VSLayout);461}462 463Tool *MSVCToolChain::buildLinker() const {464  return new tools::visualstudio::Linker(*this);465}466 467Tool *MSVCToolChain::buildAssembler() const {468  if (getTriple().isOSBinFormatMachO())469    return new tools::darwin::Assembler(*this);470  getDriver().Diag(clang::diag::err_no_external_assembler);471  return nullptr;472}473 474ToolChain::UnwindTableLevel475MSVCToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const {476  // Don't emit unwind tables by default for MachO targets.477  if (getTriple().isOSBinFormatMachO())478    return UnwindTableLevel::None;479 480  // All non-x86_32 Windows targets require unwind tables. However, LLVM481  // doesn't know how to generate them for all targets, so only enable482  // the ones that are actually implemented.483  if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm ||484      getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64)485    return UnwindTableLevel::Asynchronous;486 487  return UnwindTableLevel::None;488}489 490bool MSVCToolChain::isPICDefault() const {491  return getArch() == llvm::Triple::x86_64 ||492         getArch() == llvm::Triple::aarch64;493}494 495bool MSVCToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const {496  return false;497}498 499bool MSVCToolChain::isPICDefaultForced() const {500  return getArch() == llvm::Triple::x86_64 ||501         getArch() == llvm::Triple::aarch64;502}503 504void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,505                                       ArgStringList &CC1Args) const {506  CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args);507}508 509void MSVCToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,510                                      ArgStringList &CC1Args) const {511  RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args);512}513 514void MSVCToolChain::addSYCLIncludeArgs(const ArgList &DriverArgs,515                                       ArgStringList &CC1Args) const {516  SYCLInstallation->addSYCLIncludeArgs(DriverArgs, CC1Args);517}518 519void MSVCToolChain::AddHIPRuntimeLibArgs(const ArgList &Args,520                                         ArgStringList &CmdArgs) const {521  CmdArgs.append({Args.MakeArgString(StringRef("-libpath:") +522                                     RocmInstallation->getLibPath()),523                  "amdhip64.lib"});524}525 526void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const {527  CudaInstallation->print(OS);528  RocmInstallation->print(OS);529}530 531std::string532MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type,533                                   llvm::StringRef SubdirParent) const {534  return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, getArch(),535                                   SubdirParent);536}537 538std::string539MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type,540                                   llvm::Triple::ArchType TargetArch) const {541  return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, TargetArch,542                                   "");543}544 545// Find the most recent version of Universal CRT or Windows 10 SDK.546// vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include547// directory by name and uses the last one of the list.548// So we compare entry names lexicographically to find the greatest one.549// Gets the library path required to link against the Windows SDK.550bool MSVCToolChain::getWindowsSDKLibraryPath(const ArgList &Args,551                                             std::string &path) const {552  std::string sdkPath;553  int sdkMajor = 0;554  std::string windowsSDKIncludeVersion;555  std::string windowsSDKLibVersion;556 557  path.clear();558  if (!llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot,559                              sdkPath, sdkMajor, windowsSDKIncludeVersion,560                              windowsSDKLibVersion))561    return false;562 563  llvm::SmallString<128> libPath(sdkPath);564  llvm::sys::path::append(libPath, "Lib");565  if (sdkMajor >= 10)566    if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&567        WinSdkVersion.has_value())568      windowsSDKLibVersion = *WinSdkVersion;569  if (sdkMajor >= 8)570    llvm::sys::path::append(libPath, windowsSDKLibVersion, "um");571  return llvm::appendArchToWindowsSDKLibPath(sdkMajor, libPath, getArch(),572                                             path);573}574 575bool MSVCToolChain::useUniversalCRT() const {576  return llvm::useUniversalCRT(VSLayout, VCToolChainPath, getArch(), getVFS());577}578 579bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args,580                                               std::string &Path) const {581  std::string UniversalCRTSdkPath;582  std::string UCRTVersion;583 584  Path.clear();585  if (!llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion,586                                   WinSysRoot, UniversalCRTSdkPath,587                                   UCRTVersion))588    return false;589 590  if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&591      WinSdkVersion.has_value())592    UCRTVersion = *WinSdkVersion;593 594  StringRef ArchName = llvm::archToWindowsSDKArch(getArch());595  if (ArchName.empty())596    return false;597 598  llvm::SmallString<128> LibPath(UniversalCRTSdkPath);599  llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName);600 601  Path = std::string(LibPath);602  return true;603}604 605static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) {606  VersionTuple Version;607#ifdef _WIN32608  SmallString<128> ClExe(BinDir);609  llvm::sys::path::append(ClExe, "cl.exe");610 611  std::wstring ClExeWide;612  if (!llvm::ConvertUTF8toWide(ClExe.c_str(), ClExeWide))613    return Version;614 615  const DWORD VersionSize = ::GetFileVersionInfoSizeW(ClExeWide.c_str(),616                                                      nullptr);617  if (VersionSize == 0)618    return Version;619 620  SmallVector<uint8_t, 4 * 1024> VersionBlock(VersionSize);621  if (!::GetFileVersionInfoW(ClExeWide.c_str(), 0, VersionSize,622                             VersionBlock.data()))623    return Version;624 625  VS_FIXEDFILEINFO *FileInfo = nullptr;626  UINT FileInfoSize = 0;627  if (!::VerQueryValueW(VersionBlock.data(), L"\\",628                        reinterpret_cast<LPVOID *>(&FileInfo), &FileInfoSize) ||629      FileInfoSize < sizeof(*FileInfo))630    return Version;631 632  const unsigned Major = (FileInfo->dwFileVersionMS >> 16) & 0xFFFF;633  const unsigned Minor = (FileInfo->dwFileVersionMS      ) & 0xFFFF;634  const unsigned Micro = (FileInfo->dwFileVersionLS >> 16) & 0xFFFF;635 636  Version = VersionTuple(Major, Minor, Micro);637#endif638  return Version;639}640 641void MSVCToolChain::AddSystemIncludeWithSubfolder(642    const ArgList &DriverArgs, ArgStringList &CC1Args,643    const std::string &folder, const Twine &subfolder1, const Twine &subfolder2,644    const Twine &subfolder3) const {645  llvm::SmallString<128> path(folder);646  llvm::sys::path::append(path, subfolder1, subfolder2, subfolder3);647  addSystemInclude(DriverArgs, CC1Args, path);648}649 650void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,651                                              ArgStringList &CC1Args) const {652  if (DriverArgs.hasArg(options::OPT_nostdinc))653    return;654 655  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {656    AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, getDriver().ResourceDir,657                                  "include");658  }659 660  // Add %INCLUDE%-like directories from the -imsvc flag.661  for (const auto &Path : DriverArgs.getAllArgValues(options::OPT__SLASH_imsvc))662    addSystemInclude(DriverArgs, CC1Args, Path);663 664  auto AddSystemIncludesFromEnv = [&](StringRef Var) -> bool {665    if (auto Val = llvm::sys::Process::GetEnv(Var)) {666      SmallVector<StringRef, 8> Dirs;667      StringRef(*Val).split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);668      if (!Dirs.empty()) {669        addSystemIncludes(DriverArgs, CC1Args, Dirs);670        return true;671      }672    }673    return false;674  };675 676  // Add %INCLUDE%-like dirs via /external:env: flags.677  for (const auto &Var :678       DriverArgs.getAllArgValues(options::OPT__SLASH_external_env)) {679    AddSystemIncludesFromEnv(Var);680  }681 682  // Add DIA SDK include if requested.683  if (const Arg *A = DriverArgs.getLastArg(options::OPT__SLASH_diasdkdir,684                                           options::OPT__SLASH_winsysroot)) {685    // cl.exe doesn't find the DIA SDK automatically, so this too requires686    // explicit flags and doesn't automatically look in "DIA SDK" relative687    // to the path we found for VCToolChainPath.688    llvm::SmallString<128> DIASDKPath(A->getValue());689    if (A->getOption().getID() == options::OPT__SLASH_winsysroot)690      llvm::sys::path::append(DIASDKPath, "DIA SDK");691    AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, std::string(DIASDKPath),692                                  "include");693  }694 695  if (DriverArgs.hasArg(options::OPT_nostdlibinc))696    return;697 698  // Honor %INCLUDE% and %EXTERNAL_INCLUDE%. It should have essential search699  // paths set by vcvarsall.bat. Skip if the user expressly set any of the700  // Windows SDK or VC Tools options.701  if (!DriverArgs.hasArg(702          options::OPT__SLASH_vctoolsdir, options::OPT__SLASH_vctoolsversion,703          options::OPT__SLASH_winsysroot, options::OPT__SLASH_winsdkdir,704          options::OPT__SLASH_winsdkversion)) {705    bool Found = AddSystemIncludesFromEnv("INCLUDE");706    Found |= AddSystemIncludesFromEnv("EXTERNAL_INCLUDE");707    if (Found)708      return;709  }710 711  // When built with access to the proper Windows APIs, try to actually find712  // the correct include paths first.713  if (!VCToolChainPath.empty()) {714    addSystemInclude(DriverArgs, CC1Args,715                     getSubDirectoryPath(llvm::SubDirectoryType::Include));716    addSystemInclude(717        DriverArgs, CC1Args,718        getSubDirectoryPath(llvm::SubDirectoryType::Include, "atlmfc"));719 720    if (useUniversalCRT()) {721      std::string UniversalCRTSdkPath;722      std::string UCRTVersion;723      if (llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion,724                                      WinSysRoot, UniversalCRTSdkPath,725                                      UCRTVersion)) {726        if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&727            WinSdkVersion.has_value())728          UCRTVersion = *WinSdkVersion;729        AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath,730                                      "Include", UCRTVersion, "ucrt");731      }732    }733 734    std::string WindowsSDKDir;735    int major = 0;736    std::string windowsSDKIncludeVersion;737    std::string windowsSDKLibVersion;738    if (llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot,739                               WindowsSDKDir, major, windowsSDKIncludeVersion,740                               windowsSDKLibVersion)) {741      if (major >= 10)742        if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&743            WinSdkVersion.has_value())744          windowsSDKIncludeVersion = windowsSDKLibVersion = *WinSdkVersion;745      if (major >= 8) {746        // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10.747        // Anyway, llvm::sys::path::append is able to manage it.748        AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,749                                      "Include", windowsSDKIncludeVersion,750                                      "shared");751        AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,752                                      "Include", windowsSDKIncludeVersion,753                                      "um");754        AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,755                                      "Include", windowsSDKIncludeVersion,756                                      "winrt");757        if (major >= 10) {758          llvm::VersionTuple Tuple;759          if (!Tuple.tryParse(windowsSDKIncludeVersion) &&760              Tuple.getSubminor().value_or(0) >= 17134) {761            AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,762                                          "Include", windowsSDKIncludeVersion,763                                          "cppwinrt");764          }765        }766      } else {767        AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,768                                      "Include");769      }770    }771 772    return;773  }774 775#if defined(_WIN32)776  // As a fallback, select default install paths.777  // FIXME: Don't guess drives and paths like this on Windows.778  const StringRef Paths[] = {779    "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",780    "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",781    "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",782    "C:/Program Files/Microsoft Visual Studio 8/VC/include",783    "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"784  };785  addSystemIncludes(DriverArgs, CC1Args, Paths);786#endif787}788 789void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,790                                                 ArgStringList &CC1Args) const {791  // FIXME: There should probably be logic here to find libc++ on Windows.792}793 794VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D,795                                               const ArgList &Args) const {796  bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment();797  VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args);798  if (MSVT.empty())799    MSVT = getTriple().getEnvironmentVersion();800  if (MSVT.empty() && IsWindowsMSVC)801    MSVT =802        getMSVCVersionFromExe(getSubDirectoryPath(llvm::SubDirectoryType::Bin));803  if (MSVT.empty() &&804      Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,805                   IsWindowsMSVC)) {806    // -fms-compatibility-version=19.33 is default, aka 2022, 17.3807    // NOTE: when changing this value, also update808    // clang/docs/CommandGuide/clang.rst and clang/docs/UsersManual.rst809    // accordingly.810    MSVT = VersionTuple(19, 33);811  }812  return MSVT;813}814 815std::string816MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args,817                                           types::ID InputType) const {818  // The MSVC version doesn't care about the architecture, even though it819  // may look at the triple internally.820  VersionTuple MSVT = computeMSVCVersion(/*D=*/nullptr, Args);821  MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().value_or(0),822                      MSVT.getSubminor().value_or(0));823 824  // For the rest of the triple, however, a computed architecture name may825  // be needed.826  llvm::Triple Triple(ToolChain::ComputeEffectiveClangTriple(Args, InputType));827  if (Triple.getEnvironment() == llvm::Triple::MSVC) {828    StringRef ObjFmt = Triple.getEnvironmentName().split('-').second;829    if (ObjFmt.empty())830      Triple.setEnvironmentName((Twine("msvc") + MSVT.getAsString()).str());831    else832      Triple.setEnvironmentName(833          (Twine("msvc") + MSVT.getAsString() + Twine('-') + ObjFmt).str());834  }835  return Triple.getTriple();836}837 838SanitizerMask MSVCToolChain::getSupportedSanitizers() const {839  SanitizerMask Res = ToolChain::getSupportedSanitizers();840  Res |= SanitizerKind::Address;841  Res |= SanitizerKind::PointerCompare;842  Res |= SanitizerKind::PointerSubtract;843  Res |= SanitizerKind::Fuzzer;844  Res |= SanitizerKind::FuzzerNoLink;845  Res &= ~SanitizerKind::CFIMFCall;846  return Res;847}848 849static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL,850                            bool SupportsForcingFramePointer,851                            const char *ExpandChar, const OptTable &Opts) {852  assert(A->getOption().matches(options::OPT__SLASH_O));853 854  StringRef OptStr = A->getValue();855  for (size_t I = 0, E = OptStr.size(); I != E; ++I) {856    const char &OptChar = *(OptStr.data() + I);857    switch (OptChar) {858    default:859      break;860    case '1':861    case '2':862    case 'x':863    case 'd':864      // Ignore /O[12xd] flags that aren't the last one on the command line.865      // Only the last one gets expanded.866      if (&OptChar != ExpandChar) {867        A->claim();868        break;869      }870      if (OptChar == 'd') {871        DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0));872      } else {873        if (OptChar == '1') {874          DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");875        } else if (OptChar == '2' || OptChar == 'x') {876          DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));877          DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "3");878        }879        if (SupportsForcingFramePointer &&880            !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer))881          DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer));882        if (OptChar == '1' || OptChar == '2')883          DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections));884      }885      break;886    case 'b':887      if (I + 1 != E && isdigit(OptStr[I + 1])) {888        switch (OptStr[I + 1]) {889        case '0':890          DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline));891          break;892        case '1':893          DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions));894          break;895        case '2':896        case '3':897          DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions));898          break;899        }900        ++I;901      }902      break;903    case 'g':904      A->claim();905      break;906    case 'i':907      if (I + 1 != E && OptStr[I + 1] == '-') {908        ++I;909        DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin));910      } else {911        DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));912      }913      break;914    case 's':915      DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");916      break;917    case 't':918      DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "3");919      break;920    case 'y': {921      bool OmitFramePointer = true;922      if (I + 1 != E && OptStr[I + 1] == '-') {923        OmitFramePointer = false;924        ++I;925      }926      if (SupportsForcingFramePointer) {927        if (OmitFramePointer)928          DAL.AddFlagArg(A,929                         Opts.getOption(options::OPT_fomit_frame_pointer));930        else931          DAL.AddFlagArg(932              A, Opts.getOption(options::OPT_fno_omit_frame_pointer));933      } else {934        // Don't warn about /Oy- in x86-64 builds (where935        // SupportsForcingFramePointer is false).  The flag having no effect936        // there is a compiler-internal optimization, and people shouldn't have937        // to special-case their build files for x86-64 clang-cl.938        A->claim();939      }940      break;941    }942    }943  }944}945 946static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL,947                          const OptTable &Opts) {948  assert(A->getOption().matches(options::OPT_D));949 950  StringRef Val = A->getValue();951  size_t Hash = Val.find('#');952  if (Hash == StringRef::npos || Hash > Val.find('=')) {953    DAL.append(A);954    return;955  }956 957  std::string NewVal = std::string(Val);958  NewVal[Hash] = '=';959  DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal);960}961 962static void TranslatePermissive(Arg *A, llvm::opt::DerivedArgList &DAL,963                                const OptTable &Opts) {964  DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase_));965  DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_operator_names));966}967 968static void TranslatePermissiveMinus(Arg *A, llvm::opt::DerivedArgList &DAL,969                                     const OptTable &Opts) {970  DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase));971  DAL.AddFlagArg(A, Opts.getOption(options::OPT_foperator_names));972}973 974llvm::opt::DerivedArgList *975MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,976                             StringRef BoundArch,977                             Action::OffloadKind OFK) const {978  DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());979  const OptTable &Opts = getDriver().getOpts();980 981  // /Oy and /Oy- don't have an effect on X86-64982  bool SupportsForcingFramePointer = getArch() != llvm::Triple::x86_64;983 984  // The -O[12xd] flag actually expands to several flags.  We must desugar the985  // flags so that options embedded can be negated.  For example, the '-O2' flag986  // enables '-Oy'.  Expanding '-O2' into its constituent flags allows us to987  // correctly handle '-O2 -Oy-' where the trailing '-Oy-' disables a single988  // aspect of '-O2'.989  //990  // Note that this expansion logic only applies to the *last* of '[12xd]'.991 992  // First step is to search for the character we'd like to expand.993  const char *ExpandChar = nullptr;994  for (Arg *A : Args.filtered(options::OPT__SLASH_O)) {995    StringRef OptStr = A->getValue();996    for (size_t I = 0, E = OptStr.size(); I != E; ++I) {997      char OptChar = OptStr[I];998      char PrevChar = I > 0 ? OptStr[I - 1] : '0';999      if (PrevChar == 'b') {1000        // OptChar does not expand; it's an argument to the previous char.1001        continue;1002      }1003      if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd')1004        ExpandChar = OptStr.data() + I;1005    }1006  }1007 1008  for (Arg *A : Args) {1009    if (A->getOption().matches(options::OPT__SLASH_O)) {1010      // The -O flag actually takes an amalgam of other options.  For example,1011      // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'.1012      TranslateOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, Opts);1013    } else if (A->getOption().matches(options::OPT_D)) {1014      // Translate -Dfoo#bar into -Dfoo=bar.1015      TranslateDArg(A, *DAL, Opts);1016    } else if (A->getOption().matches(options::OPT__SLASH_permissive)) {1017      // Expand /permissive1018      TranslatePermissive(A, *DAL, Opts);1019    } else if (A->getOption().matches(options::OPT__SLASH_permissive_)) {1020      // Expand /permissive-1021      TranslatePermissiveMinus(A, *DAL, Opts);1022    } else if (OFK != Action::OFK_HIP) {1023      // HIP Toolchain translates input args by itself.1024      DAL->append(A);1025    }1026  }1027 1028  return DAL;1029}1030 1031void MSVCToolChain::addClangTargetOptions(1032    const ArgList &DriverArgs, ArgStringList &CC1Args,1033    Action::OffloadKind DeviceOffloadKind) const {1034  // MSVC STL kindly allows removing all usages of typeid by defining1035  // _HAS_STATIC_RTTI to 0. Do so, when compiling with -fno-rtti1036  if (DriverArgs.hasFlag(options::OPT_fno_rtti, options::OPT_frtti,1037                         /*Default=*/false))1038    CC1Args.push_back("-D_HAS_STATIC_RTTI=0");1039 1040  if (Arg *A = DriverArgs.getLastArgNoClaim(options::OPT_marm64x))1041    A->ignoreTargetSpecific();1042}1043