aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorIvan Komissarov <ABBAPOH@gmail.com>2019-03-19 22:24:33 +0100
committerIvan Komissarov <ABBAPOH@gmail.com>2019-04-10 07:27:02 +0000
commit62e07306481373d9d9b6b656d855b204aa6964f3 (patch)
treedac1f681be32eaba98b117a481a9011500af9b91 /src/lib
parent14324ad4aa9582e07dc687dc63b1b886f2d272e5 (diff)
Add support for the clang-cl compiler
Task-number: QBS-1316 Change-Id: Ibf9da364610c260ead088a8990a70c7739d53c39 Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/corelib/jsextensions/utilitiesextension.cpp97
-rw-r--r--src/lib/corelib/tools/hostosinfo.h9
-rw-r--r--src/lib/corelib/tools/msvcinfo.cpp80
-rw-r--r--src/lib/corelib/tools/msvcinfo.h9
-rw-r--r--src/lib/corelib/tools/vsenvironmentdetector.cpp13
-rw-r--r--src/lib/corelib/tools/vsenvironmentdetector.h3
6 files changed, 180 insertions, 31 deletions
diff --git a/src/lib/corelib/jsextensions/utilitiesextension.cpp b/src/lib/corelib/jsextensions/utilitiesextension.cpp
index 5abaccad9..62778665c 100644
--- a/src/lib/corelib/jsextensions/utilitiesextension.cpp
+++ b/src/lib/corelib/jsextensions/utilitiesextension.cpp
@@ -109,6 +109,7 @@ public:
static QScriptValue js_certificateInfo(QScriptContext *context, QScriptEngine *engine);
static QScriptValue js_signingIdentities(QScriptContext *context, QScriptEngine *engine);
static QScriptValue js_msvcCompilerInfo(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue js_clangClCompilerInfo(QScriptContext *context, QScriptEngine *engine);
static QScriptValue js_versionCompare(QScriptContext *context, QScriptEngine *engine);
@@ -455,6 +456,37 @@ QScriptValue UtilitiesExtension::js_signingIdentities(QScriptContext *context,
#endif
}
+#ifdef Q_OS_WIN
+static std::pair<QVariantMap /*result*/, QString /*error*/> msvcCompilerInfoHelper(
+ const QString &compilerFilePath,
+ MSVC::CompilerLanguage language,
+ const QString &vcvarsallPath,
+ const QString &arch)
+{
+ MSVC msvc(compilerFilePath, arch);
+ VsEnvironmentDetector envdetector(vcvarsallPath);
+ if (!envdetector.start(&msvc))
+ return { {}, QStringLiteral("Detecting the MSVC build environment failed: ")
+ + envdetector.errorString() };
+
+ try {
+ QVariantMap envMap;
+ for (const QString &key : msvc.environment.keys())
+ envMap.insert(key, msvc.environment.value(key));
+
+ return {
+ QVariantMap {
+ {QStringLiteral("buildEnvironment"), envMap},
+ {QStringLiteral("macros"), msvc.compilerDefines(compilerFilePath, language)},
+ },
+ {}
+ };
+ } catch (const qbs::ErrorInfo &info) {
+ return { {}, info.toString() };
+ }
+}
+#endif
+
QScriptValue UtilitiesExtension::js_msvcCompilerInfo(QScriptContext *context, QScriptEngine *engine)
{
#ifndef Q_OS_WIN
@@ -462,14 +494,12 @@ QScriptValue UtilitiesExtension::js_msvcCompilerInfo(QScriptContext *context, QS
return context->throwError(QScriptContext::UnknownError,
QStringLiteral("msvcCompilerInfo is not available on this platform"));
#else
- if (Q_UNLIKELY(context->argumentCount() < 1))
+ if (Q_UNLIKELY(context->argumentCount() < 2))
return context->throwError(QScriptContext::SyntaxError,
- QStringLiteral("msvcCompilerInfo expects at least 1 argument"));
+ QStringLiteral("msvcCompilerInfo expects 2 arguments"));
const QString compilerFilePath = context->argument(0).toString();
- const QString compilerLanguage = context->argumentCount() > 1
- ? context->argument(1).toString()
- : QString();
+ const QString compilerLanguage = context->argument(1).toString();
MSVC::CompilerLanguage language;
if (compilerLanguage == QStringLiteral("c"))
language = MSVC::CLanguage;
@@ -479,26 +509,45 @@ QScriptValue UtilitiesExtension::js_msvcCompilerInfo(QScriptContext *context, QS
return context->throwError(QScriptContext::TypeError,
QStringLiteral("msvcCompilerInfo expects \"c\" or \"cpp\" as its second argument"));
- MSVC msvc(compilerFilePath);
- VsEnvironmentDetector envdetector;
- if (!envdetector.start(&msvc))
- return context->throwError(QScriptContext::UnknownError,
- QStringLiteral("Detecting the MSVC build environment failed: ")
- + envdetector.errorString());
+ const auto result = msvcCompilerInfoHelper(
+ compilerFilePath, language, {}, MSVC::architectureFromClPath(compilerFilePath));
+ if (result.first.isEmpty())
+ return context->throwError(QScriptContext::UnknownError, result.second);
+ return engine->toScriptValue(result.first);
+#endif
+}
- try {
- QVariantMap envMap;
- for (const QString &key : msvc.environment.keys())
- envMap.insert(key, msvc.environment.value(key));
+QScriptValue UtilitiesExtension::js_clangClCompilerInfo(QScriptContext *context, QScriptEngine *engine)
+{
+#ifndef Q_OS_WIN
+ Q_UNUSED(engine);
+ return context->throwError(QScriptContext::UnknownError,
+ QStringLiteral("clangClCompilerInfo is not available on this platform"));
+#else
+ if (Q_UNLIKELY(context->argumentCount() < 4))
+ return context->throwError(QScriptContext::SyntaxError,
+ QStringLiteral("clangClCompilerInfo expects 4 arguments"));
- return engine->toScriptValue(QVariantMap {
- {QStringLiteral("buildEnvironment"), envMap},
- {QStringLiteral("macros"), msvc.compilerDefines(compilerFilePath, language)},
- });
- } catch (const qbs::ErrorInfo &info) {
- return context->throwError(QScriptContext::UnknownError,
- info.toString());
- }
+ const QString compilerFilePath = context->argument(0).toString();
+ QString arch = context->argument(1).toString();
+ QString vcvarsallPath = context->argument(2).toString();
+ const QString compilerLanguage = context->argumentCount() > 3
+ ? context->argument(3).toString()
+ : QString();
+ MSVC::CompilerLanguage language;
+ if (compilerLanguage == QStringLiteral("c"))
+ language = MSVC::CLanguage;
+ else if (compilerLanguage == StringConstants::cppLang())
+ language = MSVC::CPlusPlusLanguage;
+ else
+ return context->throwError(QScriptContext::TypeError,
+ QStringLiteral("clangClCompilerInfo expects \"c\" or \"cpp\" as its fourth argument"));
+
+ const auto result = msvcCompilerInfoHelper(
+ compilerFilePath, language, vcvarsallPath, arch);
+ if (result.first.isEmpty())
+ return context->throwError(QScriptContext::UnknownError, result.second);
+ return engine->toScriptValue(result.first);
#endif
}
@@ -800,6 +849,8 @@ void initializeJsExtensionUtilities(QScriptValue extensionObject)
engine->newFunction(UtilitiesExtension::js_signingIdentities, 0));
environmentObj.setProperty(QStringLiteral("msvcCompilerInfo"),
engine->newFunction(UtilitiesExtension::js_msvcCompilerInfo, 1));
+ environmentObj.setProperty(QStringLiteral("clangClCompilerInfo"),
+ engine->newFunction(UtilitiesExtension::js_clangClCompilerInfo, 1));
environmentObj.setProperty(QStringLiteral("versionCompare"),
engine->newFunction(UtilitiesExtension::js_versionCompare, 2));
environmentObj.setProperty(QStringLiteral("qmlTypeInfo"),
diff --git a/src/lib/corelib/tools/hostosinfo.h b/src/lib/corelib/tools/hostosinfo.h
index cae451638..d7f718c19 100644
--- a/src/lib/corelib/tools/hostosinfo.h
+++ b/src/lib/corelib/tools/hostosinfo.h
@@ -74,6 +74,7 @@ public:
enum HostOs { HostOsWindows, HostOsLinux, HostOsMacos, HostOsOtherUnix, HostOsOther };
static inline std::string hostOSIdentifier();
+ static inline std::string hostOSArchitecture();
static inline std::vector<std::string> hostOSIdentifiers();
static inline std::vector<std::string> canonicalOSIdentifiers(const std::string &os);
static inline HostOs hostOs();
@@ -177,6 +178,14 @@ std::string HostOsInfo::hostOSIdentifier()
#endif
}
+std::string HostOsInfo::hostOSArchitecture()
+{
+ const auto cpuArch = QSysInfo::currentCpuArchitecture();
+ if (cpuArch == QLatin1String("i386"))
+ return "x86";
+ return cpuArch.toStdString();
+}
+
std::vector<std::string> HostOsInfo::hostOSIdentifiers()
{
return canonicalOSIdentifiers(hostOSIdentifier());
diff --git a/src/lib/corelib/tools/msvcinfo.cpp b/src/lib/corelib/tools/msvcinfo.cpp
index c1312c8c9..cffec85b2 100644
--- a/src/lib/corelib/tools/msvcinfo.cpp
+++ b/src/lib/corelib/tools/msvcinfo.cpp
@@ -198,11 +198,88 @@ static QVariantMap getMsvcDefines(const QString &compilerFilePath,
#endif
}
+/*!
+ \internal
+ clang-cl does not support gcc and msvc ways to dump a macros, so we have to use original
+ clang.exe directly
+*/
+static QVariantMap getClangClDefines(
+ const QString &compilerFilePath,
+ const QProcessEnvironment &compilerEnv,
+ MSVC::CompilerLanguage language)
+{
+#ifdef Q_OS_WIN
+ QFileInfo clInfo(compilerFilePath);
+ QFileInfo clangInfo(clInfo.absolutePath() + QLatin1String("/clang.exe"));
+ if (!clangInfo.exists())
+ throw ErrorInfo(QStringLiteral("%1 does not exist").arg(clangInfo.absoluteFilePath()));
+
+ QString languageSwitch;
+ switch (language) {
+ case MSVC::CLanguage:
+ languageSwitch = QStringLiteral("c");
+ break;
+ case MSVC::CPlusPlusLanguage:
+ languageSwitch = QStringLiteral("c++");
+ break;
+ }
+ QStringList args = {
+ QStringLiteral("-dM"),
+ QStringLiteral("-E"),
+ QStringLiteral("-x"),
+ languageSwitch,
+ QStringLiteral("NUL"),
+ };
+ const auto lines = QString::fromLocal8Bit(
+ runProcess(
+ clangInfo.absoluteFilePath(),
+ args,
+ compilerEnv,
+ true)).split(QLatin1Char('\n'));
+ QVariantMap result;
+ for (const auto &line: lines) {
+ static const auto defineString = QLatin1String("#define ");
+ if (!line.startsWith(defineString)) {
+ throw ErrorInfo(QStringLiteral("Unexpected compiler frontend output: ")
+ + lines.join(QLatin1Char('\n')));
+ }
+ QStringView view(line.data() + defineString.size());
+ const auto it = std::find(view.begin(), view.end(), QLatin1Char(' '));
+ if (it == view.end()) {
+ throw ErrorInfo(QStringLiteral("Unexpected compiler frontend output: ")
+ + lines.join(QLatin1Char('\n')));
+ }
+ QStringView key(view.begin(), it);
+ QStringView value(it + 1, view.end());
+ result.insert(key.toString(), value.isEmpty() ? QVariant() : QVariant(value.toString()));
+ }
+ return result;
+#else
+ Q_UNUSED(compilerFilePath);
+ Q_UNUSED(compilerEnv);
+ Q_UNUSED(language);
+ return {};
+#endif
+}
+
void MSVC::init()
{
determineCompilerVersion();
}
+/*!
+ \internal
+ Returns the architecture detected from the compiler path.
+*/
+QString MSVC::architectureFromClPath(const QString &clPath)
+{
+ const auto parentDir = QFileInfo(clPath).absolutePath();
+ const auto parentDirName = QFileInfo(parentDir).fileName().toLower();
+ if (parentDirName == QLatin1String("bin"))
+ return QStringLiteral("x86");
+ return parentDirName;
+}
+
QString MSVC::binPathForArchitecture(const QString &arch) const
{
QString archSubDir;
@@ -222,6 +299,9 @@ QString MSVC::clPathForArchitecture(const QString &arch) const
QVariantMap MSVC::compilerDefines(const QString &compilerFilePath,
MSVC::CompilerLanguage language) const
{
+ const auto compilerName = QFileInfo(compilerFilePath).fileName().toLower();
+ if (compilerName == QLatin1String("clang-cl.exe"))
+ return getClangClDefines(compilerFilePath, environment, language);
return getMsvcDefines(compilerFilePath, environment, language);
}
diff --git a/src/lib/corelib/tools/msvcinfo.h b/src/lib/corelib/tools/msvcinfo.h
index 61a19dc4f..5f542fc97 100644
--- a/src/lib/corelib/tools/msvcinfo.h
+++ b/src/lib/corelib/tools/msvcinfo.h
@@ -77,20 +77,19 @@ public:
MSVC() { }
- MSVC(const QString &clPath)
+ MSVC(const QString &clPath, QString arch):
+ architecture(std::move(arch))
{
QDir parentDir = QFileInfo(clPath).dir();
binPath = parentDir.absolutePath();
QString parentDirName = parentDir.dirName().toLower();
- if (parentDirName == QLatin1String("bin"))
- parentDirName = QStringLiteral("x86");
- else
+ if (parentDirName != QLatin1String("bin"))
parentDir.cdUp();
- architecture = parentDirName;
vcInstallPath = parentDir.path();
}
QBS_EXPORT void init();
+ QBS_EXPORT static QString architectureFromClPath(const QString &clPath);
QBS_EXPORT QString binPathForArchitecture(const QString &arch) const;
QBS_EXPORT QString clPathForArchitecture(const QString &arch) const;
QBS_EXPORT QVariantMap compilerDefines(const QString &compilerFilePath,
diff --git a/src/lib/corelib/tools/vsenvironmentdetector.cpp b/src/lib/corelib/tools/vsenvironmentdetector.cpp
index 869423950..90f6b8921 100644
--- a/src/lib/corelib/tools/vsenvironmentdetector.cpp
+++ b/src/lib/corelib/tools/vsenvironmentdetector.cpp
@@ -69,8 +69,9 @@ static QString windowsSystem32Path()
return {};
}
-VsEnvironmentDetector::VsEnvironmentDetector()
+VsEnvironmentDetector::VsEnvironmentDetector(QString vcvarsallPath)
: m_windowsSystemDirPath(windowsSystem32Path())
+ , m_vcvarsallPath(std::move(vcvarsallPath))
{
}
@@ -137,7 +138,15 @@ QString VsEnvironmentDetector::findVcVarsAllBat(const MSVC &msvc,
bool VsEnvironmentDetector::startDetection(const std::vector<MSVC *> &compatibleMSVCs)
{
std::vector<QString> searchedPaths;
- const QString vcvarsallbat = findVcVarsAllBat(**compatibleMSVCs.begin(), searchedPaths);
+
+ if (!m_vcvarsallPath.isEmpty() && !QFileInfo::exists(m_vcvarsallPath)) {
+ m_errorString = Tr::tr("%1 does not exist.").arg(m_vcvarsallPath);
+ return false;
+ }
+
+ const auto vcvarsallbat = !m_vcvarsallPath.isEmpty()
+ ? m_vcvarsallPath
+ : findVcVarsAllBat(**compatibleMSVCs.begin(), searchedPaths);
if (vcvarsallbat.isEmpty()) {
if (!searchedPaths.empty()) {
m_errorString = Tr::tr(
diff --git a/src/lib/corelib/tools/vsenvironmentdetector.h b/src/lib/corelib/tools/vsenvironmentdetector.h
index 1970273ee..7fa152cb6 100644
--- a/src/lib/corelib/tools/vsenvironmentdetector.h
+++ b/src/lib/corelib/tools/vsenvironmentdetector.h
@@ -57,7 +57,7 @@ class MSVC;
class QBS_EXPORT VsEnvironmentDetector
{
public:
- VsEnvironmentDetector();
+ explicit VsEnvironmentDetector(QString vcvarsallPath = QString());
bool start(MSVC *msvc);
bool start(std::vector<MSVC *> msvcs);
@@ -70,6 +70,7 @@ private:
void parseBatOutput(const QByteArray &output, std::vector<MSVC *> msvcs);
const QString m_windowsSystemDirPath;
+ const QString m_vcvarsallPath;
QString m_errorString;
};