aboutsummaryrefslogtreecommitdiffstats
path: root/src/app/qbs-setup-toolchains
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/app/qbs-setup-toolchains
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/app/qbs-setup-toolchains')
-rw-r--r--src/app/qbs-setup-toolchains/clangclprobe.cpp172
-rw-r--r--src/app/qbs-setup-toolchains/clangclprobe.h55
-rw-r--r--src/app/qbs-setup-toolchains/msvcprobe.cpp33
-rw-r--r--src/app/qbs-setup-toolchains/msvcprobe.h12
-rw-r--r--src/app/qbs-setup-toolchains/probe.cpp8
-rw-r--r--src/app/qbs-setup-toolchains/probe.h2
-rw-r--r--src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro2
-rw-r--r--src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs2
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",