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/app/qbs-setup-toolchains | |
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/app/qbs-setup-toolchains')
-rw-r--r-- | src/app/qbs-setup-toolchains/clangclprobe.cpp | 172 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/clangclprobe.h | 55 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/msvcprobe.cpp | 33 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/msvcprobe.h | 12 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/probe.cpp | 8 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/probe.h | 2 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro | 2 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs | 2 |
8 files changed, 276 insertions, 10 deletions
diff --git a/src/app/qbs-setup-toolchains/clangclprobe.cpp b/src/app/qbs-setup-toolchains/clangclprobe.cpp new file mode 100644 index 000000000..89075c5e8 --- /dev/null +++ b/src/app/qbs-setup-toolchains/clangclprobe.cpp @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "clangclprobe.h" +#include "msvcprobe.h" +#include "probe.h" + +#include "../shared/logging/consolelogger.h" + +#include <logging/translator.h> +#include <tools/hostosinfo.h> +#include <tools/profile.h> +#include <tools/qttools.h> +#include <tools/settings.h> + +#include <QtCore/qdir.h> +#include <QtCore/qfileinfo.h> + +using qbs::Settings; +using qbs::Profile; +using qbs::Internal::HostOsInfo; + +using qbs::Internal::Tr; + +namespace { + +QString getToolchainInstallPath(const QString &compilerFilePath) +{ + return QFileInfo(compilerFilePath).path(); // 1 level up +} + +Profile createProfileHelper( + Settings *settings, + const QString &profileName, + const QString &toolchainInstallPath, + const QString &vcvarsallPath, + const QString &architecture) +{ + Profile profile(profileName, settings); + profile.removeProfile(); + profile.setValue(QStringLiteral("qbs.architecture"), architecture); + profile.setValue( + QStringLiteral("qbs.toolchain"), + QStringList{QStringLiteral("clang-cl"), QStringLiteral("msvc")}); + profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), toolchainInstallPath); + profile.setValue(QStringLiteral("cpp.vcvarsallPath"), vcvarsallPath); + qbsInfo() << Tr::tr("Profile '%1' created for '%2'.") + .arg(profile.name(), QDir::toNativeSeparators(toolchainInstallPath)); + return profile; +} + +std::vector<MSVCInstallInfo> compatibleMsvcs() +{ + auto msvcs = installedMSVCs(); + 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() +{ + for (const auto &msvc: compatibleMsvcs()) { + const auto vcvarsallPath = msvc.findVcvarsallBat(); + if (!vcvarsallPath.isEmpty()) + return vcvarsallPath; + } + return {}; +} + +} // namespace + +void createClangClProfile( + const QString &profileName, const QString &compilerFilePath, Settings *settings) +{ + const auto compilerName = QStringLiteral("clang-cl"); + const auto vcvarsallPath = findCompatibleVcsarsallBat(); + if (vcvarsallPath.isEmpty()) { + qbsWarning() + << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.") + .arg(compilerName); + return; + } + + const auto toolchainInstallPath = getToolchainInstallPath(compilerFilePath); + const auto hostArch = QString::fromStdString(HostOsInfo::hostOSArchitecture()); + createProfileHelper(settings, profileName, toolchainInstallPath, vcvarsallPath, hostArch); +} + +/*! + \brief Creates a clang-cl profile based on auto-detected vsversion. + \internal +*/ +void clangClProbe(Settings *settings, QList<Profile> &profiles) +{ + const auto compilerName = QStringLiteral("clang-cl"); + qbsInfo() << Tr::tr("Trying to detect %1...").arg(compilerName); + const auto compilerFilePath = findExecutable(HostOsInfo::appendExecutableSuffix(compilerName)); + if (compilerFilePath.isEmpty()) { + qbsInfo() << Tr::tr("%1 was not found.").arg(compilerName); + return; + } + + const auto vcvarsallPath = findCompatibleVcsarsallBat(); + if (vcvarsallPath.isEmpty()) { + qbsWarning() + << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.") + .arg(compilerName); + return; + } + + const QString architectures[] = { + QStringLiteral("x86_64"), + QStringLiteral("x86") + }; + const auto toolchainInstallPath = getToolchainInstallPath(compilerFilePath); + for (const auto &arch: architectures) { + const auto profileName = QStringLiteral("clang-cl-%1").arg(arch); + auto profile = createProfileHelper( + settings, profileName, toolchainInstallPath, vcvarsallPath, arch); + profiles.push_back(std::move(profile)); + } +} diff --git a/src/app/qbs-setup-toolchains/clangclprobe.h b/src/app/qbs-setup-toolchains/clangclprobe.h new file mode 100644 index 000000000..1e7724fbf --- /dev/null +++ b/src/app/qbs-setup-toolchains/clangclprobe.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CLANGCLPROBE_H +#define CLANGCLPROBE_H + +#include <QtCore/qlist.h> + +namespace qbs { +class Profile; +class Settings; +} + +void createClangClProfile( + const QString &profileName, const QString &compilerFilePath, qbs::Settings *settings); + +void clangClProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles); + +#endif // CLANGCLPROBE_H diff --git a/src/app/qbs-setup-toolchains/msvcprobe.cpp b/src/app/qbs-setup-toolchains/msvcprobe.cpp index faacb4d09..d0b60a7fe 100644 --- a/src/app/qbs-setup-toolchains/msvcprobe.cpp +++ b/src/app/qbs-setup-toolchains/msvcprobe.cpp @@ -160,12 +160,6 @@ static QString wow6432Key() #endif } -struct MSVCInstallInfo -{ - QString version; - QString installDir; -}; - static QString vswhereFilePath() { static const std::vector<const char *> envVarCandidates{"ProgramFiles", "ProgramFiles(x86)"}; @@ -288,7 +282,28 @@ static std::vector<MSVCInstallInfo> installedMSVCsFromRegistry() return result; } -static std::vector<MSVC> installedMSVCs() +QString MSVCInstallInfo::findVcvarsallBat() const +{ + static const auto vcvarsall2017 = QStringLiteral("VC/Auxiliary/Build/vcvarsall.bat"); + // 2015, 2013 and 2012 + static const auto vcvarsallOld = QStringLiteral("VC/vcvarsall.bat"); + QDir dir(installDir); + if (dir.exists(vcvarsall2017)) + return dir.absoluteFilePath(vcvarsall2017); + if (dir.exists(vcvarsallOld)) + return dir.absoluteFilePath(vcvarsallOld); + return {}; +} + +std::vector<MSVCInstallInfo> installedMSVCs() +{ + const auto installInfos = installedMSVCsFromVsWhere(); + if (installInfos.empty()) + return installedMSVCsFromRegistry(); + return installInfos; +} + +static std::vector<MSVC> installedCompilers() { std::vector<MSVC> msvcs; std::vector<MSVCInstallInfo> installInfos = installedMSVCsFromVsWhere(); @@ -385,7 +400,7 @@ void msvcProbe(Settings *settings, QList<Profile> &profiles) // 2) Installed MSVCs std::vector<MSVC> msvcs; - const auto instMsvcs = installedMSVCs(); + const auto instMsvcs = installedCompilers(); for (const MSVC &msvc : instMsvcs) { if (msvc.internalVsVersion.majorVersion() < 15) { // Check existence of various install scripts @@ -452,7 +467,7 @@ void msvcProbe(Settings *settings, QList<Profile> &profiles) void createMsvcProfile(const QString &profileName, const QString &compilerFilePath, Settings *settings) { - MSVC msvc(compilerFilePath); + MSVC msvc(compilerFilePath, MSVC::architectureFromClPath(compilerFilePath)); msvc.init(); QList<Profile> dummy; addMSVCPlatform(settings, dummy, profileName, &msvc); diff --git a/src/app/qbs-setup-toolchains/msvcprobe.h b/src/app/qbs-setup-toolchains/msvcprobe.h index 0fa209548..4fa2cde48 100644 --- a/src/app/qbs-setup-toolchains/msvcprobe.h +++ b/src/app/qbs-setup-toolchains/msvcprobe.h @@ -42,11 +42,23 @@ #include <QtCore/qlist.h> +#include <vector> + namespace qbs { class Profile; class Settings; } +struct MSVCInstallInfo +{ + QString version; + QString installDir; + + QString findVcvarsallBat() const; +}; + +std::vector<MSVCInstallInfo> installedMSVCs(); + void createMsvcProfile(const QString &profileName, const QString &compilerFilePath, qbs::Settings *settings); diff --git a/src/app/qbs-setup-toolchains/probe.cpp b/src/app/qbs-setup-toolchains/probe.cpp index c4ccbc517..6deac36ee 100644 --- a/src/app/qbs-setup-toolchains/probe.cpp +++ b/src/app/qbs-setup-toolchains/probe.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "probe.h" +#include "clangclprobe.h" #include "msvcprobe.h" #include "xcodeprobe.h" @@ -66,7 +67,7 @@ using Internal::Tr; static QTextStream qStdout(stdout); static QTextStream qStderr(stderr); -static QString findExecutable(const QString &fileName) +QString findExecutable(const QString &fileName) { QString fullFileName = fileName; if (HostOsInfo::isWindowsHost() @@ -135,6 +136,8 @@ static QStringList toolchainTypeFromCompilerName(const QString &compilerName) { if (compilerName == QLatin1String("cl.exe")) return canonicalToolchain(QStringLiteral("msvc")); + if (compilerName == QLatin1String("clang-cl.exe")) + return canonicalToolchain(QLatin1String("clang-cl")); const auto types = { QStringLiteral("clang"), QStringLiteral("llvm"), QStringLiteral("mingw"), QStringLiteral("gcc") }; for (const auto &type : types) { @@ -409,6 +412,7 @@ void probe(Settings *settings) QList<Profile> profiles; if (HostOsInfo::isWindowsHost()) { msvcProbe(settings, profiles); + clangClProbe(settings, profiles); } else { gccProbe(settings, profiles, QStringLiteral("gcc")); gccProbe(settings, profiles, QStringLiteral("clang")); @@ -451,6 +455,8 @@ void createProfile(const QString &profileName, const QString &toolchainType, if (toolchainTypes.contains(QLatin1String("msvc"))) createMsvcProfile(profileName, compiler.absoluteFilePath(), settings); + else if (toolchainTypes.contains(QLatin1String("clang-cl"))) + createClangClProfile(profileName, compiler.absoluteFilePath(), settings); else if (toolchainTypes.contains(QLatin1String("gcc"))) createGccProfile(compiler.absoluteFilePath(), settings, toolchainTypes, profileName); else if (toolchainTypes.contains(QLatin1String("iar"))) diff --git a/src/app/qbs-setup-toolchains/probe.h b/src/app/qbs-setup-toolchains/probe.h index 5c8774ddb..510747ef7 100644 --- a/src/app/qbs-setup-toolchains/probe.h +++ b/src/app/qbs-setup-toolchains/probe.h @@ -48,6 +48,8 @@ QT_END_NAMESPACE namespace qbs { class Settings; } +QString findExecutable(const QString &fileName); + void createProfile(const QString &profileName, const QString &toolchainType, const QString &compilerFilePath, qbs::Settings *settings); diff --git a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro index f395c5458..79b9316ad 100644 --- a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro +++ b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro @@ -4,12 +4,14 @@ TARGET = qbs-setup-toolchains HEADERS += \ commandlineparser.h \ + clangclprobe.h \ msvcprobe.h \ probe.h \ xcodeprobe.h SOURCES += \ commandlineparser.cpp \ + clangclprobe.cpp \ main.cpp \ msvcprobe.cpp \ probe.cpp \ diff --git a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs index 1b7cb6526..f4a521b22 100644 --- a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs +++ b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs @@ -4,6 +4,8 @@ QbsApp { name: "qbs-setup-toolchains" cpp.dynamicLibraries: qbs.targetOS.contains("windows") ? base.concat("shell32") : base files: [ + "clangclprobe.cpp", + "clangclprobe.h", "commandlineparser.cpp", "commandlineparser.h", "main.cpp", |