llvm-project/clang/lib/Driver/MSVCToolChain.cpp

862 lines
30 KiB
C++

//===--- ToolChains.cpp - ToolChain Implementations -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "ToolChains.h"
#include "Tools.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/llvm-config.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/Path.h"
#include "llvm/Support/Process.h"
#include <cstdio>
// Include the necessary headers to interface with the Windows registry and
// environment.
#if defined(LLVM_ON_WIN32)
#define USE_WIN32
#endif
#ifdef USE_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;
using namespace llvm::opt;
MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple& Triple,
const ArgList &Args)
: ToolChain(D, Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
}
Tool *MSVCToolChain::buildLinker() const {
return new tools::visualstudio::Linker(*this);
}
Tool *MSVCToolChain::buildAssembler() const {
if (getTriple().isOSBinFormatMachO())
return new tools::darwin::Assembler(*this);
getDriver().Diag(clang::diag::err_no_external_assembler);
return nullptr;
}
bool MSVCToolChain::IsIntegratedAssemblerDefault() const {
return true;
}
bool MSVCToolChain::IsUnwindTablesDefault() const {
// Emit unwind tables by default on Win64. All non-x86_32 Windows platforms
// such as ARM and PPC actually require unwind tables, but LLVM doesn't know
// how to generate them yet.
// Don't emit unwind tables by default for MachO targets.
if (getTriple().isOSBinFormatMachO())
return false;
return getArch() == llvm::Triple::x86_64;
}
bool MSVCToolChain::isPICDefault() const {
return getArch() == llvm::Triple::x86_64;
}
bool MSVCToolChain::isPIEDefault() const {
return false;
}
bool MSVCToolChain::isPICDefaultForced() const {
return getArch() == llvm::Triple::x86_64;
}
#ifdef USE_WIN32
static bool readFullStringValue(HKEY hkey, const char *valueName,
std::string &value) {
std::wstring WideValueName;
if (!llvm::ConvertUTF8toWide(valueName, WideValueName))
return false;
DWORD result = 0;
DWORD valueSize = 0;
DWORD type = 0;
// First just query for the required size.
result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, &type, NULL,
&valueSize);
if (result != ERROR_SUCCESS || type != REG_SZ || !valueSize)
return false;
std::vector<BYTE> buffer(valueSize);
result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, NULL, &buffer[0],
&valueSize);
if (result == ERROR_SUCCESS) {
std::wstring WideValue(reinterpret_cast<const wchar_t *>(buffer.data()),
valueSize / sizeof(wchar_t));
if (valueSize && WideValue.back() == L'\0') {
WideValue.pop_back();
}
// The destination buffer must be empty as an invariant of the conversion
// function; but this function is sometimes called in a loop that passes in
// the same buffer, however. Simply clear it out so we can overwrite it.
value.clear();
return llvm::convertWideToUTF8(WideValue, value);
}
return false;
}
#endif
/// \brief Read registry string.
/// This also supports a means to look for high-versioned keys by use
/// of a $VERSION placeholder in the key path.
/// $VERSION in the key path is a placeholder for the version number,
/// causing the highest value path to be searched for and used.
/// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
/// There can be additional characters in the component. Only the numeric
/// characters are compared. This function only searches HKLM.
static bool getSystemRegistryString(const char *keyPath, const char *valueName,
std::string &value, std::string *phValue) {
#ifndef USE_WIN32
return false;
#else
HKEY hRootKey = HKEY_LOCAL_MACHINE;
HKEY hKey = NULL;
long lResult;
bool returnValue = false;
const char *placeHolder = strstr(keyPath, "$VERSION");
std::string bestName;
// If we have a $VERSION placeholder, do the highest-version search.
if (placeHolder) {
const char *keyEnd = placeHolder - 1;
const char *nextKey = placeHolder;
// Find end of previous key.
while ((keyEnd > keyPath) && (*keyEnd != '\\'))
keyEnd--;
// Find end of key containing $VERSION.
while (*nextKey && (*nextKey != '\\'))
nextKey++;
size_t partialKeyLength = keyEnd - keyPath;
char partialKey[256];
if (partialKeyLength >= sizeof(partialKey))
partialKeyLength = sizeof(partialKey) - 1;
strncpy(partialKey, keyPath, partialKeyLength);
partialKey[partialKeyLength] = '\0';
HKEY hTopKey = NULL;
lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY,
&hTopKey);
if (lResult == ERROR_SUCCESS) {
char keyName[256];
double bestValue = 0.0;
DWORD index, size = sizeof(keyName) - 1;
for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, NULL,
NULL, NULL) == ERROR_SUCCESS;
index++) {
const char *sp = keyName;
while (*sp && !isDigit(*sp))
sp++;
if (!*sp)
continue;
const char *ep = sp + 1;
while (*ep && (isDigit(*ep) || (*ep == '.')))
ep++;
char numBuf[32];
strncpy(numBuf, sp, sizeof(numBuf) - 1);
numBuf[sizeof(numBuf) - 1] = '\0';
double dvalue = strtod(numBuf, NULL);
if (dvalue > bestValue) {
// Test that InstallDir is indeed there before keeping this index.
// Open the chosen key path remainder.
bestName = keyName;
// Append rest of key.
bestName.append(nextKey);
lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0,
KEY_READ | KEY_WOW64_32KEY, &hKey);
if (lResult == ERROR_SUCCESS) {
if (readFullStringValue(hKey, valueName, value)) {
bestValue = dvalue;
if (phValue)
*phValue = bestName;
returnValue = true;
}
RegCloseKey(hKey);
}
}
size = sizeof(keyName) - 1;
}
RegCloseKey(hTopKey);
}
} else {
lResult =
RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey);
if (lResult == ERROR_SUCCESS) {
if (readFullStringValue(hKey, valueName, value))
returnValue = true;
if (phValue)
phValue->clear();
RegCloseKey(hKey);
}
}
return returnValue;
#endif // USE_WIN32
}
// Convert LLVM's ArchType
// to the corresponding name of Windows SDK libraries subfolder
static StringRef getWindowsSDKArch(llvm::Triple::ArchType Arch) {
switch (Arch) {
case llvm::Triple::x86:
return "x86";
case llvm::Triple::x86_64:
return "x64";
case llvm::Triple::arm:
return "arm";
default:
return "";
}
}
// Find the most recent version of Universal CRT or Windows 10 SDK.
// vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include
// directory by name and uses the last one of the list.
// So we compare entry names lexicographically to find the greatest one.
static bool getWindows10SDKVersion(const std::string &SDKPath,
std::string &SDKVersion) {
SDKVersion.clear();
std::error_code EC;
llvm::SmallString<128> IncludePath(SDKPath);
llvm::sys::path::append(IncludePath, "Include");
for (llvm::sys::fs::directory_iterator DirIt(IncludePath, EC), DirEnd;
DirIt != DirEnd && !EC; DirIt.increment(EC)) {
if (!llvm::sys::fs::is_directory(DirIt->path()))
continue;
StringRef CandidateName = llvm::sys::path::filename(DirIt->path());
// If WDK is installed, there could be subfolders like "wdf" in the
// "Include" directory.
// Allow only directories which names start with "10.".
if (!CandidateName.startswith("10."))
continue;
if (CandidateName > SDKVersion)
SDKVersion = CandidateName;
}
return !SDKVersion.empty();
}
/// \brief Get Windows SDK installation directory.
bool MSVCToolChain::getWindowsSDKDir(std::string &Path, int &Major,
std::string &WindowsSDKIncludeVersion,
std::string &WindowsSDKLibVersion) const {
std::string RegistrySDKVersion;
// Try the Windows registry.
if (!getSystemRegistryString(
"SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
"InstallationFolder", Path, &RegistrySDKVersion))
return false;
if (Path.empty() || RegistrySDKVersion.empty())
return false;
WindowsSDKIncludeVersion.clear();
WindowsSDKLibVersion.clear();
Major = 0;
std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major);
if (Major <= 7)
return true;
if (Major == 8) {
// Windows SDK 8.x installs libraries in a folder whose names depend on the
// version of the OS you're targeting. By default choose the newest, which
// usually corresponds to the version of the OS you've installed the SDK on.
const char *Tests[] = {"winv6.3", "win8", "win7"};
for (const char *Test : Tests) {
llvm::SmallString<128> TestPath(Path);
llvm::sys::path::append(TestPath, "Lib", Test);
if (llvm::sys::fs::exists(TestPath.c_str())) {
WindowsSDKLibVersion = Test;
break;
}
}
return !WindowsSDKLibVersion.empty();
}
if (Major == 10) {
if (!getWindows10SDKVersion(Path, WindowsSDKIncludeVersion))
return false;
WindowsSDKLibVersion = WindowsSDKIncludeVersion;
return true;
}
// Unsupported SDK version
return false;
}
// Gets the library path required to link against the Windows SDK.
bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const {
std::string sdkPath;
int sdkMajor = 0;
std::string windowsSDKIncludeVersion;
std::string windowsSDKLibVersion;
path.clear();
if (!getWindowsSDKDir(sdkPath, sdkMajor, windowsSDKIncludeVersion,
windowsSDKLibVersion))
return false;
llvm::SmallString<128> libPath(sdkPath);
llvm::sys::path::append(libPath, "Lib");
if (sdkMajor <= 7) {
switch (getArch()) {
// In Windows SDK 7.x, x86 libraries are directly in the Lib folder.
case llvm::Triple::x86:
break;
case llvm::Triple::x86_64:
llvm::sys::path::append(libPath, "x64");
break;
case llvm::Triple::arm:
// It is not necessary to link against Windows SDK 7.x when targeting ARM.
return false;
default:
return false;
}
} else {
const StringRef archName = getWindowsSDKArch(getArch());
if (archName.empty())
return false;
llvm::sys::path::append(libPath, windowsSDKLibVersion, "um", archName);
}
path = libPath.str();
return true;
}
// Check if the Include path of a specified version of Visual Studio contains
// specific header files. If not, they are probably shipped with Universal CRT.
bool clang::driver::toolchains::MSVCToolChain::useUniversalCRT(
std::string &VisualStudioDir) const {
llvm::SmallString<128> TestPath(VisualStudioDir);
llvm::sys::path::append(TestPath, "VC\\include\\stdlib.h");
return !llvm::sys::fs::exists(TestPath);
}
bool MSVCToolChain::getUniversalCRTSdkDir(std::string &Path,
std::string &UCRTVersion) const {
// vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry
// for the specific key "KitsRoot10". So do we.
if (!getSystemRegistryString(
"SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10",
Path, nullptr))
return false;
return getWindows10SDKVersion(Path, UCRTVersion);
}
bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const {
std::string UniversalCRTSdkPath;
std::string UCRTVersion;
Path.clear();
if (!getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion))
return false;
StringRef ArchName = getWindowsSDKArch(getArch());
if (ArchName.empty())
return false;
llvm::SmallString<128> LibPath(UniversalCRTSdkPath);
llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName);
Path = LibPath.str();
return true;
}
// Get the location to use for Visual Studio binaries. The location priority
// is: %VCINSTALLDIR% > %PATH% > newest copy of Visual Studio installed on
// system (as reported by the registry).
bool MSVCToolChain::getVisualStudioBinariesFolder(const char *clangProgramPath,
std::string &path) const {
path.clear();
SmallString<128> BinDir;
// First check the environment variables that vsvars32.bat sets.
llvm::Optional<std::string> VcInstallDir =
llvm::sys::Process::GetEnv("VCINSTALLDIR");
if (VcInstallDir.hasValue()) {
BinDir = VcInstallDir.getValue();
llvm::sys::path::append(BinDir, "bin");
} else {
// Next walk the PATH, trying to find a cl.exe in the path. If we find one,
// use that. However, make sure it's not clang's cl.exe.
llvm::Optional<std::string> OptPath = llvm::sys::Process::GetEnv("PATH");
if (OptPath.hasValue()) {
const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'};
SmallVector<StringRef, 8> PathSegments;
llvm::SplitString(OptPath.getValue(), PathSegments, EnvPathSeparatorStr);
for (StringRef PathSegment : PathSegments) {
if (PathSegment.empty())
continue;
SmallString<128> FilePath(PathSegment);
llvm::sys::path::append(FilePath, "cl.exe");
// Checking if cl.exe exists is a small optimization over calling
// can_execute, which really only checks for existence but will also do
// extra checks for cl.exe.exe. These add up when walking a long path.
if (llvm::sys::fs::exists(FilePath.c_str()) &&
!llvm::sys::fs::equivalent(FilePath.c_str(), clangProgramPath)) {
// If we found it on the PATH, use it exactly as is with no
// modifications.
path = PathSegment;
return true;
}
}
}
std::string installDir;
// With no VCINSTALLDIR and nothing on the PATH, if we can't find it in the
// registry then we have no choice but to fail.
if (!getVisualStudioInstallDir(installDir))
return false;
// Regardless of what binary we're ultimately trying to find, we make sure
// that this is a Visual Studio directory by checking for cl.exe. We use
// cl.exe instead of other binaries like link.exe because programs such as
// GnuWin32 also have a utility called link.exe, so cl.exe is the least
// ambiguous.
BinDir = installDir;
llvm::sys::path::append(BinDir, "VC", "bin");
SmallString<128> ClPath(BinDir);
llvm::sys::path::append(ClPath, "cl.exe");
if (!llvm::sys::fs::can_execute(ClPath.c_str()))
return false;
}
if (BinDir.empty())
return false;
switch (getArch()) {
case llvm::Triple::x86:
break;
case llvm::Triple::x86_64:
llvm::sys::path::append(BinDir, "amd64");
break;
case llvm::Triple::arm:
llvm::sys::path::append(BinDir, "arm");
break;
default:
// Whatever this is, Visual Studio doesn't have a toolchain for it.
return false;
}
path = BinDir.str();
return true;
}
VersionTuple MSVCToolChain::getMSVCVersionFromExe() const {
VersionTuple Version;
#ifdef USE_WIN32
std::string BinPath;
if (!getVisualStudioBinariesFolder("", BinPath))
return Version;
SmallString<128> ClExe(BinPath);
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;
}
// Get Visual Studio installation directory.
bool MSVCToolChain::getVisualStudioInstallDir(std::string &path) const {
// First check the environment variables that vsvars32.bat sets.
if (llvm::Optional<std::string> VcInstallDir =
llvm::sys::Process::GetEnv("VCINSTALLDIR")) {
path = std::move(*VcInstallDir);
path = path.substr(0, path.find("\\VC"));
return true;
}
std::string vsIDEInstallDir;
std::string vsExpressIDEInstallDir;
// Then try the windows registry.
bool hasVCDir =
getSystemRegistryString("SOFTWARE\\Microsoft\\VisualStudio\\$VERSION",
"InstallDir", vsIDEInstallDir, nullptr);
if (hasVCDir && !vsIDEInstallDir.empty()) {
path = vsIDEInstallDir.substr(0, vsIDEInstallDir.find("\\Common7\\IDE"));
return true;
}
bool hasVCExpressDir =
getSystemRegistryString("SOFTWARE\\Microsoft\\VCExpress\\$VERSION",
"InstallDir", vsExpressIDEInstallDir, nullptr);
if (hasVCExpressDir && !vsExpressIDEInstallDir.empty()) {
path = vsExpressIDEInstallDir.substr(
0, vsIDEInstallDir.find("\\Common7\\IDE"));
return true;
}
// Try the environment.
std::string vcomntools;
if (llvm::Optional<std::string> vs120comntools =
llvm::sys::Process::GetEnv("VS120COMNTOOLS"))
vcomntools = std::move(*vs120comntools);
else if (llvm::Optional<std::string> vs100comntools =
llvm::sys::Process::GetEnv("VS100COMNTOOLS"))
vcomntools = std::move(*vs100comntools);
else if (llvm::Optional<std::string> vs90comntools =
llvm::sys::Process::GetEnv("VS90COMNTOOLS"))
vcomntools = std::move(*vs90comntools);
else if (llvm::Optional<std::string> vs80comntools =
llvm::sys::Process::GetEnv("VS80COMNTOOLS"))
vcomntools = std::move(*vs80comntools);
// Find any version we can.
if (!vcomntools.empty()) {
size_t p = vcomntools.find("\\Common7\\Tools");
if (p != std::string::npos)
vcomntools.resize(p);
path = std::move(vcomntools);
return true;
}
return false;
}
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);
if (DriverArgs.hasArg(options::OPT_nostdlibinc))
return;
// Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat.
if (llvm::Optional<std::string> cl_include_dir =
llvm::sys::Process::GetEnv("INCLUDE")) {
SmallVector<StringRef, 8> Dirs;
StringRef(*cl_include_dir)
.split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
for (StringRef Dir : Dirs)
addSystemInclude(DriverArgs, CC1Args, Dir);
if (!Dirs.empty())
return;
}
std::string VSDir;
// When built with access to the proper Windows APIs, try to actually find
// the correct include paths first.
if (getVisualStudioInstallDir(VSDir)) {
AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, VSDir, "VC\\include");
if (useUniversalCRT(VSDir)) {
std::string UniversalCRTSdkPath;
std::string UCRTVersion;
if (getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) {
AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath,
"Include", UCRTVersion, "ucrt");
}
}
std::string WindowsSDKDir;
int major;
std::string windowsSDKIncludeVersion;
std::string windowsSDKLibVersion;
if (getWindowsSDKDir(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");
} else {
AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
"include");
}
} else {
addSystemInclude(DriverArgs, CC1Args, VSDir);
}
return;
}
#if defined(LLVM_ON_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.
}
std::string
MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
types::ID InputType) const {
std::string TripleStr =
ToolChain::ComputeEffectiveClangTriple(Args, InputType);
llvm::Triple Triple(TripleStr);
VersionTuple MSVT =
tools::visualstudio::getMSVCVersion(/*D=*/nullptr, *this, Triple, Args,
/*IsWindowsMSVC=*/true);
if (MSVT.empty())
return TripleStr;
MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().getValueOr(0),
MSVT.getSubminor().getValueOr(0));
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;
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':
if (&OptChar == ExpandChar) {
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':
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 64-bit 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 64-bit 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 = Val;
NewVal[Hash] = '=';
DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal);
}
llvm::opt::DerivedArgList *
MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
StringRef BoundArch, Action::OffloadKind) const {
DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
const OptTable &Opts = getDriver().getOpts();
// /Oy and /Oy- only has an effect under X86-32.
bool SupportsForcingFramePointer = getArch() == llvm::Triple::x86;
// 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) {
if (!A->getOption().matches(options::OPT__SLASH_O))
continue;
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 {
DAL->append(A);
}
}
return DAL;
}