992 lines
38 KiB
C++
992 lines
38 KiB
C++
//===-- 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");
|
|
}
|