aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--share/qbs/imports/qbs/ModUtils/utils.js2
-rw-r--r--share/qbs/imports/qbs/Probes/MsvcProbe.qbs (renamed from src/app/qbs-setup-toolchains/compilerversion.h)50
-rw-r--r--share/qbs/modules/cpp/CppModule.qbs8
-rw-r--r--share/qbs/modules/cpp/windows-msvc.qbs24
-rw-r--r--src/app/qbs-setup-toolchains/msvcprobe.cpp92
-rw-r--r--src/app/qbs-setup-toolchains/probe.cpp2
-rw-r--r--src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro5
-rw-r--r--src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs8
-rw-r--r--src/lib/corelib/corelib.pro2
-rw-r--r--src/lib/corelib/corelib.qbs6
-rw-r--r--src/lib/corelib/jsextensions/utilitiesextension.cpp45
-rw-r--r--src/lib/corelib/tools/msvcinfo.cpp (renamed from src/app/qbs-setup-toolchains/compilerversion.cpp)135
-rw-r--r--src/lib/corelib/tools/msvcinfo.h (renamed from src/app/qbs-setup-toolchains/msvcinfo.h)14
-rw-r--r--src/lib/corelib/tools/tools.pri8
-rw-r--r--src/lib/corelib/tools/vsenvironmentdetector.cpp (renamed from src/app/qbs-setup-toolchains/vsenvironmentdetector.cpp)6
-rw-r--r--src/lib/corelib/tools/vsenvironmentdetector.h (renamed from src/app/qbs-setup-toolchains/vsenvironmentdetector.h)10
16 files changed, 290 insertions, 127 deletions
diff --git a/share/qbs/imports/qbs/ModUtils/utils.js b/share/qbs/imports/qbs/ModUtils/utils.js
index 670c3894c..b3714b957 100644
--- a/share/qbs/imports/qbs/ModUtils/utils.js
+++ b/share/qbs/imports/qbs/ModUtils/utils.js
@@ -515,7 +515,7 @@ function guessArchitecture(m) {
}
} else if (hasAnyOf(m, ["__i386", "__i386__", "_M_IX86"])) {
architecture = "x86";
- } else if (hasAnyOf(m, ["__x86_64", "__x86_64__", "__amd64", "_M_X64"])) {
+ } else if (hasAnyOf(m, ["__x86_64", "__x86_64__", "__amd64", "_M_X64", "_M_AMD64"])) {
architecture = "x86_64";
} else if (hasAnyOf(m, ["__ia64", "__ia64__", "_M_IA64"])) {
architecture = "ia64";
diff --git a/src/app/qbs-setup-toolchains/compilerversion.h b/share/qbs/imports/qbs/Probes/MsvcProbe.qbs
index df9f66045..05a307439 100644
--- a/src/app/qbs-setup-toolchains/compilerversion.h
+++ b/share/qbs/imports/qbs/Probes/MsvcProbe.qbs
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2016 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qbs.
@@ -27,21 +27,43 @@
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
-#ifndef QBS_COMPILERVERSION_H
-#define QBS_COMPILERVERSION_H
-#include <QtGlobal>
-#include <QProcessEnvironment>
+import qbs
+import qbs.ModUtils
+import qbs.Utilities
-namespace qbs { class Profile; }
+PathProbe {
+ // Inputs
+ property string compilerFilePath
+ property string preferredArchitecture
-QT_BEGIN_NAMESPACE
-class QString;
-class QStringList;
-QT_END_NAMESPACE
+ // Outputs
+ property string architecture
+ property int versionMajor
+ property int versionMinor
+ property int versionPatch
+ property var buildEnv
-void setCompilerVersion(const QString &compilerFilePath, const QStringList &qbsToolchain,
- qbs::Profile &profile,
- const QProcessEnvironment &compilerEnv = QProcessEnvironment());
+ configure: {
+ var info = Utilities.msvcCompilerInfo(compilerFilePath);
+ found = !!info && !!info.macros && !!info.buildEnvironment;
-#endif // Include guard
+ var macros = info.macros;
+ architecture = ModUtils.guessArchitecture(macros);
+
+ var ver = macros["_MSC_FULL_VER"];
+
+ versionMajor = parseInt(ver.substr(0, 2), 10);
+ versionMinor = parseInt(ver.substr(2, 2), 10);
+ versionPatch = parseInt(ver.substr(4), 10);
+
+ buildEnv = info.buildEnvironment;
+
+ if (preferredArchitecture && Utilities.canonicalArchitecture(preferredArchitecture)
+ !== Utilities.canonicalArchitecture(architecture)) {
+ throw "'" + preferredArchitecture +
+ "' differs from the architecture produced by this compiler (" +
+ architecture + ")";
+ }
+ }
+}
diff --git a/share/qbs/modules/cpp/CppModule.qbs b/share/qbs/modules/cpp/CppModule.qbs
index 3c0ef0574..433fbc395 100644
--- a/share/qbs/modules/cpp/CppModule.qbs
+++ b/share/qbs/modules/cpp/CppModule.qbs
@@ -329,6 +329,14 @@ Module {
return !architecture || architecture === Utilities.canonicalArchitecture(architecture);
}, "'" + architecture + "' is invalid. You must use the canonical name '" +
Utilities.canonicalArchitecture(architecture) + "'");
+ validator.setRequiredProperty("compilerVersion", compilerVersion);
+ validator.setRequiredProperty("compilerVersionMajor", compilerVersionMajor);
+ validator.setRequiredProperty("compilerVersionMinor", compilerVersionMinor);
+ validator.setRequiredProperty("compilerVersionPatch", compilerVersionPatch);
+ validator.addVersionValidator("compilerVersion", compilerVersion, 3, 3);
+ validator.addRangeValidator("compilerVersionMajor", compilerVersionMajor, 1);
+ validator.addRangeValidator("compilerVersionMinor", compilerVersionMinor, 0);
+ validator.addRangeValidator("compilerVersionPatch", compilerVersionPatch, 0);
if (minimumWindowsVersion) {
validator.addVersionValidator("minimumWindowsVersion", minimumWindowsVersion, 2, 2);
validator.addCustomValidator("minimumWindowsVersion", minimumWindowsVersion, function (v) {
diff --git a/share/qbs/modules/cpp/windows-msvc.qbs b/share/qbs/modules/cpp/windows-msvc.qbs
index a7cb6b36f..f8974bf89 100644
--- a/share/qbs/modules/cpp/windows-msvc.qbs
+++ b/share/qbs/modules/cpp/windows-msvc.qbs
@@ -33,6 +33,7 @@ import qbs.File
import qbs.FileInfo
import qbs.ModUtils
import qbs.PathTools
+import qbs.Probes
import qbs.Utilities
import qbs.WindowsUtils
import 'msvc.js' as MSVC
@@ -44,6 +45,18 @@ CppModule {
id: module
+ Probes.MsvcProbe {
+ id: msvcProbe
+ compilerFilePath: compilerPath
+ preferredArchitecture: qbs.architecture
+ }
+
+ qbs.architecture: msvcProbe.found ? msvcProbe.architecture : original
+
+ compilerVersionMajor: msvcProbe.versionMajor
+ compilerVersionMinor: msvcProbe.versionMinor
+ compilerVersionPatch: msvcProbe.versionPatch
+
windowsApiCharacterSet: "unicode"
platformDefines: base.concat(WindowsUtils.characterSetDefines(windowsApiCharacterSet))
platformCommonCompilerFlags: {
@@ -55,6 +68,7 @@ CppModule {
compilerDefines: ['_WIN32', MSVC.compilerVersionDefine(module)]
warningLevel: "default"
compilerName: "cl.exe"
+ compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName)
assemblerName: {
switch (qbs.architecture) {
case "armv7":
@@ -85,6 +99,16 @@ CppModule {
property string dynamicLibraryImportSuffix: ".lib"
imageFormat: "pe"
+ property var buildEnv: msvcProbe.buildEnv
+
+ setupBuildEnvironment: {
+ for (var key in buildEnv) {
+ var v = new ModUtils.EnvironmentVariable(key);
+ v.value = buildEnv[key];
+ v.set();
+ }
+ }
+
Rule {
condition: useCPrecompiledHeader
inputs: ["c_pch_src"]
diff --git a/src/app/qbs-setup-toolchains/msvcprobe.cpp b/src/app/qbs-setup-toolchains/msvcprobe.cpp
index 898c9d4f4..ffaaabc5a 100644
--- a/src/app/qbs-setup-toolchains/msvcprobe.cpp
+++ b/src/app/qbs-setup-toolchains/msvcprobe.cpp
@@ -30,18 +30,17 @@
#include "msvcprobe.h"
-#include "compilerversion.h"
-#include "msvcinfo.h"
#include "probe.h"
-#include "vsenvironmentdetector.h"
#include "../shared/logging/consolelogger.h"
#include <logging/translator.h>
#include <tools/architectures.h>
#include <tools/error.h>
+#include <tools/msvcinfo.h>
#include <tools/profile.h>
#include <tools/settings.h>
#include <tools/visualstudioversioninfo.h>
+#include <tools/vsenvironmentdetector.h>
#include <QDir>
#include <QFileInfo>
@@ -50,6 +49,7 @@
#include <QVector>
using namespace qbs;
+using namespace qbs::Internal;
using Internal::Tr;
QT_BEGIN_NAMESPACE
@@ -57,46 +57,67 @@ Q_DECLARE_TYPEINFO(WinSDK, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(MSVC, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
-static void writeEnvironment(Profile &p, const QProcessEnvironment &env)
+// Not necessary but helps setup-qt automatically associate base profiles
+static void setQtHelperProperties(Profile &p, const QString &architecture,
+ const QString &compilerFilePath)
{
- foreach (const QString &name, env.keys())
- p.setValue(QLatin1String("buildEnvironment.") + name, env.value(name));
+ MSVC msvc(compilerFilePath);
+ VsEnvironmentDetector envdetector(&msvc);
+ if (!envdetector.start()) {
+ qbsWarning() << (QStringLiteral("Detecting the MSVC build environment failed: ")
+ + envdetector.errorString());
+ return;
+ }
+
+ QString targetArch = architecture.split(QLatin1Char('_')).last();
+ if (targetArch.isEmpty())
+ targetArch = QStringLiteral("x86");
+ if (targetArch == QStringLiteral("arm"))
+ targetArch = QStringLiteral("armv7");
+
+ p.setValue(QStringLiteral("qbs.architecture"), canonicalArchitecture(targetArch));
+ p.setValue(QStringLiteral("cpp.compilerVersionMajor"),
+ msvc.compilerDefines(compilerFilePath)[QStringLiteral("_MSC_FULL_VER")]
+ .toString().mid(0, 2).toInt());
}
-static void addMSVCPlatform(const MSVC &msvc, Settings *settings, QList<Profile> &profiles,
+static void addMSVCPlatform(Settings *settings, QList<Profile> &profiles,
QString name, const QString &installPath, const QString &architecture,
bool appendArchToName = true)
{
- if (appendArchToName)
- name.append(QLatin1Char('_') + architecture);
+ QStringList toolchainInstallPath = QStringList() << installPath;
+ if (!architecture.isEmpty()) {
+ toolchainInstallPath.append(architecture);
+ if (appendArchToName)
+ name.append(QLatin1Char('-') + architecture);
+ }
qbsInfo() << Tr::tr("Setting up profile '%1'.").arg(name);
Profile p(name, settings);
p.removeProfile();
p.setValue(QLatin1String("qbs.targetOS"), QStringList(QLatin1String("windows")));
- p.setValue(QLatin1String("cpp.toolchainInstallPath"), installPath);
p.setValue(QLatin1String("qbs.toolchain"), QStringList(QLatin1String("msvc")));
- p.setValue(QLatin1String("qbs.architecture"), canonicalArchitecture(architecture));
- const QProcessEnvironment compilerEnvironment = msvc.environments.value(architecture);
- setCompilerVersion(installPath + QLatin1String("/cl.exe"), QStringList(QLatin1String("msvc")),
- p, compilerEnvironment);
- writeEnvironment(p, compilerEnvironment);
+ p.setValue(QLatin1String("cpp.toolchainInstallPath"),
+ toolchainInstallPath.join(QDir::separator()));
+ setQtHelperProperties(p, architecture,
+ toolchainInstallPath.join(QDir::separator()) + QLatin1String("/cl.exe"));
profiles << p;
}
static void findSupportedArchitectures(MSVC *msvc)
{
- if (QFile::exists(msvc->clPath())
- || QFile::exists(msvc->clPath(QLatin1String("amd64_x86"))))
- msvc->architectures += QLatin1String("x86");
- if (QFile::exists(msvc->clPath(QLatin1String("amd64")))
- || QFile::exists(msvc->clPath(QLatin1String("x86_amd64"))))
- msvc->architectures += QLatin1String("x86_64");
- if (QFile::exists(msvc->clPath(QLatin1String("ia64")))
- || QFile::exists(msvc->clPath(QLatin1String("x86_ia64"))))
- msvc->architectures += QLatin1String("ia64");
- if (QFile::exists(msvc->clPath(QLatin1String("x86_arm")))
- || QFile::exists(msvc->clPath(QLatin1String("amd64_arm"))))
- msvc->architectures += QLatin1String("armv7");
+ static const QStringList knownArchitectures = QStringList()
+ << QString() // x86_x86
+ << QStringLiteral("amd64_x86")
+ << QStringLiteral("amd64")
+ << QStringLiteral("x86_amd64")
+ << QStringLiteral("ia64")
+ << QStringLiteral("x86_ia64")
+ << QStringLiteral("x86_arm")
+ << QStringLiteral("amd64_arm");
+ for (const QString &knownArchitecture : knownArchitectures) {
+ if (QFile::exists(msvc->clPath(knownArchitecture)))
+ msvc->architectures += knownArchitecture;
+ }
}
static QString wow6432Key()
@@ -177,14 +198,6 @@ void msvcProbe(Settings *settings, QList<Profile> &profiles)
if (!QFileInfo(vcvars32bat).isFile())
continue;
- VsEnvironmentDetector envdetector(&msvc);
- if (!envdetector.start()) {
- qbsError() << " "
- << Tr::tr("Detecting the build environment from '%1' failed.").arg(
- vcvars32bat);
- continue;
- }
-
msvcs += msvc;
}
@@ -202,14 +215,14 @@ void msvcProbe(Settings *settings, QList<Profile> &profiles)
foreach (const WinSDK &sdk, winSDKs) {
foreach (const QString &arch, sdk.architectures) {
- addMSVCPlatform(sdk, settings, profiles, QLatin1String("WinSDK") + sdk.version,
+ addMSVCPlatform(settings, profiles, QLatin1String("WinSDK") + sdk.version,
sdk.installPath + QLatin1String("\\bin"), arch);
}
}
foreach (const MSVC &msvc, msvcs) {
foreach (const QString &arch, msvc.architectures) {
- addMSVCPlatform(msvc, settings, profiles, QLatin1String("MSVC") + msvc.version,
+ addMSVCPlatform(settings, profiles, QLatin1String("MSVC") + msvc.version,
msvc.installPath, arch);
}
}
@@ -219,11 +232,8 @@ void createMsvcProfile(const QString &profileName, const QString &compilerFilePa
Settings *settings)
{
MSVC msvc(compilerFilePath);
- VsEnvironmentDetector envdetector(&msvc);
- if (!envdetector.start())
- throw qbs::ErrorInfo(Tr::tr("Detecting the build environment failed."));
QList<Profile> dummy;
- addMSVCPlatform(msvc, settings, dummy, profileName, msvc.installPath,
+ addMSVCPlatform(settings, dummy, profileName, msvc.installPath,
msvc.architectures.first(), false);
qbsInfo() << Tr::tr("Profile '%1' created for '%2'.")
.arg(profileName, QDir::toNativeSeparators(compilerFilePath));
diff --git a/src/app/qbs-setup-toolchains/probe.cpp b/src/app/qbs-setup-toolchains/probe.cpp
index 793c96997..8a5b306f2 100644
--- a/src/app/qbs-setup-toolchains/probe.cpp
+++ b/src/app/qbs-setup-toolchains/probe.cpp
@@ -29,7 +29,6 @@
****************************************************************************/
#include "probe.h"
-#include "compilerversion.h"
#include "msvcprobe.h"
#include "xcodeprobe.h"
@@ -140,7 +139,6 @@ static void setCommonProperties(Profile &profile, const QString &compilerFilePat
profile.setValue(QLatin1String("cpp.toolchainInstallPath"), cfi.absolutePath());
profile.setValue(QLatin1String("qbs.toolchain"), toolchainTypes);
- setCompilerVersion(compilerFilePath, toolchainTypes, profile);
const QString suffix = compilerName.right(compilerName.size() - prefix.size());
if (!standardCompilerFileNames().contains(suffix))
diff --git a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro
index 865a445ea..f395c5458 100644
--- a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro
+++ b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro
@@ -4,20 +4,15 @@ TARGET = qbs-setup-toolchains
HEADERS += \
commandlineparser.h \
- compilerversion.h \
- msvcinfo.h \
msvcprobe.h \
probe.h \
- vsenvironmentdetector.h \
xcodeprobe.h
SOURCES += \
commandlineparser.cpp \
- compilerversion.cpp \
main.cpp \
msvcprobe.cpp \
probe.cpp \
- vsenvironmentdetector.cpp \
xcodeprobe.cpp
mingw {
diff --git a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs
index 13bb0dd01..3536b51db 100644
--- a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs
+++ b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs
@@ -6,18 +6,12 @@ QbsApp {
files: [
"commandlineparser.cpp",
"commandlineparser.h",
- "compilerversion.cpp",
- "compilerversion.h",
"main.cpp",
- "msvcinfo.h",
"msvcprobe.cpp",
"msvcprobe.h",
"probe.cpp",
"probe.h",
- "vsenvironmentdetector.cpp",
- "vsenvironmentdetector.h",
"xcodeprobe.cpp",
- "xcodeprobe.h"
+ "xcodeprobe.h",
]
}
-
diff --git a/src/lib/corelib/corelib.pro b/src/lib/corelib/corelib.pro
index 0a6a994f6..c2926f3a1 100644
--- a/src/lib/corelib/corelib.pro
+++ b/src/lib/corelib/corelib.pro
@@ -21,7 +21,7 @@ include(logging/logging.pri)
include(parser/parser.pri)
include(tools/tools.pri)
-win32:LIBS += -lpsapi
+win32:LIBS += -lpsapi -lshell32
HEADERS += \
qbs.h
diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs
index 3bf313f02..280ff9c12 100644
--- a/src/lib/corelib/corelib.qbs
+++ b/src/lib/corelib/corelib.qbs
@@ -21,7 +21,7 @@ QbsLibrary {
Properties {
condition: qbs.targetOS.contains("windows")
- cpp.dynamicLibraries: base.concat(["Psapi"])
+ cpp.dynamicLibraries: base.concat(["Psapi", "shell32"])
}
cpp.dynamicLibraries: base
@@ -339,6 +339,8 @@ QbsLibrary {
"id.cpp",
"id.h",
"installoptions.cpp",
+ "msvcinfo.cpp",
+ "msvcinfo.h",
"persistence.cpp",
"persistence.h",
"persistentobject.h",
@@ -373,6 +375,8 @@ QbsLibrary {
"version.h",
"visualstudioversioninfo.cpp",
"visualstudioversioninfo.h",
+ "vsenvironmentdetector.cpp",
+ "vsenvironmentdetector.h",
"weakpointer.h"
]
}
diff --git a/src/lib/corelib/jsextensions/utilitiesextension.cpp b/src/lib/corelib/jsextensions/utilitiesextension.cpp
index fb60da7fb..6e71c2946 100644
--- a/src/lib/corelib/jsextensions/utilitiesextension.cpp
+++ b/src/lib/corelib/jsextensions/utilitiesextension.cpp
@@ -40,6 +40,11 @@
#include <tools/applecodesignutils.h>
#endif
+#ifdef Q_OS_WIN
+#include <tools/msvcinfo.h>
+#include <tools/vsenvironmentdetector.h>
+#endif
+
#include <QCryptographicHash>
#include <QDir>
#include <QFileInfo>
@@ -65,6 +70,7 @@ public:
static QScriptValue js_smimeMessageContent(QScriptContext *context, QScriptEngine *engine);
static QScriptValue js_certificateInfo(QScriptContext *context, QScriptEngine *engine);
static QScriptValue js_signingIdentities(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue js_msvcCompilerInfo(QScriptContext *context, QScriptEngine *engine);
};
void initializeJsExtensionUtilities(QScriptValue extensionObject)
@@ -90,6 +96,8 @@ void initializeJsExtensionUtilities(QScriptValue extensionObject)
engine->newFunction(UtilitiesExtension::js_certificateInfo, 1));
environmentObj.setProperty(QStringLiteral("signingIdentities"),
engine->newFunction(UtilitiesExtension::js_signingIdentities, 0));
+ environmentObj.setProperty(QStringLiteral("msvcCompilerInfo"),
+ engine->newFunction(UtilitiesExtension::js_msvcCompilerInfo, 1));
extensionObject.setProperty(QStringLiteral("Utilities"), environmentObj);
}
@@ -241,6 +249,43 @@ QScriptValue UtilitiesExtension::js_signingIdentities(QScriptContext *context,
#endif
}
+QScriptValue UtilitiesExtension::js_msvcCompilerInfo(QScriptContext *context, QScriptEngine *engine)
+{
+#ifndef Q_OS_WIN
+ Q_UNUSED(engine);
+ return context->throwError(QScriptContext::UnknownError,
+ QLatin1String("msvcCompilerInfo is not available on this platform"));
+#else
+ if (Q_UNLIKELY(context->argumentCount() != 1))
+ return context->throwError(QScriptContext::SyntaxError,
+ QLatin1String("msvcCompilerInfo expects 1 argument"));
+
+ const QString compilerFilePath = context->argument(0).toString();
+ MSVC msvc(compilerFilePath);
+ VsEnvironmentDetector envdetector(&msvc);
+ if (!envdetector.start())
+ return context->throwError(QScriptContext::UnknownError,
+ QStringLiteral("Detecting the MSVC build environment failed: ")
+ + envdetector.errorString());
+
+ try {
+ const auto env = msvc.environments[msvc.architectures.first()];
+
+ QVariantMap envMap;
+ for (const QString &key : env.keys())
+ envMap.insert(key, env.value(key));
+
+ return engine->toScriptValue(QVariantMap {
+ {QStringLiteral("buildEnvironment"), envMap},
+ {QStringLiteral("macros"), msvc.compilerDefines(compilerFilePath)},
+ });
+ } catch (const qbs::ErrorInfo &info) {
+ return context->throwError(QScriptContext::UnknownError,
+ info.toString());
+ }
+#endif
+}
+
} // namespace Internal
} // namespace qbs
diff --git a/src/app/qbs-setup-toolchains/compilerversion.cpp b/src/lib/corelib/tools/msvcinfo.cpp
index 8de5f3ba5..0ea4e11f2 100644
--- a/src/app/qbs-setup-toolchains/compilerversion.cpp
+++ b/src/lib/corelib/tools/msvcinfo.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2016 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qbs.
@@ -27,11 +27,13 @@
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
-#include "compilerversion.h"
+
+#include "msvcinfo.h"
#include <tools/error.h>
#include <tools/profile.h>
#include <tools/version.h>
+#include <tools/vsenvironmentdetector.h>
#include <QByteArray>
#include <QDir>
@@ -40,6 +42,10 @@
#include <QStringList>
#include <QTemporaryFile>
+#ifdef Q_OS_WIN
+#include <qt_windows.h>
+#endif
+
using namespace qbs;
using namespace qbs::Internal;
@@ -69,7 +75,8 @@ private:
};
static QByteArray runProcess(const QString &exeFilePath, const QStringList &args,
- const QProcessEnvironment &env = QProcessEnvironment())
+ const QProcessEnvironment &env = QProcessEnvironment(),
+ bool allowFailure = false)
{
TemporaryEnvChanger envChanger(env);
QProcess process;
@@ -78,7 +85,7 @@ static QByteArray runProcess(const QString &exeFilePath, const QStringList &args
|| process.exitStatus() != QProcess::NormalExit) {
throw ErrorInfo(mkStr("Could not run %1 (%2)").arg(exeFilePath, process.errorString()));
}
- if (process.exitCode() != 0) {
+ if (process.exitCode() != 0 && !allowFailure) {
ErrorInfo e(mkStr("Process '%1' failed with exit code %2.")
.arg(exeFilePath).arg(process.exitCode()));
const QByteArray stdErr = process.readAllStandardError();
@@ -99,8 +106,28 @@ public:
const QString filePath;
};
-static Version getMsvcVersion(const QString &compilerFilePath,
- const QProcessEnvironment &compilerEnv)
+static QStringList parseCommandLine(const QString &commandLine)
+{
+ QStringList list;
+#ifdef Q_OS_WIN
+ wchar_t *buf = new wchar_t[commandLine.size() + 1];
+ buf[commandLine.toWCharArray(buf)] = 0;
+ int argCount = 0;
+ LPWSTR *args = CommandLineToArgvW(buf, &argCount);
+ if (!args)
+ throw ErrorInfo(mkStr("Could not parse command line arguments: ") + commandLine);
+ for (int i = 0; i < argCount; ++i)
+ list.append(QString::fromWCharArray(args[i]));
+ delete[] buf;
+#else
+ Q_UNUSED(commandLine);
+#endif
+ return list;
+}
+
+static QVariantMap getMsvcDefines(const QString &hostCompilerFilePath,
+ const QString &compilerFilePath,
+ const QProcessEnvironment &compilerEnv)
{
const QScopedPointer<QTemporaryFile> dummyFile(
new QTemporaryFile(QDir::tempPath() + QLatin1String("/qbs_dummy")));
@@ -108,8 +135,10 @@ static Version getMsvcVersion(const QString &compilerFilePath,
throw ErrorInfo(mkStr("Could not create temporary file (%1)")
.arg(dummyFile->errorString()));
}
- const QByteArray magicPrefix = "int version = ";
- dummyFile->write(magicPrefix + "_MSC_FULL_VER\r\n");
+ dummyFile->write("#include <stdio.h>\n");
+ dummyFile->write("#include <stdlib.h>\n");
+ dummyFile->write("int main(void) { char *p = getenv(\"MSC_CMD_FLAGS\");"
+ "if (p) printf(\"%s\", p); return EXIT_FAILURE; }\n");
dummyFile->close();
// We cannot use the temporary file itself, as Qt has a lock on it
@@ -121,49 +150,57 @@ static Version getMsvcVersion(const QString &compilerFilePath,
.arg(nativeDummyFilePath));
}
DummyFile actualDummyFile(actualDummyFilePath);
- const QString preprocessedFilePath = nativeDummyFilePath + QLatin1String(".i");
- const QStringList compilerArgs = QStringList() << QLatin1String("/nologo")
- << QLatin1String("/P") << nativeDummyFilePath
- << (QLatin1String("/Fi") + preprocessedFilePath);
- runProcess(compilerFilePath, compilerArgs, compilerEnv);
- QFile preprocessedFile(preprocessedFilePath);
- if (!preprocessedFile.open(QIODevice::ReadOnly)) {
- throw ErrorInfo(mkStr("Cannot read preprocessed file '%1' (%2)")
- .arg(preprocessedFilePath, preprocessedFile.errorString()));
- }
- QString versionString;
- foreach (const QByteArray &line, preprocessedFile.readAll().split('\n')) {
- const QByteArray cleanLine = line.trimmed();
- if (cleanLine.startsWith(magicPrefix)) {
- versionString = QString::fromLocal8Bit(cleanLine.mid(magicPrefix.count()));
- break;
- }
+ const QString qbsClFrontend = nativeDummyFilePath + QStringLiteral(".exe");
+
+ // The host compiler is the x86 compiler, which will execute on any edition of Windows
+ // for which host compilers have been released so far (x86, x86_64, ia64)
+ MSVC msvc2(hostCompilerFilePath);
+ VsEnvironmentDetector envdetector(&msvc2);
+ if (!envdetector.start())
+ throw ErrorInfo(QStringLiteral("Detecting the MSVC build environment failed: ")
+ + envdetector.errorString());
+ runProcess(hostCompilerFilePath, QStringList()
+ << QStringLiteral("/nologo")
+ << QStringLiteral("/TC")
+ << nativeDummyFilePath
+ << QStringLiteral("/link")
+ << (QStringLiteral("/out:") + qbsClFrontend), msvc2.environments[QString()]);
+
+ QStringList out = QString::fromLocal8Bit(runProcess(compilerFilePath, QStringList()
+ << QStringLiteral("/nologo")
+ << QStringLiteral("/B1")
+ << qbsClFrontend
+ << QStringLiteral("/c")
+ << QStringLiteral("/TC")
+ << QStringLiteral("NUL"), compilerEnv, true)).split(QStringLiteral("\r\n"));
+
+ if (out.size() != 2)
+ throw ErrorInfo(QStringLiteral("Unexpected compiler frontend output: ")
+ + out.join(QLatin1Char('\n')));
+
+ if (out.first() == QStringLiteral("NUL"))
+ out.removeFirst();
+
+ QVariantMap map;
+ const QStringList args = parseCommandLine(out.first());
+ for (const QString &arg : args) {
+ if (!arg.startsWith(QStringLiteral("-D")))
+ continue;
+ int idx = arg.indexOf(QLatin1Char('='), 2);
+ if (idx > 2)
+ map.insert(arg.mid(2, idx - 2), arg.mid(idx + 1));
+ else
+ map.insert(arg.mid(2), QVariant());
}
- if (versionString.isEmpty())
- throw ErrorInfo(mkStr("No version number found in preprocessed file."));
- if (versionString.count() < 5)
- throw ErrorInfo(mkStr("Version number '%1' not understood.").arg(versionString));
- versionString.insert(2, QLatin1Char('.')).insert(5, QLatin1Char('.'));
- const Version version = Version::fromString(versionString);
- if (!version.isValid())
- throw ErrorInfo(mkStr("Invalid version string '%1'.").arg(versionString));
- return version;
-}
+ return map;
+}
-void setCompilerVersion(const QString &compilerFilePath, const QStringList &qbsToolchain,
- Profile &profile, const QProcessEnvironment &compilerEnv)
+QVariantMap MSVC::compilerDefines(const QString &compilerFilePath) const
{
- try {
- if (qbsToolchain.contains(QLatin1String("msvc"))) {
- const Version version = getMsvcVersion(compilerFilePath, compilerEnv);
- if (version.isValid()) {
- profile.setValue(QLatin1String("cpp.compilerVersionMajor"), version.majorVersion());
- profile.setValue(QLatin1String("cpp.compilerVersionMinor"), version.minorVersion());
- profile.setValue(QLatin1String("cpp.compilerVersionPatch"), version.patchLevel());
- }
- }
- } catch (const ErrorInfo &e) {
- qDebug("Warning: Failed to retrieve compiler version: %s", qPrintable(e.toString()));
- }
+ // Should never happen
+ if (architectures.size() != 1)
+ throw ErrorInfo(mkStr("Unexpected number of architectures"));
+
+ return getMsvcDefines(clPath(), compilerFilePath, environments[architectures.first()]);
}
diff --git a/src/app/qbs-setup-toolchains/msvcinfo.h b/src/lib/corelib/tools/msvcinfo.h
index aab1bb57e..8c5c288b6 100644
--- a/src/app/qbs-setup-toolchains/msvcinfo.h
+++ b/src/lib/corelib/tools/msvcinfo.h
@@ -40,6 +40,11 @@
#include <QProcessEnvironment>
#include <QStringList>
+namespace qbs {
+namespace Internal {
+
+class Version;
+
class MSVC
{
public:
@@ -58,20 +63,22 @@ public:
QDir parentDir = QFileInfo(clPath).dir();
QString arch = parentDir.dirName().toLower();
if (arch == QLatin1String("bin"))
- arch = QLatin1String("x86");
+ arch = QString(); // x86
else
parentDir.cdUp();
architectures << arch;
installPath = parentDir.path();
}
- QString clPath(const QString &arch = QString()) {
+ QString clPath(const QString &arch = QString()) const {
return QDir::cleanPath(
installPath + QLatin1Char('/') +
pathPrefix + QLatin1Char('/') +
arch + QLatin1Char('/') +
QLatin1String("cl.exe"));
}
+
+ QBS_EXPORT QVariantMap compilerDefines(const QString &compilerFilePath) const;
};
class WinSDK : public MSVC
@@ -85,4 +92,7 @@ public:
}
};
+} // namespace Internal
+} // namespace qbs
+
#endif // QBS_MSVCINFO_H
diff --git a/src/lib/corelib/tools/tools.pri b/src/lib/corelib/tools/tools.pri
index 915ac750b..3fe070575 100644
--- a/src/lib/corelib/tools/tools.pri
+++ b/src/lib/corelib/tools/tools.pri
@@ -13,6 +13,7 @@ HEADERS += \
$$PWD/filetime.h \
$$PWD/generateoptions.h \
$$PWD/id.h \
+ $$PWD/msvcinfo.h \
$$PWD/persistence.h \
$$PWD/scannerpluginmanager.h \
$$PWD/scripttools.h \
@@ -40,7 +41,8 @@ HEADERS += \
$$PWD/qttools.h \
$$PWD/settingscreator.h \
$$PWD/version.h \
- $$PWD/visualstudioversioninfo.h
+ $$PWD/visualstudioversioninfo.h \
+ $$PWD/vsenvironmentdetector.h
SOURCES += \
$$PWD/architectures.cpp \
@@ -52,6 +54,7 @@ SOURCES += \
$$PWD/fileinfo.cpp \
$$PWD/generateoptions.cpp \
$$PWD/id.cpp \
+ $$PWD/msvcinfo.cpp \
$$PWD/persistence.cpp \
$$PWD/scannerpluginmanager.cpp \
$$PWD/scripttools.cpp \
@@ -74,7 +77,8 @@ SOURCES += \
$$PWD/settingscreator.cpp \
$$PWD/toolchains.cpp \
$$PWD/version.cpp \
- $$PWD/visualstudioversioninfo.cpp
+ $$PWD/visualstudioversioninfo.cpp \
+ $$PWD/vsenvironmentdetector.cpp
osx {
HEADERS += $$PWD/applecodesignutils.h
diff --git a/src/app/qbs-setup-toolchains/vsenvironmentdetector.cpp b/src/lib/corelib/tools/vsenvironmentdetector.cpp
index b754f23ae..1958d2c23 100644
--- a/src/app/qbs-setup-toolchains/vsenvironmentdetector.cpp
+++ b/src/lib/corelib/tools/vsenvironmentdetector.cpp
@@ -45,7 +45,8 @@
#include <ShlObj.h>
#endif
-using qbs::Internal::Tr;
+namespace qbs {
+namespace Internal {
static QString windowsSystem32Path()
{
@@ -185,3 +186,6 @@ void VsEnvironmentDetector::parseBatOutput(const QByteArray &output)
}
}
}
+
+} // namespace Internal
+} // namespace qbs
diff --git a/src/app/qbs-setup-toolchains/vsenvironmentdetector.h b/src/lib/corelib/tools/vsenvironmentdetector.h
index 2aced981d..d9856402d 100644
--- a/src/app/qbs-setup-toolchains/vsenvironmentdetector.h
+++ b/src/lib/corelib/tools/vsenvironmentdetector.h
@@ -31,15 +31,20 @@
#ifndef QBS_VSENVIRONMENTDETECTOR_H
#define QBS_VSENVIRONMENTDETECTOR_H
+#include "qbs_export.h"
+
#include <QStringList>
QT_BEGIN_NAMESPACE
class QIODevice;
QT_END_NAMESPACE
+namespace qbs {
+namespace Internal {
+
class MSVC;
-class VsEnvironmentDetector
+class QBS_EXPORT VsEnvironmentDetector
{
public:
VsEnvironmentDetector(MSVC *msvc);
@@ -56,4 +61,7 @@ private:
QString m_errorString;
};
+} // namespace Internal
+} // namespace qbs
+
#endif // QBS_VSENVIRONMENTDETECTOR_H