aboutsummaryrefslogtreecommitdiffstats
path: root/src
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
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')
-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
-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
14 files changed, 456 insertions, 41 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",
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;
};