diff options
author | Ivan Komissarov <ABBAPOH@gmail.com> | 2020-02-12 16:53:00 +0100 |
---|---|---|
committer | Ivan Komissarov <ABBAPOH@gmail.com> | 2020-02-17 10:26:13 +0000 |
commit | ff53ff1fda2689e71b9d0d8ec73e55f414a78f79 (patch) | |
tree | 767c915f21e88e10efe7e427ab01d6c3a600692a | |
parent | ab2dd5f1b20f07f2734267095af9b9deaede7079 (diff) |
Autodetect clang-cl by using Probe
This allows to build projects without calling "qbs setup-toolchains"
first by simply calling "qbs build qbs.toolchainType:clang-cl"
Change-Id: I86d135ddf2cb588f322709e4e7a265cb6fd7772f
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
-rw-r--r-- | share/qbs/imports/qbs/Probes/ClangClBinaryProbe.qbs | 73 | ||||
-rw-r--r-- | share/qbs/modules/cpp/windows-clang-cl.qbs | 4 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/clangclprobe.cpp | 120 | ||||
-rw-r--r-- | src/lib/corelib/corelib.qbs | 2 | ||||
-rw-r--r-- | src/lib/corelib/jsextensions/utilitiesextension.cpp | 44 | ||||
-rw-r--r-- | src/lib/corelib/tools/clangclinfo.cpp | 176 | ||||
-rw-r--r-- | src/lib/corelib/tools/clangclinfo.h | 61 | ||||
-rw-r--r-- | src/lib/corelib/tools/tools.pri | 2 | ||||
-rw-r--r-- | tests/auto/blackbox/tst_blackbox.cpp | 15 |
9 files changed, 384 insertions, 113 deletions
diff --git a/share/qbs/imports/qbs/Probes/ClangClBinaryProbe.qbs b/share/qbs/imports/qbs/Probes/ClangClBinaryProbe.qbs new file mode 100644 index 000000000..f4916a37a --- /dev/null +++ b/share/qbs/imports/qbs/Probes/ClangClBinaryProbe.qbs @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +import qbs.FileInfo +import qbs.ModUtils +import qbs.Utilities +import "path-probe.js" as PathProbeConfigure + +BinaryProbe { + // output + property string vcvarsallPath; + + configure: { + var _selectors; + var results = PathProbeConfigure.configure(_selectors, names, nameSuffixes, nameFilter, + candidateFilter, searchPaths, pathSuffixes, + platformSearchPaths, environmentPaths, + platformEnvironmentPaths, pathListSeparator); + var compilerPath; + if (results.found) + compilerPath = results.files[0].filePath; + var compilers = Utilities.installedClangCls(compilerPath); + if (compilers.length >= 1) { + var result = {}; + result.fileName = "clang-cl.exe"; + result.path = compilers[0].toolchainInstallPath; + result.filePath = FileInfo.joinPaths(result.path, result.fileName); + result.candidatePaths = result.filePath; + result.vcvarsallPath = compilers[0].vcvarsallPath; + results.found = true; + results.files = [result]; + } + + found = results.found; + allResults = results.files; + + if (allResults.length === 1) { + var result = allResults[0]; + candidatePaths = result.candidatePaths; + path = result.path; + filePath = result.filePath; + fileName = result.fileName; + vcvarsallPath = result.vcvarsallPath; + } + } +} diff --git a/share/qbs/modules/cpp/windows-clang-cl.qbs b/share/qbs/modules/cpp/windows-clang-cl.qbs index d57f5a7ad..a34a67ad2 100644 --- a/share/qbs/modules/cpp/windows-clang-cl.qbs +++ b/share/qbs/modules/cpp/windows-clang-cl.qbs @@ -40,7 +40,7 @@ MsvcBaseModule { qbs.toolchain && qbs.toolchain.contains('clang-cl') priority: 100 - Probes.BinaryProbe { + Probes.ClangClBinaryProbe { id: clangPathProbe condition: !toolchainInstallPath && !_skipAllChecks names: ["clang-cl"] @@ -78,7 +78,7 @@ MsvcBaseModule { driverLinkerFlags: "-fuse-ld=" + linkerVariant } - property string vcvarsallPath + property string vcvarsallPath : clangPathProbe.found ? clangPathProbe.vcvarsallPath : undefined compilerName: "clang-cl.exe" linkerName: "lld-link.exe" diff --git a/src/app/qbs-setup-toolchains/clangclprobe.cpp b/src/app/qbs-setup-toolchains/clangclprobe.cpp index ee445a2fb..6eff83217 100644 --- a/src/app/qbs-setup-toolchains/clangclprobe.cpp +++ b/src/app/qbs-setup-toolchains/clangclprobe.cpp @@ -44,6 +44,7 @@ #include "../shared/logging/consolelogger.h" #include <logging/translator.h> +#include <tools/clangclinfo.h> #include <tools/hostosinfo.h> #include <tools/msvcinfo.h> #include <tools/profile.h> @@ -55,6 +56,7 @@ using qbs::Settings; using qbs::Profile; +using qbs::Internal::ClangClInfo; using qbs::Internal::HostOsInfo; using qbs::Internal::MSVC; using qbs::Internal::MSVCInstallInfo; @@ -63,11 +65,6 @@ using qbs::Internal::Tr; namespace { -QString getToolchainInstallPath(const QFileInfo &compiler) -{ - return compiler.path(); // 1 level up -} - Profile createProfileHelper( Settings *settings, const QString &profileName, @@ -88,90 +85,13 @@ Profile createProfileHelper( return profile; } -std::vector<MSVCInstallInfo> compatibleMsvcs() -{ - auto msvcs = MSVCInstallInfo::installedMSVCs(ConsoleLogger::instance()); - auto filter = [](const MSVCInstallInfo &info) - { - const auto versions = info.version.split(QLatin1Char('.')); - if (versions.empty()) - return true; - bool ok = false; - const int major = versions.at(0).toInt(&ok); - return !(ok && major >= 15); // support MSVC2017 and above - }; - const auto it = std::remove_if(msvcs.begin(), msvcs.end(), filter); - msvcs.erase(it, msvcs.end()); - for (const auto &msvc: msvcs) { - auto vcvarsallPath = msvc.findVcvarsallBat(); - if (vcvarsallPath.isEmpty()) - continue; - } - return msvcs; -} - -QString findCompatibleVcsarsallBat(const std::vector<MSVCInstallInfo> &msvcs) +QString findClangCl() { - for (const auto &msvc: msvcs) { - const auto vcvarsallPath = msvc.findVcvarsallBat(); - if (!vcvarsallPath.isEmpty()) - return vcvarsallPath; - } - return {}; -} - -QString wow6432Key() -{ -#ifdef Q_OS_WIN64 - return QStringLiteral("\\Wow6432Node"); -#else - return {}; -#endif -} - -// Function can modify passed list in case it has found clang in one of the VS installation - -// in that case, there's no point in looking for vcvarsall.bat among all installed VSs, we just -// use .bat file corresponding to that particular VS installation -QString findClangCl(std::vector<MSVCInstallInfo> *msvcs) -{ - Q_ASSERT(msvcs); const auto compilerName = HostOsInfo::appendExecutableSuffix(QStringLiteral("clang-cl")); const auto compilerFromPath = findExecutable(compilerName); if (!compilerFromPath.isEmpty()) return compilerFromPath; - const QSettings registry( - QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE%1\\LLVM\\LLVM").arg(wow6432Key()), - QSettings::NativeFormat); - const auto key = QStringLiteral("."); - if (registry.contains(key)) { - const auto compilerPath = QDir::fromNativeSeparators(registry.value(key).toString()) - + QStringLiteral("/bin/") + compilerName; - if (QFileInfo(compilerPath).exists()) - return compilerPath; - } - - // this branch can be useful in case user had two LLVM installations (e.g. 32bit & 64bit) - // but uninstalled one - in that case, registry will be empty - static const char * const envVarCandidates[] = {"ProgramFiles", "ProgramFiles(x86)"}; - for (const auto &envVar : envVarCandidates) { - const auto value - = QDir::fromNativeSeparators(QString::fromLocal8Bit(qgetenv(envVar))); - const auto compilerPath = value + QStringLiteral("/LLVM/bin/") + compilerName; - if (QFileInfo(compilerPath).exists()) - return compilerPath; - } - - // If we didn't find custom LLVM installation, try to find if it's installed with Visual Studio - for (const auto &msvc : *msvcs) { - const auto compilerPath = QStringLiteral("%1/VC/Tools/Llvm/bin/%2") - .arg(msvc.installDir, compilerName); - if (QFileInfo(compilerPath).exists()) { - *msvcs = {msvc}; // reduce list to one installation - return compilerPath; - } - } - return {}; } @@ -180,18 +100,13 @@ QString findClangCl(std::vector<MSVCInstallInfo> *msvcs) void createClangClProfile(const QFileInfo &compiler, Settings *settings, const QString &profileName) { - const auto compilerName = QStringLiteral("clang-cl"); - const auto vcvarsallPath = findCompatibleVcsarsallBat(compatibleMsvcs()); - if (vcvarsallPath.isEmpty()) { - qbsWarning() - << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.") - .arg(compilerName); + const auto clangCl = ClangClInfo::fromCompilerFilePath( + compiler.filePath(), ConsoleLogger::instance()); + if (clangCl.isEmpty()) return; - } - - const auto toolchainInstallPath = getToolchainInstallPath(compiler); const auto hostArch = QString::fromStdString(HostOsInfo::hostOSArchitecture()); - createProfileHelper(settings, profileName, toolchainInstallPath, vcvarsallPath, hostArch); + createProfileHelper( + settings, profileName, clangCl.toolchainInstallPath, clangCl.vcvarsallPath, hostArch); } /*! @@ -200,33 +115,24 @@ void createClangClProfile(const QFileInfo &compiler, Settings *settings, */ void clangClProbe(Settings *settings, std::vector<Profile> &profiles) { - auto msvcs = compatibleMsvcs(); - const auto compilerName = QStringLiteral("clang-cl"); qbsInfo() << Tr::tr("Trying to detect %1...").arg(compilerName); - const QString compilerFilePath = findClangCl(&msvcs); - if (compilerFilePath.isEmpty()) { + const auto clangCls = ClangClInfo::installedCompilers( + {findClangCl()}, ConsoleLogger::instance()); + if (clangCls.empty()) { qbsInfo() << Tr::tr("%1 was not found.").arg(compilerName); return; } - const QFileInfo compiler(compilerFilePath); - const auto vcvarsallPath = findCompatibleVcsarsallBat(msvcs); - if (vcvarsallPath.isEmpty()) { - qbsWarning() - << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.") - .arg(compilerName); - return; - } + const auto clangCl = clangCls.front(); const QString architectures[] = { QStringLiteral("x86_64"), QStringLiteral("x86") }; - const auto toolchainInstallPath = getToolchainInstallPath(compiler); for (const auto &arch: architectures) { const auto profileName = QStringLiteral("clang-cl-%1").arg(arch); auto profile = createProfileHelper( - settings, profileName, toolchainInstallPath, vcvarsallPath, arch); + settings, profileName, clangCl.toolchainInstallPath, clangCl.vcvarsallPath, arch); profiles.push_back(std::move(profile)); } } diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs index bd44ac3ed..619c0f0e3 100644 --- a/src/lib/corelib/corelib.qbs +++ b/src/lib/corelib/corelib.qbs @@ -395,6 +395,8 @@ QbsLibrary { "buildgraphlocker.cpp", "buildgraphlocker.h", "buildoptions.cpp", + "clangclinfo.cpp", + "clangclinfo.h", "cleanoptions.cpp", "codelocation.cpp", "commandechomode.cpp", diff --git a/src/lib/corelib/jsextensions/utilitiesextension.cpp b/src/lib/corelib/jsextensions/utilitiesextension.cpp index 2d29cb7c5..6c693cb61 100644 --- a/src/lib/corelib/jsextensions/utilitiesextension.cpp +++ b/src/lib/corelib/jsextensions/utilitiesextension.cpp @@ -72,6 +72,7 @@ struct fat_arch_64 { #ifdef Q_OS_WIN +#include <tools/clangclinfo.h> #include <tools/msvcinfo.h> #include <tools/vsenvironmentdetector.h> #endif @@ -88,6 +89,10 @@ struct fat_arch_64 { namespace qbs { namespace Internal { +class DummyLogSink : public ILogSink { + void doPrintMessage(LoggerLevel, const QString &, const QString &) override { } +}; + class UtilitiesExtension : public QObject, QScriptable { Q_OBJECT @@ -111,6 +116,7 @@ public: static QScriptValue js_msvcCompilerInfo(QScriptContext *context, QScriptEngine *engine); static QScriptValue js_clangClCompilerInfo(QScriptContext *context, QScriptEngine *engine); static QScriptValue js_installedMSVCs(QScriptContext *context, QScriptEngine *engine); + static QScriptValue js_installedClangCls(QScriptContext *context, QScriptEngine *engine); static QScriptValue js_versionCompare(QScriptContext *context, QScriptEngine *engine); @@ -530,7 +536,11 @@ QScriptValue UtilitiesExtension::js_clangClCompilerInfo(QScriptContext *context, QStringLiteral("clangClCompilerInfo expects 4 arguments")); const QString compilerFilePath = context->argument(0).toString(); - QString arch = context->argument(1).toString(); + // architecture cannot be empty as vcvarsall.bat requires at least 1 arg, so fallback + // to host architecture if none is present + QString arch = !context->argument(1).isNull() && !context->argument(1).isUndefined() + ? context->argument(1).toString() + : QString::fromStdString(HostOsInfo::hostOSArchitecture()); QString vcvarsallPath = context->argument(2).toString(); const QString compilerLanguage = context->argumentCount() > 3 ? context->argument(3).toString() @@ -570,9 +580,7 @@ QScriptValue UtilitiesExtension::js_installedMSVCs(QScriptContext *context, QScr ? value0.toString() : hostArch; - class LogSink : public ILogSink { - void doPrintMessage(LoggerLevel, const QString &, const QString &) override { } - } dummySink; + DummyLogSink dummySink; Logger dummyLogger(&dummySink); auto msvcs = MSVC::installedCompilers(dummyLogger); @@ -589,6 +597,32 @@ QScriptValue UtilitiesExtension::js_installedMSVCs(QScriptContext *context, QScr #endif } +QScriptValue UtilitiesExtension::js_installedClangCls( + QScriptContext *context, QScriptEngine *engine) +{ +#ifndef Q_OS_WIN + Q_UNUSED(engine); + return context->throwError(QScriptContext::UnknownError, + QStringLiteral("installedClangCls is not available on this platform")); +#else + if (Q_UNLIKELY(context->argumentCount() != 1)) { + return context->throwError(QScriptContext::SyntaxError, + QStringLiteral("installedClangCls expects 1 arguments")); + } + + const auto value0 = context->argument(0); + const auto path = !value0.isNull() && !value0.isUndefined() ? value0.toString() : QString(); + + DummyLogSink dummySink; + Logger dummyLogger(&dummySink); + auto compilers = ClangClInfo::installedCompilers({path}, dummyLogger); + QVariantList result; + for (const auto &compiler: compilers) + result.append(compiler.toVariantMap()); + return engine->toScriptValue(result); +#endif +} + QScriptValue UtilitiesExtension::js_versionCompare(QScriptContext *context, QScriptEngine *engine) { if (context->argumentCount() == 2) { @@ -891,6 +925,8 @@ void initializeJsExtensionUtilities(QScriptValue extensionObject) engine->newFunction(UtilitiesExtension::js_clangClCompilerInfo, 1)); environmentObj.setProperty(QStringLiteral("installedMSVCs"), engine->newFunction(UtilitiesExtension::js_installedMSVCs, 1)); + environmentObj.setProperty(QStringLiteral("installedClangCls"), + engine->newFunction(UtilitiesExtension::js_installedClangCls, 1)); environmentObj.setProperty(QStringLiteral("versionCompare"), engine->newFunction(UtilitiesExtension::js_versionCompare, 2)); environmentObj.setProperty(QStringLiteral("qmlTypeInfo"), diff --git a/src/lib/corelib/tools/clangclinfo.cpp b/src/lib/corelib/tools/clangclinfo.cpp new file mode 100644 index 000000000..4e1022c28 --- /dev/null +++ b/src/lib/corelib/tools/clangclinfo.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "clangclinfo.h" + +#include "hostosinfo.h" +#include "msvcinfo.h" +#include "stlutils.h" + +namespace qbs { +namespace Internal { + +static std::vector<MSVCInstallInfo> compatibleMsvcs(Logger &logger) +{ + auto msvcs = MSVCInstallInfo::installedMSVCs(logger); + auto filter = [](const MSVCInstallInfo &info) + { + const auto versions = info.version.split(QLatin1Char('.')); + if (versions.empty()) + return true; + bool ok = false; + const int major = versions.at(0).toInt(&ok); + return !(ok && major >= 15); // support MSVC2017 and above + }; + const auto it = std::remove_if(msvcs.begin(), msvcs.end(), filter); + msvcs.erase(it, msvcs.end()); + for (const auto &msvc: msvcs) { + auto vcvarsallPath = msvc.findVcvarsallBat(); + if (vcvarsallPath.isEmpty()) + continue; + } + return msvcs; +} + +static QString findCompatibleVcsarsallBat(const std::vector<MSVCInstallInfo> &msvcs) +{ + for (const auto &msvc: msvcs) { + const auto vcvarsallPath = msvc.findVcvarsallBat(); + if (!vcvarsallPath.isEmpty()) + return vcvarsallPath; + } + return {}; +} + +static QString wow6432Key() +{ +#ifdef Q_OS_WIN64 + return QStringLiteral("\\Wow6432Node"); +#else + return {}; +#endif +} + +static QString getToolchainInstallPath(const QFileInfo &compiler) +{ + return compiler.path(); // 1 level up +} + +QVariantMap ClangClInfo::toVariantMap() const +{ + return { + {QStringLiteral("toolchainInstallPath"), toolchainInstallPath}, + {QStringLiteral("vcvarsallPath"), vcvarsallPath}, + }; +} + +ClangClInfo ClangClInfo::fromCompilerFilePath(const QString &path, Logger &logger) +{ + const auto compilerName = QStringLiteral("clang-cl"); + const auto vcvarsallPath = findCompatibleVcsarsallBat(compatibleMsvcs(logger)); + if (vcvarsallPath.isEmpty()) { + logger.qbsWarning() + << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.") + .arg(compilerName); + return {}; + } + + const auto toolchainInstallPath = getToolchainInstallPath(path); + return {toolchainInstallPath, vcvarsallPath}; +} + +std::vector<ClangClInfo> ClangClInfo::installedCompilers( + const std::vector<QString> &extraPaths, Logger &logger) +{ + std::vector<QString> compilerPaths; + compilerPaths.reserve(extraPaths.size()); + std::copy_if(extraPaths.begin(), extraPaths.end(), + std::back_inserter(compilerPaths), + [](const QString &path){ return !path.isEmpty(); }); + const auto compilerName = HostOsInfo::appendExecutableSuffix(QStringLiteral("clang-cl")); + + const QSettings registry( + QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE%1\\LLVM\\LLVM").arg(wow6432Key()), + QSettings::NativeFormat); + const auto key = QStringLiteral("."); + if (registry.contains(key)) { + const auto compilerPath = QDir::fromNativeSeparators(registry.value(key).toString()) + + QStringLiteral("/bin/") + compilerName; + if (QFileInfo(compilerPath).exists()) + compilerPaths.push_back(compilerPath); + } + + // this branch can be useful in case user had two LLVM installations (e.g. 32bit & 64bit) + // but uninstalled one - in that case, registry will be empty + static const char * const envVarCandidates[] = {"ProgramFiles", "ProgramFiles(x86)"}; + for (const auto &envVar : envVarCandidates) { + const auto value + = QDir::fromNativeSeparators(QString::fromLocal8Bit(qgetenv(envVar))); + const auto compilerPath = value + QStringLiteral("/LLVM/bin/") + compilerName; + if (QFileInfo(compilerPath).exists() && !contains(compilerPaths, compilerPath)) + compilerPaths.push_back(compilerPath); + } + + const auto msvcs = compatibleMsvcs(logger); + const auto vcvarsallPath = findCompatibleVcsarsallBat(msvcs); + if (vcvarsallPath.isEmpty()) { + logger.qbsWarning() + << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.") + .arg(compilerName); + return {}; + } + + std::vector<ClangClInfo> result; + result.reserve(compilerPaths.size() + msvcs.size()); + + for (const auto &path: compilerPaths) + result.push_back({getToolchainInstallPath(path), vcvarsallPath}); + + // If we didn't find custom LLVM installation, try to find if it's installed with Visual Studio + for (const auto &msvc : msvcs) { + const auto compilerPath = QStringLiteral("%1/VC/Tools/Llvm/bin/%2") + .arg(msvc.installDir, compilerName); + if (QFileInfo(compilerPath).exists()) { + const auto vcvarsallPath = msvc.findVcvarsallBat(); + if (vcvarsallPath.isEmpty()) { + logger.qbsWarning() + << Tr::tr("Found LLVM in %1, but vcvarsall.bat is missing.") + .arg(msvc.installDir); + } + + result.push_back({getToolchainInstallPath(compilerPath), vcvarsallPath}); + } + } + + return result; +} + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/tools/clangclinfo.h b/src/lib/corelib/tools/clangclinfo.h new file mode 100644 index 000000000..76ae169f2 --- /dev/null +++ b/src/lib/corelib/tools/clangclinfo.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef QBS_CLANGCLINFO_H +#define QBS_CLANGCLINFO_H + +#include "logging/logger.h" + +#include <QtCore/qstring.h> + +#include <vector> + +namespace qbs { +namespace Internal { + +class ClangClInfo +{ +public: + QString toolchainInstallPath; + QString vcvarsallPath; + + bool isEmpty() const { return toolchainInstallPath.isEmpty() && vcvarsallPath.isEmpty(); } + + QBS_EXPORT QVariantMap toVariantMap() const; + + QBS_EXPORT static ClangClInfo fromCompilerFilePath(const QString &path, Logger &logger); + QBS_EXPORT static std::vector<ClangClInfo> installedCompilers( + const std::vector<QString> &extraPaths, qbs::Internal::Logger &logger); +}; + +} // namespace Internal +} // namespace qbs + +#endif // QBS_CLANGCLINFO_H diff --git a/src/lib/corelib/tools/tools.pri b/src/lib/corelib/tools/tools.pri index 89d752671..00d87ecc7 100644 --- a/src/lib/corelib/tools/tools.pri +++ b/src/lib/corelib/tools/tools.pri @@ -10,6 +10,7 @@ QBS_SYSTEM_SETTINGS_DIR = $$(QBS_SYSTEM_SETTINGS_DIR) HEADERS += \ $$PWD/architectures.h \ $$PWD/buildgraphlocker.h \ + $$PWD/clangclinfo.h \ $$PWD/codelocation.h \ $$PWD/commandechomode.h \ $$PWD/dynamictypecheck.h \ @@ -68,6 +69,7 @@ HEADERS += \ SOURCES += \ $$PWD/architectures.cpp \ $$PWD/buildgraphlocker.cpp \ + $$PWD/clangclinfo.cpp \ $$PWD/codelocation.cpp \ $$PWD/commandechomode.cpp \ $$PWD/error.cpp \ diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp index a30d57be9..a1672f4c1 100644 --- a/tests/auto/blackbox/tst_blackbox.cpp +++ b/tests/auto/blackbox/tst_blackbox.cpp @@ -3476,10 +3476,25 @@ void TestBlackbox::emptyProfile() { QDir::setCurrent(testDataDir + "/empty-profile"); + const SettingsPtr s = settings(); + const Profile buildProfile(profileName(), s.get()); + const QStringList toolchain = buildProfile.value("qbs.toolchain").toStringList(); + QTemporaryDir tempDir; QbsRunParameters params; params.profile.clear(); params.settingsDir = tempDir.path(); // should be no settings here + if (toolchain.contains(QLatin1String("clang-cl"))) + params.arguments = QStringList{QStringLiteral("qbs.toolchainType:clang-cl")}; + else if (toolchain.contains(QLatin1String("msvc"))) + params.arguments = QStringList{QStringLiteral("qbs.toolchainType:msvc")}; + else if (toolchain.contains(QLatin1String("xcode"))) + params.arguments = QStringList{QStringLiteral("qbs.toolchainType:xcode")}; + else if (toolchain.contains(QLatin1String("clang"))) + params.arguments = QStringList{QStringLiteral("qbs.toolchainType:clang")}; + else if (toolchain.contains(QLatin1String("gcc"))) + params.arguments = QStringList{QStringLiteral("qbs.toolchainType:gcc")}; + QCOMPARE(runQbs(params), 0); } |