| //===--- 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/Driver/Arg.h" |
| #include "clang/Driver/ArgList.h" |
| #include "clang/Driver/Compilation.h" |
| #include "clang/Driver/Driver.h" |
| #include "clang/Driver/Options.h" |
| #include "clang/Basic/Version.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; |
| |
| 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: |
| llvm_unreachable("Invalid tool kind."); |
| case Action::PreprocessJobClass: |
| case Action::PrecompileJobClass: |
| case Action::AnalyzeJobClass: |
| 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 { |
| // FIXME: Gross; we should probably have some separate target |
| // definition, possibly even reusing the one in clang. |
| return getArchName() == "x86_64"; |
| } |
| |
| const char *Windows::GetDefaultRelocationModel() const { |
| return "static"; |
| } |
| |
| const char *Windows::GetForcedPicModel() const { |
| if (getArchName() == "x86_64") |
| return "pic"; |
| return 0; |
| } |
| |
| // 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; |
| |
| std::string VSDir; |
| std::string WindowsSDKDir; |
| |
| #ifdef _MSC_VER |
| // 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. |
| } |