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

364 lines
12 KiB
C++
Raw Normal View History

//===--- 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 "clang/Basic/CharInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Options.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Path.h"
// Include the necessary headers to interface with the Windows registry and
// environment.
#ifdef _MSC_VER
#define WIN32_LEAN_AND_MEAN
#define NOGDI
#define NOMINMAX
#include <Windows.h>
#endif
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
Revert r149083 which is not the direction we're going in the Clang driver based on discussions with Doug Gregor. There are several issues: 1) The patch was not reviewed prior to commit and there were review comments. 2) The design of the functionality (triple-prefixed tool invocation) isn't the design we want for Clang going forward: it focuses on the "user triple" rather than on the "toolchain triple", and forces that bit of state into the API of every single toolchain instead of handling it automatically in the common base classes. 3) The tests provided are not stable. They fail on a few Linux variants (Gentoo among them) and on mingw32 and some other environments. I *am* interested in the Clang driver being able to invoke triple-prefixed tools, but we need to design that feature the right way. This patch just extends the previous hack without fixing the underlying problems with it. I'm working on a new design for this that I will mail for review by tomorrow. I am aware that this removes functionality that NetBSD relies on, but this is ToT, not a release. This functionality hasn't been properly designed, implemented, and tested yet. We can't "regress" until we get something that really works, both with the immediate use cases and with long term maintenance of the Clang driver. For reference, the original commit log: Keep track of the original target the user specified before normalization. This used to be captured in DefaultTargetTriple and is used for the (optional) $triple-$tool lookup for cross-compilation. Do this properly by making it an attribute of the toolchain and use it in combination with the computed triple as index for the toolchain lookup. llvm-svn: 149337
2012-01-31 10:21:20 +08:00
Windows::Windows(const Driver &D, const llvm::Triple& Triple)
: ToolChain(D, Triple) {
}
Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const {
Action::ActionClass Key;
if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
else
Key = JA.getKind();
bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
options::OPT_no_integrated_as,
IsIntegratedAssemblerDefault());
Tool *&T = Tools[Key];
if (!T) {
switch (Key) {
case Action::InputClass:
case Action::BindArchClass:
case Action::LipoJobClass:
case Action::DsymutilJobClass:
case Action::VerifyJobClass:
case Action::PreprocessJobClass:
case Action::PrecompileJobClass:
case Action::AnalyzeJobClass:
case Action::MigrateJobClass:
case Action::CompileJobClass:
T = new tools::Clang(*this); break;
case Action::AssembleJobClass:
if (!UseIntegratedAs && getTriple().getEnvironment() == llvm::Triple::MachO)
T = new tools::darwin::Assemble(*this);
else
T = new tools::ClangAs(*this);
break;
case Action::LinkJobClass:
T = new tools::visualstudio::Link(*this); break;
}
}
return *T;
}
bool Windows::IsIntegratedAssemblerDefault() const {
return true;
}
bool Windows::IsUnwindTablesDefault() const {
return getArch() == llvm::Triple::x86_64;
}
Completely re-work how the Clang driver interprets PIC and PIE options. There were numerous issues here that were all entangled, and so I've tried to do a general simplification of the logic. 1) The logic was mimicing actual GCC bugs, rather than "features". These have been fixed in trunk GCC, and this fixes Clang as well. Notably, the logic was always intended to be last-match-wins like any other flag. 2) The logic for handling '-mdynamic-no-pic' was preposterously unclear. It also allowed the use of this flag on non-Darwin platforms where it has no actual meaning. Now this option is handled directly based on tests of how llvm-gcc behaves, and it is only supported on Darwin. 3) The APIs for the Driver's ToolChains had the implementation ugliness of dynamic-no-pic leaking through them. They also had the implementation details of the LLVM relocation model flag names leaking through. 4) The actual results of passing these flags was incorrect on Darwin in many cases. For example, Darwin *always* uses PIC level 2 if it uses in PIC level, and Darwin *always* uses PIC on 64-bit regardless of the flags specified, including -fPIE. Darwin never compiles in PIE mode, but it can *link* in PIE mode. 5) Also, PIC was not always being enabled even when PIE was. This isn't a supported mode at all and may have caused some fallout in builds with complex PIC and PIE interactions. The result is (I hope) cleaner and clearer for readers. I've also left comments and tests about some of the truly strage behavior that is observed on Darwin platforms. We have no real testing of Windows platforms and PIC, but I don't have the tools handy to figure that out. Hopefully others can beef up our testing here. Unfortunately, I can't test this for every platform. =/ If folks have dependencies on these flags that aren't covered by tests, they may break. I've audited and ensured that all the changes in behavior of the existing tests are intentional and good. In particular I've tried to make sure the Darwin behavior (which is more suprising than the Linux behavior) also matches that of 'gcc' on my mac. llvm-svn: 168297
2012-11-19 11:52:03 +08:00
bool Windows::isPICDefault() const {
return getArch() == llvm::Triple::x86_64;
}
Completely re-work how the Clang driver interprets PIC and PIE options. There were numerous issues here that were all entangled, and so I've tried to do a general simplification of the logic. 1) The logic was mimicing actual GCC bugs, rather than "features". These have been fixed in trunk GCC, and this fixes Clang as well. Notably, the logic was always intended to be last-match-wins like any other flag. 2) The logic for handling '-mdynamic-no-pic' was preposterously unclear. It also allowed the use of this flag on non-Darwin platforms where it has no actual meaning. Now this option is handled directly based on tests of how llvm-gcc behaves, and it is only supported on Darwin. 3) The APIs for the Driver's ToolChains had the implementation ugliness of dynamic-no-pic leaking through them. They also had the implementation details of the LLVM relocation model flag names leaking through. 4) The actual results of passing these flags was incorrect on Darwin in many cases. For example, Darwin *always* uses PIC level 2 if it uses in PIC level, and Darwin *always* uses PIC on 64-bit regardless of the flags specified, including -fPIE. Darwin never compiles in PIE mode, but it can *link* in PIE mode. 5) Also, PIC was not always being enabled even when PIE was. This isn't a supported mode at all and may have caused some fallout in builds with complex PIC and PIE interactions. The result is (I hope) cleaner and clearer for readers. I've also left comments and tests about some of the truly strage behavior that is observed on Darwin platforms. We have no real testing of Windows platforms and PIC, but I don't have the tools handy to figure that out. Hopefully others can beef up our testing here. Unfortunately, I can't test this for every platform. =/ If folks have dependencies on these flags that aren't covered by tests, they may break. I've audited and ensured that all the changes in behavior of the existing tests are intentional and good. In particular I've tried to make sure the Darwin behavior (which is more suprising than the Linux behavior) also matches that of 'gcc' on my mac. llvm-svn: 168297
2012-11-19 11:52:03 +08:00
bool Windows::isPICDefaultForced() const {
return getArch() == llvm::Triple::x86_64;
}
// FIXME: This probably should goto to some platform utils place.
#ifdef _MSC_VER
/// \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. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
/// There can be additional characters in the component. Only the numberic
/// characters are compared.
static bool getSystemRegistryString(const char *keyPath, const char *valueName,
char *value, size_t maxLength) {
HKEY hRootKey = NULL;
HKEY hKey = NULL;
const char* subKey = NULL;
DWORD valueType;
DWORD valueSize = maxLength - 1;
long lResult;
bool returnValue = false;
if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) {
hRootKey = HKEY_CLASSES_ROOT;
subKey = keyPath + 18;
} else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) {
hRootKey = HKEY_USERS;
subKey = keyPath + 11;
} else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) {
hRootKey = HKEY_LOCAL_MACHINE;
subKey = keyPath + 19;
} else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) {
hRootKey = HKEY_CURRENT_USER;
subKey = keyPath + 18;
} else {
return false;
}
const char *placeHolder = strstr(subKey, "$VERSION");
char bestName[256];
bestName[0] = '\0';
// 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 > subKey) && (*keyEnd != '\\'))
keyEnd--;
// Find end of key containing $VERSION.
while (*nextKey && (*nextKey != '\\'))
nextKey++;
size_t partialKeyLength = keyEnd - subKey;
char partialKey[256];
if (partialKeyLength > sizeof(partialKey))
partialKeyLength = sizeof(partialKey);
strncpy(partialKey, subKey, partialKeyLength);
partialKey[partialKeyLength] = '\0';
HKEY hTopKey = NULL;
lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ, &hTopKey);
if (lResult == ERROR_SUCCESS) {
char keyName[256];
int bestIndex = -1;
double bestValue = 0.0;
DWORD index, size = sizeof(keyName) - 1;
for (index = 0; RegEnumKeyEx(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 value = strtod(numBuf, NULL);
if (value > bestValue) {
bestIndex = (int)index;
bestValue = value;
strcpy(bestName, keyName);
}
size = sizeof(keyName) - 1;
}
// If we found the highest versioned key, open the key and get the value.
if (bestIndex != -1) {
// Append rest of key.
strncat(bestName, nextKey, sizeof(bestName) - 1);
bestName[sizeof(bestName) - 1] = '\0';
// Open the chosen key path remainder.
lResult = RegOpenKeyEx(hTopKey, bestName, 0, KEY_READ, &hKey);
if (lResult == ERROR_SUCCESS) {
lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
(LPBYTE)value, &valueSize);
if (lResult == ERROR_SUCCESS)
returnValue = true;
RegCloseKey(hKey);
}
}
RegCloseKey(hTopKey);
}
} else {
lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ, &hKey);
if (lResult == ERROR_SUCCESS) {
lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
(LPBYTE)value, &valueSize);
if (lResult == ERROR_SUCCESS)
returnValue = true;
RegCloseKey(hKey);
}
}
return returnValue;
}
/// \brief Get Windows SDK installation directory.
static bool getWindowsSDKDir(std::string &path) {
char windowsSDKInstallDir[256];
// Try the Windows registry.
bool hasSDKDir = getSystemRegistryString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
"InstallationFolder",
windowsSDKInstallDir,
sizeof(windowsSDKInstallDir) - 1);
// If we have both vc80 and vc90, pick version we were compiled with.
if (hasSDKDir && windowsSDKInstallDir[0]) {
path = windowsSDKInstallDir;
return true;
}
return false;
}
// Get Visual Studio installation directory.
static bool getVisualStudioDir(std::string &path) {
// First check the environment variables that vsvars32.bat sets.
const char* vcinstalldir = getenv("VCINSTALLDIR");
if (vcinstalldir) {
char *p = const_cast<char *>(strstr(vcinstalldir, "\\VC"));
if (p)
*p = '\0';
path = vcinstalldir;
return true;
}
char vsIDEInstallDir[256];
char vsExpressIDEInstallDir[256];
// Then try the windows registry.
bool hasVCDir = getSystemRegistryString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION",
"InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1);
bool hasVCExpressDir = getSystemRegistryString(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION",
"InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1);
// If we have both vc80 and vc90, pick version we were compiled with.
if (hasVCDir && vsIDEInstallDir[0]) {
char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE");
if (p)
*p = '\0';
path = vsIDEInstallDir;
return true;
}
if (hasVCExpressDir && vsExpressIDEInstallDir[0]) {
char *p = (char*)strstr(vsExpressIDEInstallDir, "\\Common7\\IDE");
if (p)
*p = '\0';
path = vsExpressIDEInstallDir;
return true;
}
// Try the environment.
const char *vs100comntools = getenv("VS100COMNTOOLS");
const char *vs90comntools = getenv("VS90COMNTOOLS");
const char *vs80comntools = getenv("VS80COMNTOOLS");
const char *vscomntools = NULL;
// Try to find the version that we were compiled with
if(false) {}
#if (_MSC_VER >= 1600) // VC100
else if(vs100comntools) {
vscomntools = vs100comntools;
}
#elif (_MSC_VER == 1500) // VC80
else if(vs90comntools) {
vscomntools = vs90comntools;
}
#elif (_MSC_VER == 1400) // VC80
else if(vs80comntools) {
vscomntools = vs80comntools;
}
#endif
// Otherwise find any version we can
else if (vs100comntools)
vscomntools = vs100comntools;
else if (vs90comntools)
vscomntools = vs90comntools;
else if (vs80comntools)
vscomntools = vs80comntools;
if (vscomntools && *vscomntools) {
const char *p = strstr(vscomntools, "\\Common7\\Tools");
path = p ? std::string(vscomntools, p) : vscomntools;
return true;
}
return false;
}
#endif // _MSC_VER
void Windows::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
if (DriverArgs.hasArg(options::OPT_nostdinc))
return;
if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
llvm::sys::Path P(getDriver().ResourceDir);
P.appendComponent("include");
addSystemInclude(DriverArgs, CC1Args, P.str());
}
if (DriverArgs.hasArg(options::OPT_nostdlibinc))
return;
#ifdef _MSC_VER
// Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat.
if (const char *cl_include_dir = getenv("INCLUDE")) {
SmallVector<StringRef, 8> Dirs;
StringRef(cl_include_dir).split(Dirs, ";");
int n = 0;
for (SmallVectorImpl<StringRef>::iterator I = Dirs.begin(), E = Dirs.end();
I != E; ++I) {
StringRef d = *I;
if (d.size() == 0)
continue;
++n;
addSystemInclude(DriverArgs, CC1Args, d);
}
if (n) return;
}
std::string VSDir;
std::string WindowsSDKDir;
// When built with access to the proper Windows APIs, try to actually find
// the correct include paths first.
if (getVisualStudioDir(VSDir)) {
addSystemInclude(DriverArgs, CC1Args, VSDir + "\\VC\\include");
if (getWindowsSDKDir(WindowsSDKDir))
addSystemInclude(DriverArgs, CC1Args, WindowsSDKDir + "\\include");
else
addSystemInclude(DriverArgs, CC1Args,
VSDir + "\\VC\\PlatformSDK\\Include");
return;
}
#endif // _MSC_VER
// As a fallback, select default install paths.
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);
}
void Windows::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
// FIXME: There should probably be logic here to find libc++ on Windows.
}