diff options
author | Ivan Komissarov <ABBAPOH@gmail.com> | 2019-03-19 22:24:33 +0100 |
---|---|---|
committer | Ivan Komissarov <ABBAPOH@gmail.com> | 2019-04-10 07:27:02 +0000 |
commit | 62e07306481373d9d9b6b656d855b204aa6964f3 (patch) | |
tree | dac1f681be32eaba98b117a481a9011500af9b91 /src/lib | |
parent | 14324ad4aa9582e07dc687dc63b1b886f2d272e5 (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.cpp | 97 | ||||
-rw-r--r-- | src/lib/corelib/tools/hostosinfo.h | 9 | ||||
-rw-r--r-- | src/lib/corelib/tools/msvcinfo.cpp | 80 | ||||
-rw-r--r-- | src/lib/corelib/tools/msvcinfo.h | 9 | ||||
-rw-r--r-- | src/lib/corelib/tools/vsenvironmentdetector.cpp | 13 | ||||
-rw-r--r-- | src/lib/corelib/tools/vsenvironmentdetector.h | 3 |
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; }; |