Move platform specific code from CIFactory.cpp into separate modules.
Signed-off-by: Vassil Vassilev <vvasilev@cern.ch>
This commit is contained in:
parent
a55bbe356c
commit
cce7d69844
105
include/cling/Utils/Platform.h
Normal file
105
include/cling/Utils/Platform.h
Normal file
@ -0,0 +1,105 @@
|
||||
//--------------------------------------------------------------------*- C++ -*-
|
||||
// CLING - the C++ LLVM-based InterpreterG :)
|
||||
// author: Roman Zulak
|
||||
//
|
||||
// This file is dual-licensed: you can choose to license it under the University
|
||||
// of Illinois Open Source License or the GNU Lesser General Public License. See
|
||||
// LICENSE.TXT for details.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef CLING_PLATFORM_H
|
||||
#define CLING_PLATFORM_H
|
||||
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <string>
|
||||
|
||||
namespace cling {
|
||||
namespace utils {
|
||||
namespace platform {
|
||||
|
||||
///\brief Returns the current working directory
|
||||
///
|
||||
std::string GetCwd();
|
||||
|
||||
#if defined(LLVM_ON_UNIX)
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
||||
inline namespace osx {
|
||||
///\brief Get a path to an OSX SDK that can be used for -isysroot. Matches
|
||||
/// 1. Version matching the running system
|
||||
/// 2. Version that cling was compiled
|
||||
/// 3. Highest installed version
|
||||
///
|
||||
/// \param [out] SysRoot - The path to the SDK
|
||||
/// \param [in] Verbose - Log progress
|
||||
///
|
||||
bool GetISysRoot(std::string& SysRoot, bool Verbose = false);
|
||||
|
||||
} // namespace osx
|
||||
|
||||
#endif // __APPLE__
|
||||
|
||||
#elif defined(LLVM_ON_WIN32)
|
||||
|
||||
inline namespace windows {
|
||||
|
||||
///\brief Get an error message from the last Windows API
|
||||
///
|
||||
/// \param [in] Prefix - Prefix the message with this (ex. API call name)
|
||||
///
|
||||
/// \returns true if ::GetLastError returned an error code
|
||||
///
|
||||
bool GetLastErrorAsString(std::string& ErrStr, const char* Prefix = nullptr);
|
||||
|
||||
///\brief Reports the last Windows API error (currently to cling::errs)
|
||||
///
|
||||
/// \param [in] Prefix - Prefix the message with this
|
||||
///
|
||||
bool ReportLastError(const char* Prefix = nullptr);
|
||||
|
||||
/// \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.
|
||||
///
|
||||
/// \param [in] Key - Key to lookup
|
||||
/// \param [in] ValueName - Value to lookup
|
||||
/// \param [out] Value - The value of the given key-value pair
|
||||
///
|
||||
/// \returns true if key-value existed and was read into Value
|
||||
///
|
||||
bool GetSystemRegistryString(const char* Key, const char* ValueName,
|
||||
std::string& Value);
|
||||
|
||||
///\brief Get a path to an installed VisualStudio directory matching:
|
||||
/// 1. Version that cling was compiled
|
||||
/// 2. Version that shell is initialized to
|
||||
/// 3. Highest installed version
|
||||
///
|
||||
/// \param [out] Path - Path to VisualStudio
|
||||
/// \param [out] WindSDK - Store the path to the Windows SDK here
|
||||
/// \param [out] UniversalSDK - Store the path to the Universal SDK here
|
||||
/// \param [in] Verbose - Log progress
|
||||
///
|
||||
bool GetVisualStudioDirs(std::string& Path,
|
||||
std::string* WindSDK = nullptr,
|
||||
std::string* UniversalSDK = nullptr,
|
||||
bool Verbose = false);
|
||||
|
||||
///\brief Returns the VisualStudio version cling was compiled with
|
||||
int GetVisualStudioVersionCompiledWith();
|
||||
|
||||
} // namespace windows
|
||||
#endif // LLVM_ON_WIN32
|
||||
|
||||
} // namespace platform
|
||||
} // namespace utils
|
||||
namespace platform = utils::platform;
|
||||
} // namespace cling
|
||||
|
||||
#endif // CLING_PLATFORM_H
|
@ -7,14 +7,15 @@
|
||||
// LICENSE.TXT for details.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "cling/Interpreter/CIFactory.h"
|
||||
#include "cling/Utils/Paths.h"
|
||||
#include "cling/Interpreter/InvocationOptions.h"
|
||||
#include "ClingUtils.h"
|
||||
|
||||
#include "DeclCollector.h"
|
||||
#include "cling-compiledata.h"
|
||||
|
||||
#include "cling/Interpreter/CIFactory.h"
|
||||
#include "cling/Interpreter/InvocationOptions.h"
|
||||
#include "cling/Utils/Paths.h"
|
||||
#include "cling/Utils/Platform.h"
|
||||
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Basic/Version.h"
|
||||
@ -32,481 +33,16 @@
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#define getcwd_func getcwd
|
||||
#endif
|
||||
|
||||
// FIXME: This code has been taken (copied from) llvm/tools/clang/lib/Driver/WindowsToolChain.cpp
|
||||
// and should probably go to some platform utils place.
|
||||
// the code for VS 11.0 and 12.0 common tools (vs110comntools and vs120comntools)
|
||||
// has been implemented (added) in getVisualStudioDir()
|
||||
#ifdef _MSC_VER
|
||||
// Include the necessary headers to interface with the Windows registry and
|
||||
// environment.
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define NOGDI
|
||||
# ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
# endif
|
||||
# include <Windows.h>
|
||||
# include <direct.h>
|
||||
# define popen _popen
|
||||
# define pclose _pclose
|
||||
# define getcwd_func _getcwd
|
||||
# pragma comment(lib, "Advapi32.lib")
|
||||
|
||||
using namespace clang;
|
||||
|
||||
/// \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 | KEY_WOW64_32KEY,
|
||||
&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 dvalue = strtod(numBuf, NULL);
|
||||
if (dvalue > bestValue) {
|
||||
// Test that InstallDir is indeed there before keeping this index.
|
||||
// Open the chosen key path remainder.
|
||||
strcpy(bestName, keyName);
|
||||
// Append rest of key.
|
||||
strncat(bestName, nextKey, sizeof(bestName) - 1);
|
||||
bestName[sizeof(bestName) - 1] = '\0';
|
||||
lResult = RegOpenKeyEx(hTopKey, bestName, 0,
|
||||
KEY_READ | KEY_WOW64_32KEY, &hKey);
|
||||
if (lResult == ERROR_SUCCESS) {
|
||||
lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
|
||||
(LPBYTE)value, &valueSize);
|
||||
if (lResult == ERROR_SUCCESS) {
|
||||
bestIndex = (int)index;
|
||||
bestValue = dvalue;
|
||||
returnValue = true;
|
||||
}
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
}
|
||||
size = sizeof(keyName) - 1;
|
||||
}
|
||||
RegCloseKey(hTopKey);
|
||||
}
|
||||
} else {
|
||||
lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ | KEY_WOW64_32KEY,
|
||||
&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;
|
||||
}
|
||||
|
||||
#if LLVM_MSC_PREREQ(1900)
|
||||
// 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();
|
||||
}
|
||||
|
||||
static bool getUniversalCRTSdkDir(std::string &Path,
|
||||
std::string &UCRTVersion) {
|
||||
// vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry
|
||||
// for the specific key "KitsRoot10". So do we.
|
||||
char sPath[256];
|
||||
if (!getSystemRegistryString(
|
||||
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots",
|
||||
"KitsRoot10", sPath, sizeof(sPath)))
|
||||
return false;
|
||||
Path = sPath;
|
||||
return getWindows10SDKVersion(Path, UCRTVersion);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void logSearch(const char* Name, const std::string& Value,
|
||||
const char* Found = nullptr) {
|
||||
if (Found)
|
||||
llvm::errs() << "Found " << Name << " '" << Value << "' that matches "
|
||||
<< Found << " version\n";
|
||||
else
|
||||
llvm::errs() << Name << " '" << Value << "' not found.\n";
|
||||
}
|
||||
|
||||
static void trimString(const char* Value, const char* SubStr,
|
||||
std::string& Out) {
|
||||
const char* End = ::strstr(Value, SubStr);
|
||||
Out = End ? std::string(Value, End) : Value;
|
||||
}
|
||||
|
||||
static bool getVSRegistryString(const char* Product, int VSVersion,
|
||||
std::string& Path, const char* Verbose) {
|
||||
std::stringstream Key;
|
||||
Key << "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" << Product << "\\"
|
||||
<< VSVersion << ".0";
|
||||
char IDEInstallDir[1024];
|
||||
if (!getSystemRegistryString(Key.str().c_str(), "InstallDir",
|
||||
IDEInstallDir, sizeof(IDEInstallDir) - 1)
|
||||
|| IDEInstallDir[0] == 0) {
|
||||
if (Verbose)
|
||||
logSearch("Registry", Key.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
trimString(IDEInstallDir, "\\Common7\\IDE", Path);
|
||||
if (Verbose)
|
||||
logSearch("Registry", Key.str(), Verbose);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool getVSEnvironmentString(int VSVersion, std::string& Path,
|
||||
const char* Verbose) {
|
||||
std::stringstream Key;
|
||||
Key << "VS" << VSVersion * 10 << "COMNTOOLS";
|
||||
const char* Tools = ::getenv(Key.str().c_str());
|
||||
if (!Tools) {
|
||||
if (Verbose)
|
||||
logSearch("Environment", Key.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
trimString(Tools, "\\Common7\\Tools", Path);
|
||||
if (Verbose)
|
||||
logSearch("Environment", Key.str(), Verbose);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool getVisualStudioVer(int VSVersion, std::string& Path,
|
||||
const char* Verbose) {
|
||||
if (getVSRegistryString("VisualStudio", VSVersion, Path, Verbose))
|
||||
return true;
|
||||
|
||||
if (getVSRegistryString("VCExpress", VSVersion, Path, Verbose))
|
||||
return true;
|
||||
|
||||
if (getVSEnvironmentString(VSVersion, Path, Verbose))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get Visual Studio installation directory.
|
||||
static bool getVisualStudioDir(std::string& Path, bool Verbose) {
|
||||
|
||||
#if (_MSC_VER >= 1900)
|
||||
const int VSVersion = 14;
|
||||
#else
|
||||
const int VSVersion = (_MSC_VER / 100) - 6;
|
||||
#endif
|
||||
|
||||
// Try for the version compiled with first
|
||||
if (getVisualStudioVer(VSVersion, Path, Verbose ? "compiled" : nullptr))
|
||||
return true;
|
||||
|
||||
// Check the environment variables that vsvars32.bat sets.
|
||||
// We don't do this first so we can run from other VSStudio shells properly
|
||||
if (const char* VCInstall = ::getenv("VCINSTALLDIR")) {
|
||||
trimString(VCInstall, "\\VC", Path);
|
||||
if (Verbose)
|
||||
llvm::errs() << "Using VCINSTALLDIR '" << VCInstall << "'\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try for any other version we can get
|
||||
const int Versions[] = { 14, 12, 11, 10, 9, 8, 0 };
|
||||
for (unsigned i = 0; Versions[i]; ++i) {
|
||||
if (Versions[i] != VSVersion && getVisualStudioVer(Versions[i], Path,
|
||||
Verbose ? "highest" : nullptr))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
#include <CoreFoundation/CFBase.h> // For MAC_OS_X_VERSION_X_X macros
|
||||
|
||||
// gcc on Mac can only include CoreServices.h up to 10.9 SDK, which means
|
||||
// we cannot use Gestalt to get the running OS version when >= 10.10
|
||||
#if defined(__clang__) || !defined(MAC_OS_X_VERSION_10_10)
|
||||
#include <dlfcn.h> // dlopen to avoid linking with CoreServices
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#else
|
||||
#define CLING_SWVERS_PARSE_ONLY 1
|
||||
#endif
|
||||
|
||||
|
||||
static bool getISysRootVersion(const std::string& SDKs, int Major,
|
||||
int Minor, std::string& SysRoot,
|
||||
const char* Verbose) {
|
||||
std::ostringstream os;
|
||||
os << SDKs << "MacOSX" << Major << "." << Minor << ".sdk";
|
||||
|
||||
std::string SDKv = os.str();
|
||||
if (llvm::sys::fs::is_directory(SDKv)) {
|
||||
SysRoot.swap(SDKv);
|
||||
if (Verbose) {
|
||||
llvm::errs() << "SDK version matching " << Major << "." << Minor
|
||||
<< " found, this does " << Verbose << "\n";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Verbose)
|
||||
llvm::errs() << "SDK version matching " << Major << "." << Minor
|
||||
<< " not found, this would " << Verbose << "\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::string ReadSingleLine(const char* Cmd) {
|
||||
if (FILE* PF = ::popen(Cmd, "r")) {
|
||||
char Buf[1024];
|
||||
char* BufPtr = ::fgets(Buf, sizeof(Buf), PF);
|
||||
::pclose(PF);
|
||||
if (BufPtr && Buf[0]) {
|
||||
const llvm::StringRef Result(Buf);
|
||||
assert(Result[Result.size()-1] == '\n' && "Single line too large");
|
||||
return Result.trim().str();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static bool getISysRoot(std::string& sysRoot, bool Verbose) {
|
||||
using namespace llvm::sys;
|
||||
|
||||
// Some versions of OS X and Server have headers installed
|
||||
if (fs::is_regular_file("/usr/include/stdlib.h"))
|
||||
return false;
|
||||
|
||||
std::string SDKs("/Applications/Xcode.app/Contents/Developer");
|
||||
|
||||
// Is XCode installed where it usually is?
|
||||
if (!fs::is_directory(SDKs)) {
|
||||
// Nope, use xcode-select -p to get the path
|
||||
SDKs = ReadSingleLine("xcode-select -p");
|
||||
if (SDKs.empty())
|
||||
return false; // Nothing more we can do
|
||||
}
|
||||
|
||||
SDKs.append("/Platforms/MacOSX.platform/Developer/SDKs/");
|
||||
if (!fs::is_directory(SDKs))
|
||||
return false;
|
||||
|
||||
|
||||
// Try to get the SDK for whatever version of OS X is currently running
|
||||
// Seems to make more sense to get the currently running SDK so headers
|
||||
// and any loaded libraries will match.
|
||||
|
||||
int32_t majorVers = -1, minorVers = -1;
|
||||
#ifndef CLING_SWVERS_PARSE_ONLY
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
if (void *core = dlopen(
|
||||
"/System/Library/Frameworks/CoreServices.framework/CoreServices",
|
||||
RTLD_LAZY)) {
|
||||
typedef ::OSErr (*GestaltProc)(::OSType, ::SInt32 *);
|
||||
if (GestaltProc Gestalt = (GestaltProc)dlsym(core, "Gestalt")) {
|
||||
if (Gestalt(gestaltSystemVersionMajor, &majorVers) == ::noErr) {
|
||||
if (Gestalt(gestaltSystemVersionMinor, &minorVers) != ::noErr)
|
||||
minorVers = -1;
|
||||
} else
|
||||
majorVers = -1;
|
||||
}
|
||||
::dlclose(core);
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
if (majorVers == -1 || minorVers == -1) {
|
||||
const std::string SWVers = ReadSingleLine("sw_vers | grep ProductVersion"
|
||||
" | awk '{print $2}'");
|
||||
if (!SWVers.empty()) {
|
||||
if (::sscanf(SWVers.c_str(), "%d.%d", &majorVers, &minorVers) != 2) {
|
||||
majorVers = -1;
|
||||
minorVers = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (majorVers != -1 && minorVers != -1) {
|
||||
if (getISysRootVersion(SDKs, majorVers, minorVers, sysRoot,
|
||||
Verbose ? "match the version of OS X running"
|
||||
: nullptr)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define GET_ISYSROOT_VER(maj, min) \
|
||||
if (getISysRootVersion(SDKs, maj, min, sysRoot, Verbose ? \
|
||||
"match what cling was compiled with" : nullptr)) \
|
||||
return true;
|
||||
|
||||
// Try to get the SDK for whatever cling was compiled with
|
||||
#if defined(MAC_OS_X_VERSION_10_11)
|
||||
GET_ISYSROOT_VER(10, 11);
|
||||
#elif defined(MAC_OS_X_VERSION_10_10)
|
||||
GET_ISYSROOT_VER(10, 10);
|
||||
#elif defined(MAC_OS_X_VERSION_10_9)
|
||||
GET_ISYSROOT_VER(10, 9);
|
||||
#elif defined(MAC_OS_X_VERSION_10_8)
|
||||
GET_ISYSROOT_VER(10, 8);
|
||||
#elif defined(MAC_OS_X_VERSION_10_7)
|
||||
GET_ISYSROOT_VER(10, 7);
|
||||
#elif defined(MAC_OS_X_VERSION_10_6)
|
||||
GET_ISYSROOT_VER(10, 6);
|
||||
#elif defined(MAC_OS_X_VERSION_10_5)
|
||||
GET_ISYSROOT_VER(10, 5);
|
||||
#elif defined(MAC_OS_X_VERSION_10_4)
|
||||
GET_ISYSROOT_VER(10, 4);
|
||||
#elif defined(MAC_OS_X_VERSION_10_3)
|
||||
GET_ISYSROOT_VER(10, 3);
|
||||
#elif defined(MAC_OS_X_VERSION_10_2)
|
||||
GET_ISYSROOT_VER(10, 2);
|
||||
#elif defined(MAC_OS_X_VERSION_10_1)
|
||||
GET_ISYSROOT_VER(10, 1);
|
||||
#else // MAC_OS_X_VERSION_10_0
|
||||
GET_ISYSROOT_VER(10, 0);
|
||||
#endif
|
||||
|
||||
#undef GET_ISYSROOT_VER
|
||||
|
||||
// Nothing left to do but iterate the SDKs directory
|
||||
// copy the paths and then sort for the latest
|
||||
std::error_code ec;
|
||||
std::vector<std::string> srtd;
|
||||
for (fs::directory_iterator it(SDKs, ec), e; it != e; it.increment(ec))
|
||||
srtd.push_back(it->path());
|
||||
if (!srtd.empty()) {
|
||||
std::sort(srtd.begin(), srtd.end(), std::greater<std::string>());
|
||||
sysRoot.swap(srtd[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // __APPLE__, _MSC_VER
|
||||
|
||||
using namespace clang;
|
||||
using namespace cling;
|
||||
@ -631,8 +167,11 @@ namespace {
|
||||
|
||||
// When built with access to the proper Windows APIs, try to actually find
|
||||
// the correct include paths first.
|
||||
std::string VSDir;
|
||||
if (getVisualStudioDir(VSDir, Verbose)) {
|
||||
std::string VSDir, WinSDK, UnivSDK;
|
||||
if (platform::GetVisualStudioDirs(VSDir,
|
||||
opts.NoBuiltinInc ? nullptr : &WinSDK,
|
||||
opts.NoBuiltinInc ? nullptr : &UnivSDK,
|
||||
Verbose)) {
|
||||
if (!opts.NoCXXInc) {
|
||||
const std::string VSIncl = VSDir + "\\VC\\include";
|
||||
if (Verbose)
|
||||
@ -640,16 +179,12 @@ namespace {
|
||||
sArguments.addArgument("-I", std::move(VSIncl));
|
||||
}
|
||||
if (!opts.NoBuiltinInc) {
|
||||
std::string WindowsSDKDir;
|
||||
if (getWindowsSDKDir(WindowsSDKDir)) {
|
||||
if (WindowsSDKDir.back() != '\\')
|
||||
WindowsSDKDir += '\\';
|
||||
WindowsSDKDir += "include";
|
||||
if (!WinSDK.empty()) {
|
||||
WinSDK.append("\\include");
|
||||
if (Verbose)
|
||||
llvm::errs() << "Adding Windows SDK: '" << WindowsSDKDir << "'\n";
|
||||
sArguments.addArgument("-I", std::move(WindowsSDKDir));
|
||||
}
|
||||
else {
|
||||
llvm::errs() << "Adding Windows SDK: '" << WinSDK << "'\n";
|
||||
sArguments.addArgument("-I", std::move(WinSDK));
|
||||
} else {
|
||||
VSDir.append("\\VC\\PlatformSDK\\Include");
|
||||
if (Verbose)
|
||||
llvm::errs() << "Adding Platform SDK: '" << VSDir << "'\n";
|
||||
@ -659,17 +194,10 @@ namespace {
|
||||
}
|
||||
|
||||
#if LLVM_MSC_PREREQ(1900)
|
||||
std::string UniversalCRTSdkPath;
|
||||
std::string UCRTVersion;
|
||||
if (getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) {
|
||||
if (UniversalCRTSdkPath.back() != '\\')
|
||||
UniversalCRTSdkPath += '\\';
|
||||
UniversalCRTSdkPath += "Include\\" + UCRTVersion + "\\ucrt";
|
||||
if (Verbose) {
|
||||
llvm::errs() << "Adding UniversalCRT SDK: '"
|
||||
<< UniversalCRTSdkPath << "'\n";
|
||||
}
|
||||
sArguments.addArgument("-I", std::move(UniversalCRTSdkPath));
|
||||
if (!UnivSDK.empty()) {
|
||||
if (Verbose)
|
||||
llvm::errs() << "Adding UniversalCRT SDK: '" << UnivSDK << "'\n";
|
||||
sArguments.addArgument("-I", std::move(UnivSDK));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -747,7 +275,7 @@ namespace {
|
||||
|
||||
if (!opts.NoBuiltinInc && !opts.SysRoot) {
|
||||
std::string sysRoot;
|
||||
if (getISysRoot(sysRoot, Verbose)) {
|
||||
if (platform::GetISysRoot(sysRoot, Verbose)) {
|
||||
if (Verbose)
|
||||
llvm::errs() << "Using SDK \"" << sysRoot << "\"\n";
|
||||
sArguments.addArgument("-isysroot", std::move(sysRoot));
|
||||
@ -1191,12 +719,7 @@ namespace {
|
||||
// name), clang will call $PWD "." which is terrible if we ever change
|
||||
// directories (see ROOT-7114). By asking for $PWD (and not ".") it will
|
||||
// be registered as $PWD instead, which is stable even after chdirs.
|
||||
char cwdbuf[2048];
|
||||
if (!getcwd_func(cwdbuf, sizeof(cwdbuf))) {
|
||||
// getcwd can fail, but that shouldn't mean we have to.
|
||||
::perror("Could not get current working directory");
|
||||
} else
|
||||
FM.getDirectory(cwdbuf);
|
||||
FM.getDirectory(platform::GetCwd());
|
||||
|
||||
// Build the virtual file, Give it a name that's likely not to ever
|
||||
// be #included (so we won't get a clash in clangs cache).
|
||||
|
@ -12,6 +12,9 @@ set( LLVM_LINK_COMPONENTS
|
||||
add_cling_library(clingUtils OBJECT
|
||||
AST.cpp
|
||||
Paths.cpp
|
||||
PlatformMac.cpp
|
||||
PlatformPosix.cpp
|
||||
PlatformWin.cpp
|
||||
SourceNormalization.cpp
|
||||
Validation.cpp
|
||||
|
||||
|
199
lib/Utils/PlatformMac.cpp
Normal file
199
lib/Utils/PlatformMac.cpp
Normal file
@ -0,0 +1,199 @@
|
||||
//--------------------------------------------------------------------*- C++ -*-
|
||||
// CLING - the C++ LLVM-based InterpreterG :)
|
||||
// author: Roman Zulak
|
||||
//
|
||||
// This file is dual-licensed: you can choose to license it under the University
|
||||
// of Illinois Open Source License or the GNU Lesser General Public License. See
|
||||
// LICENSE.TXT for details.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "cling/Utils/Platform.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#include "cling/Utils/Paths.h"
|
||||
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <CoreFoundation/CFBase.h> // For MAC_OS_X_VERSION_X_X macros
|
||||
|
||||
// gcc on Mac can only include CoreServices.h up to 10.9 SDK, which means
|
||||
// we cannot use Gestalt to get the running OS version when >= 10.10
|
||||
#if defined(__clang__) || !defined(MAC_OS_X_VERSION_10_10)
|
||||
#include <dlfcn.h> // dlopen to avoid linking with CoreServices
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#else
|
||||
#define CLING_SWVERS_PARSE_ONLY 1
|
||||
#endif
|
||||
|
||||
namespace cling {
|
||||
namespace utils {
|
||||
namespace platform {
|
||||
inline namespace osx {
|
||||
|
||||
namespace {
|
||||
|
||||
static bool getISysRootVersion(const std::string& SDKs, int Major,
|
||||
int Minor, std::string& SysRoot,
|
||||
const char* Verbose) {
|
||||
std::ostringstream os;
|
||||
os << SDKs << "MacOSX" << Major << "." << Minor << ".sdk";
|
||||
|
||||
std::string SDKv = os.str();
|
||||
if (llvm::sys::fs::is_directory(SDKv)) {
|
||||
SysRoot.swap(SDKv);
|
||||
if (Verbose) {
|
||||
llvm::errs() << "SDK version matching " << Major << "." << Minor
|
||||
<< " found, this does " << Verbose << "\n";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Verbose)
|
||||
llvm::errs() << "SDK version matching " << Major << "." << Minor
|
||||
<< " not found, this would " << Verbose << "\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::string ReadSingleLine(const char* Cmd) {
|
||||
if (FILE* PF = ::popen(Cmd, "r")) {
|
||||
char Buf[1024];
|
||||
char* BufPtr = ::fgets(Buf, sizeof(Buf), PF);
|
||||
::pclose(PF);
|
||||
if (BufPtr && Buf[0]) {
|
||||
const llvm::StringRef Result(Buf);
|
||||
assert(Result[Result.size()-1] == '\n' && "Single line too large");
|
||||
return Result.trim().str();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
bool GetISysRoot(std::string& sysRoot, bool Verbose) {
|
||||
using namespace llvm::sys;
|
||||
|
||||
// Some versions of OS X and Server have headers installed
|
||||
if (fs::is_regular_file("/usr/include/stdlib.h"))
|
||||
return false;
|
||||
|
||||
std::string SDKs("/Applications/Xcode.app/Contents/Developer");
|
||||
|
||||
// Is XCode installed where it usually is?
|
||||
if (!fs::is_directory(SDKs)) {
|
||||
// Nope, use xcode-select -p to get the path
|
||||
SDKs = ReadSingleLine("xcode-select -p");
|
||||
if (SDKs.empty())
|
||||
return false; // Nothing more we can do
|
||||
}
|
||||
|
||||
SDKs.append("/Platforms/MacOSX.platform/Developer/SDKs/");
|
||||
if (!fs::is_directory(SDKs))
|
||||
return false;
|
||||
|
||||
|
||||
// Try to get the SDK for whatever version of OS X is currently running
|
||||
// Seems to make more sense to get the currently running SDK so headers
|
||||
// and any loaded libraries will match.
|
||||
|
||||
int32_t majorVers = -1, minorVers = -1;
|
||||
#ifndef CLING_SWVERS_PARSE_ONLY
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
if (void *core = ::dlopen(
|
||||
"/System/Library/Frameworks/CoreServices.framework/CoreServices",
|
||||
RTLD_LAZY)) {
|
||||
typedef ::OSErr (*GestaltProc)(::OSType, ::SInt32 *);
|
||||
if (GestaltProc Gestalt = (GestaltProc)dlsym(core, "Gestalt")) {
|
||||
if (Gestalt(gestaltSystemVersionMajor, &majorVers) == ::noErr) {
|
||||
if (Gestalt(gestaltSystemVersionMinor, &minorVers) != ::noErr)
|
||||
minorVers = -1;
|
||||
} else
|
||||
majorVers = -1;
|
||||
}
|
||||
::dlclose(core);
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
if (majorVers == -1 || minorVers == -1) {
|
||||
const std::string SWVers = ReadSingleLine("sw_vers | grep ProductVersion"
|
||||
" | awk '{print $2}'");
|
||||
if (!SWVers.empty()) {
|
||||
if (::sscanf(SWVers.c_str(), "%d.%d", &majorVers, &minorVers) != 2) {
|
||||
majorVers = -1;
|
||||
minorVers = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (majorVers != -1 && minorVers != -1) {
|
||||
if (getISysRootVersion(SDKs, majorVers, minorVers, sysRoot,
|
||||
Verbose ? "match the version of OS X running"
|
||||
: nullptr)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define GET_ISYSROOT_VER(maj, min) \
|
||||
if (getISysRootVersion(SDKs, maj, min, sysRoot, Verbose ? \
|
||||
"match what cling was compiled with" : nullptr)) \
|
||||
return true;
|
||||
|
||||
// Try to get the SDK for whatever cling was compiled with
|
||||
#if defined(MAC_OS_X_VERSION_10_11)
|
||||
GET_ISYSROOT_VER(10, 11);
|
||||
#elif defined(MAC_OS_X_VERSION_10_10)
|
||||
GET_ISYSROOT_VER(10, 10);
|
||||
#elif defined(MAC_OS_X_VERSION_10_9)
|
||||
GET_ISYSROOT_VER(10, 9);
|
||||
#elif defined(MAC_OS_X_VERSION_10_8)
|
||||
GET_ISYSROOT_VER(10, 8);
|
||||
#elif defined(MAC_OS_X_VERSION_10_7)
|
||||
GET_ISYSROOT_VER(10, 7);
|
||||
#elif defined(MAC_OS_X_VERSION_10_6)
|
||||
GET_ISYSROOT_VER(10, 6);
|
||||
#elif defined(MAC_OS_X_VERSION_10_5)
|
||||
GET_ISYSROOT_VER(10, 5);
|
||||
#elif defined(MAC_OS_X_VERSION_10_4)
|
||||
GET_ISYSROOT_VER(10, 4);
|
||||
#elif defined(MAC_OS_X_VERSION_10_3)
|
||||
GET_ISYSROOT_VER(10, 3);
|
||||
#elif defined(MAC_OS_X_VERSION_10_2)
|
||||
GET_ISYSROOT_VER(10, 2);
|
||||
#elif defined(MAC_OS_X_VERSION_10_1)
|
||||
GET_ISYSROOT_VER(10, 1);
|
||||
#else // MAC_OS_X_VERSION_10_0
|
||||
GET_ISYSROOT_VER(10, 0);
|
||||
#endif
|
||||
|
||||
#undef GET_ISYSROOT_VER
|
||||
|
||||
// Nothing left to do but iterate the SDKs directory
|
||||
// copy the paths and then sort for the latest
|
||||
std::error_code ec;
|
||||
std::vector<std::string> srtd;
|
||||
for (fs::directory_iterator it(SDKs, ec), e; it != e; it.increment(ec))
|
||||
srtd.push_back(it->path());
|
||||
if (!srtd.empty()) {
|
||||
std::sort(srtd.begin(), srtd.end(), std::greater<std::string>());
|
||||
sysRoot.swap(srtd[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
} // namespace osx
|
||||
} // namespace platform
|
||||
} // namespace utils
|
||||
} // namespace cling
|
||||
|
||||
#endif // __APPLE__
|
41
lib/Utils/PlatformPosix.cpp
Normal file
41
lib/Utils/PlatformPosix.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
//--------------------------------------------------------------------*- C++ -*-
|
||||
// CLING - the C++ LLVM-based InterpreterG :)
|
||||
// author: Roman Zulak
|
||||
//
|
||||
// This file is dual-licensed: you can choose to license it under the University
|
||||
// of Illinois Open Source License or the GNU Lesser General Public License. See
|
||||
// LICENSE.TXT for details.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "cling/Utils/Platform.h"
|
||||
|
||||
#if defined(LLVM_ON_UNIX)
|
||||
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
|
||||
// PATH_MAX
|
||||
#ifdef __APPLE__
|
||||
#include <sys/syslimits.h>
|
||||
#else
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
namespace cling {
|
||||
namespace utils {
|
||||
namespace platform {
|
||||
|
||||
std::string GetCwd() {
|
||||
char Buffer[PATH_MAX+1];
|
||||
if (::getcwd(Buffer, sizeof(Buffer)))
|
||||
return Buffer;
|
||||
|
||||
::perror("Could not get current working directory");
|
||||
return std::string();
|
||||
}
|
||||
|
||||
} // namespace platform
|
||||
} // namespace utils
|
||||
} // namespace cling
|
||||
|
||||
#endif // LLVM_ON_UNIX
|
432
lib/Utils/PlatformWin.cpp
Normal file
432
lib/Utils/PlatformWin.cpp
Normal file
@ -0,0 +1,432 @@
|
||||
//--------------------------------------------------------------------*- C++ -*-
|
||||
// CLING - the C++ LLVM-based InterpreterG :)
|
||||
// author: Roman Zulak
|
||||
//
|
||||
// This file is dual-licensed: you can choose to license it under the University
|
||||
// of Illinois Open Source License or the GNU Lesser General Public License. See
|
||||
// LICENSE.TXT for details.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "cling/Utils/Platform.h"
|
||||
|
||||
#if defined(LLVM_ON_WIN32)
|
||||
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/ConvertUTF.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#ifndef NOGDI
|
||||
#define NOGDI
|
||||
#endif
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include <Windows.h>
|
||||
#include <Psapi.h> // EnumProcessModulesEx
|
||||
#include <direct.h> // _getcwd
|
||||
#pragma comment(lib, "Advapi32.lib")
|
||||
|
||||
// This is how MSDN does it
|
||||
#define MAX_PATH (_MAX_PATH + 1)
|
||||
|
||||
namespace cling {
|
||||
namespace utils {
|
||||
namespace platform {
|
||||
|
||||
std::string GetCwd() {
|
||||
char Buffer[MAX_PATH];
|
||||
if (::_getcwd(Buffer, sizeof(Buffer)))
|
||||
return Buffer;
|
||||
|
||||
::perror("Could not get current working directory");
|
||||
return std::string();
|
||||
}
|
||||
|
||||
inline namespace windows {
|
||||
|
||||
static void GetErrorAsString(DWORD Err, std::string& ErrStr, const char* Prefix) {
|
||||
llvm::raw_string_ostream Strm(ErrStr);
|
||||
if (Prefix)
|
||||
Strm << Prefix << ": returned " << Err << " ";
|
||||
|
||||
LPTSTR Message = nullptr;
|
||||
const DWORD Size = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, Err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&Message, 0, nullptr);
|
||||
|
||||
if (Size && Message) {
|
||||
Strm << Message;
|
||||
::LocalFree(Message);
|
||||
ErrStr = llvm::StringRef(Strm.str()).rtrim().str();
|
||||
}
|
||||
}
|
||||
|
||||
static void ReportError(DWORD Err, const char* Prefix) {
|
||||
std::string Message;
|
||||
GetErrorAsString(Err, Message, Prefix);
|
||||
llvm::errs() << Err << '\n';
|
||||
}
|
||||
|
||||
bool GetLastErrorAsString(std::string& ErrStr, const char* Prefix) {
|
||||
if (const DWORD Err = ::GetLastError()) {
|
||||
GetErrorAsString(Err, ErrStr, Prefix);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReportLastError(const char* Prefix) {
|
||||
if (const DWORD Err = ::GetLastError()) {
|
||||
ReportError(Err, Prefix);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Taken from clang/lib/Driver/MSVCToolChain.cpp
|
||||
static bool readFullStringValue(HKEY hkey, const char *valueName,
|
||||
std::string &value) {
|
||||
std::wstring WideValueName;
|
||||
if (!llvm::ConvertUTF8toWide(valueName, WideValueName))
|
||||
return false;
|
||||
|
||||
// First just query for the required size.
|
||||
DWORD valueSize = 0, type = 0;
|
||||
DWORD result = ::RegQueryValueExW(hkey, WideValueName.c_str(), NULL, &type,
|
||||
NULL, &valueSize);
|
||||
if (result == ERROR_SUCCESS) {
|
||||
if (type != REG_SZ || !valueSize)
|
||||
return false;
|
||||
|
||||
llvm::SmallVector<wchar_t, MAX_PATH> buffer;
|
||||
buffer.resize(valueSize/sizeof(wchar_t));
|
||||
result = ::RegQueryValueExW(hkey, WideValueName.c_str(), NULL, NULL,
|
||||
reinterpret_cast<BYTE*>(&buffer[0]), &valueSize);
|
||||
if (result == ERROR_SUCCESS) {
|
||||
// String might be null terminated, which we don't want
|
||||
while (!buffer.empty() && buffer.back() == 0)
|
||||
buffer.pop_back();
|
||||
|
||||
std::wstring WideValue(buffer.data(), buffer.size());
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
ReportError(result, "RegQueryValueEx");
|
||||
return false;
|
||||
}
|
||||
|
||||
static void logSearch(const char* Name, const std::string& Value,
|
||||
const char* Found = nullptr) {
|
||||
if (Found)
|
||||
llvm::errs() << "Found " << Name << " '" << Value << "' that matches "
|
||||
<< Found << " version\n";
|
||||
else
|
||||
llvm::errs() << Name << " '" << Value << "' not found.\n";
|
||||
}
|
||||
|
||||
static void trimString(const char* Value, const char* Sub, std::string& Out) {
|
||||
const char* End = ::strstr(Value, Sub);
|
||||
Out = End ? std::string(Value, End) : Value;
|
||||
}
|
||||
|
||||
static bool getVSRegistryString(const char* Product, int VSVersion,
|
||||
std::string& Path, const char* Verbose) {
|
||||
std::ostringstream Key;
|
||||
Key << "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" << Product << "\\"
|
||||
<< VSVersion << ".0";
|
||||
|
||||
std::string IDEInstallDir;
|
||||
if (!GetSystemRegistryString(Key.str().c_str(), "InstallDir", IDEInstallDir)
|
||||
|| IDEInstallDir.empty()) {
|
||||
if (Verbose)
|
||||
logSearch("Registry", Key.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
trimString(IDEInstallDir.c_str(), "\\Common7\\IDE", Path);
|
||||
if (Verbose)
|
||||
logSearch("Registry", Key.str(), Verbose);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool getVSEnvironmentString(int VSVersion, std::string& Path,
|
||||
const char* Verbose) {
|
||||
std::ostringstream Key;
|
||||
Key << "VS" << VSVersion * 10 << "COMNTOOLS";
|
||||
const char* Tools = ::getenv(Key.str().c_str());
|
||||
if (!Tools) {
|
||||
if (Verbose)
|
||||
logSearch("Environment", Key.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
trimString(Tools, "\\Common7\\Tools", Path);
|
||||
if (Verbose)
|
||||
logSearch("Environment", Key.str(), Verbose);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool getVisualStudioVer(int VSVersion, std::string& Path,
|
||||
const char* Verbose) {
|
||||
if (getVSRegistryString("VisualStudio", VSVersion, Path, Verbose))
|
||||
return true;
|
||||
|
||||
if (getVSRegistryString("VCExpress", VSVersion, Path, Verbose))
|
||||
return true;
|
||||
|
||||
if (getVSEnvironmentString(VSVersion, Path, Verbose))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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(std::string& SDKPath,
|
||||
std::string& SDKVersion) {
|
||||
SDKVersion.clear();
|
||||
|
||||
std::error_code EC;
|
||||
llvm::SmallString<MAX_PATH> 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;
|
||||
llvm::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) {
|
||||
SDKPath = DirIt->path();
|
||||
SDKVersion = CandidateName;
|
||||
}
|
||||
}
|
||||
return !SDKVersion.empty();
|
||||
}
|
||||
|
||||
static bool getUniversalCRTSdkDir(std::string& Path,
|
||||
std::string& UCRTVersion) {
|
||||
// vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry
|
||||
// for the specific key "KitsRoot10". So do we.
|
||||
if (!GetSystemRegistryString("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
|
||||
"Windows Kits\\Installed Roots", "KitsRoot10",
|
||||
Path))
|
||||
return false;
|
||||
|
||||
return getWindows10SDKVersion(Path, UCRTVersion);
|
||||
}
|
||||
|
||||
bool getWindowsSDKDir(std::string& WindowsSDK) {
|
||||
return GetSystemRegistryString("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
|
||||
"Microsoft SDKs\\Windows\\$VERSION",
|
||||
"InstallationFolder", WindowsSDK);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
bool GetSystemRegistryString(const char *keyPath, const char *valueName,
|
||||
std::string& outValue) {
|
||||
HKEY hRootKey = NULL;
|
||||
const char* subKey = NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
long lResult;
|
||||
bool returnValue = false;
|
||||
HKEY hKey = NULL;
|
||||
|
||||
// If we have a $VERSION placeholder, do the highest-version search.
|
||||
if (const char *placeHolder = ::strstr(subKey, "$VERSION")) {
|
||||
char bestName[256];
|
||||
bestName[0] = '\0';
|
||||
|
||||
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 = ::RegOpenKeyExA(hRootKey, partialKey, 0,
|
||||
KEY_READ | KEY_WOW64_32KEY, &hTopKey);
|
||||
if (lResult == ERROR_SUCCESS) {
|
||||
char keyName[256];
|
||||
// int bestIndex = -1;
|
||||
double bestValue = 0.0;
|
||||
DWORD size = sizeof(keyName) - 1;
|
||||
for (DWORD 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.
|
||||
::strcpy(bestName, keyName);
|
||||
// Append rest of key.
|
||||
::strncat(bestName, nextKey, sizeof(bestName) - 1);
|
||||
bestName[sizeof(bestName) - 1] = '\0';
|
||||
lResult = ::RegOpenKeyExA(hTopKey, bestName, 0,
|
||||
KEY_READ | KEY_WOW64_32KEY, &hKey);
|
||||
if (lResult == ERROR_SUCCESS) {
|
||||
if (readFullStringValue(hKey, valueName, outValue)) {
|
||||
// bestIndex = (int)index;
|
||||
bestValue = dvalue;
|
||||
returnValue = true;
|
||||
}
|
||||
::RegCloseKey(hKey);
|
||||
}
|
||||
}
|
||||
size = sizeof(keyName) - 1;
|
||||
}
|
||||
::RegCloseKey(hTopKey);
|
||||
} else
|
||||
ReportError(lResult, "RegOpenKeyEx");
|
||||
} else {
|
||||
lResult = ::RegOpenKeyExA(hRootKey, subKey, 0, KEY_READ | KEY_WOW64_32KEY,
|
||||
&hKey);
|
||||
if (lResult == ERROR_SUCCESS) {
|
||||
returnValue = readFullStringValue(hKey, valueName, outValue);
|
||||
::RegCloseKey(hKey);
|
||||
} else
|
||||
ReportError(lResult, "RegOpenKeyEx");
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
int GetVisualStudioVersionCompiledWith() {
|
||||
#if (_MSC_VER >= 1900)
|
||||
return 14;
|
||||
#endif
|
||||
return (_MSC_VER / 100) - 6;
|
||||
}
|
||||
|
||||
static void fixupPath(std::string& Path, const char* Append = nullptr) {
|
||||
const char kSep = '\\';
|
||||
if (Append) {
|
||||
if (Path.empty())
|
||||
return;
|
||||
if (Path.back() != kSep)
|
||||
Path.append(1, kSep);
|
||||
Path.append(Append);
|
||||
}
|
||||
else {
|
||||
while (!Path.empty() && Path.back() == kSep)
|
||||
Path.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
bool GetVisualStudioDirs(std::string& Path, std::string* WinSDK,
|
||||
std::string* UniversalSDK, bool Verbose) {
|
||||
|
||||
if (WinSDK) {
|
||||
if (!getWindowsSDKDir(*WinSDK)) {
|
||||
WinSDK->clear();
|
||||
if (Verbose)
|
||||
llvm::errs() << "Could not get Windows SDK path\n";
|
||||
} else
|
||||
fixupPath(*WinSDK);
|
||||
}
|
||||
|
||||
if (UniversalSDK) {
|
||||
std::string UCRTVersion;
|
||||
if (!getUniversalCRTSdkDir(*UniversalSDK, UCRTVersion)) {
|
||||
UniversalSDK->clear();
|
||||
if (Verbose)
|
||||
llvm::errs() << "Could not get Universal SDK path\n";
|
||||
} else
|
||||
fixupPath(*UniversalSDK, "ucrt");
|
||||
}
|
||||
|
||||
const char* Msg = Verbose ? "compiled" : nullptr;
|
||||
|
||||
// Try for the version compiled with first
|
||||
const int VSVersion = GetVisualStudioVersionCompiledWith();
|
||||
if (getVisualStudioVer(VSVersion, Path, Msg)) {
|
||||
fixupPath(Path);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check the environment variables that vsvars32.bat sets.
|
||||
// We don't do this first so we can run from other VSStudio shells properly
|
||||
if (const char* VCInstall = ::getenv("VCINSTALLDIR")) {
|
||||
trimString(VCInstall, "\\VC", Path);
|
||||
if (Verbose)
|
||||
llvm::errs() << "Using VCINSTALLDIR '" << VCInstall << "'\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try for any other version we can get
|
||||
Msg = Verbose ? "highest" : nullptr;
|
||||
const int Versions[] = { 14, 12, 11, 10, 9, 8, 0 };
|
||||
for (unsigned i = 0; Versions[i]; ++i) {
|
||||
if (Versions[i] != VSVersion && getVisualStudioVer(Versions[i], Path, Msg)) {
|
||||
fixupPath(Path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace windows
|
||||
} // namespace platform
|
||||
} // namespace utils
|
||||
} // namespace cling
|
||||
|
||||
#endif // LLVM_ON_WIN32
|
Loading…
x
Reference in New Issue
Block a user