aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoerg Bornemann <joerg.bornemann@qt.io>2016-11-07 18:16:51 +0100
committerJoerg Bornemann <joerg.bornemann@qt.io>2016-11-10 15:13:21 +0000
commit684548e2634ca620ae24b73f7715b70ac90cbb76 (patch)
tree44f4b7d5716cf8b8ac896646eb3aa2b5223b95ca
parent171a104ec567d660fd3ac44cfc2031ac748f6d56 (diff)
Refactor MSVC toolchain detection
Have one MSVC object per MSVC installation instead of one MSVC per VS installation with some list members. This cleans up the code quite a bit and prepares for VS 15 support and speed improvements. Change-Id: Idf6759e5b05584532f56be4036c87df310363bd3 Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
-rw-r--r--src/app/qbs-setup-toolchains/msvcprobe.cpp99
-rw-r--r--src/lib/corelib/jsextensions/utilitiesextension.cpp10
-rw-r--r--src/lib/corelib/tools/msvcinfo.cpp27
-rw-r--r--src/lib/corelib/tools/msvcinfo.h34
-rw-r--r--src/lib/corelib/tools/vsenvironmentdetector.cpp69
-rw-r--r--src/lib/corelib/tools/vsenvironmentdetector.h12
6 files changed, 141 insertions, 110 deletions
diff --git a/src/app/qbs-setup-toolchains/msvcprobe.cpp b/src/app/qbs-setup-toolchains/msvcprobe.cpp
index 7ec15e44a..08d92319a 100644
--- a/src/app/qbs-setup-toolchains/msvcprobe.cpp
+++ b/src/app/qbs-setup-toolchains/msvcprobe.cpp
@@ -71,8 +71,8 @@ static void setQtHelperProperties(Profile &p, const QString &architecture,
const QString &compilerFilePath)
{
MSVC msvc(compilerFilePath);
- VsEnvironmentDetector envdetector(&msvc);
- if (!envdetector.start()) {
+ VsEnvironmentDetector envdetector;
+ if (!envdetector.start(&msvc)) {
qbsWarning() << (QStringLiteral("Detecting the MSVC build environment failed: ")
+ envdetector.errorString());
return;
@@ -95,32 +95,22 @@ static void setQtHelperProperties(Profile &p, const QString &architecture,
}
}
-static void addMSVCPlatform(Settings *settings, QList<Profile> &profiles,
- QString name, const QString &installPath, const QString &architecture,
- bool appendArchToName = true)
+static void addMSVCPlatform(Settings *settings, QList<Profile> &profiles, QString name, MSVC *msvc)
{
- 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("qbs.toolchain"), QStringList(QLatin1String("msvc")));
- p.setValue(QLatin1String("cpp.toolchainInstallPath"),
- toolchainInstallPath.join(QDir::separator()));
- setQtHelperProperties(p, architecture,
- toolchainInstallPath.join(QDir::separator()) + QLatin1String("/cl.exe"));
+ p.setValue(QLatin1String("cpp.toolchainInstallPath"), msvc->binPath);
+ setQtHelperProperties(p, msvc->architecture, msvc->binPath + QLatin1String("/cl.exe"));
profiles << p;
}
-static void findSupportedArchitectures(MSVC *msvc)
+static QStringList findSupportedArchitectures(MSVC *msvc)
{
static const QStringList knownArchitectures = QStringList()
- << QString() // x86_x86
+ << QStringLiteral("x86")
<< QStringLiteral("amd64_x86")
<< QStringLiteral("amd64")
<< QStringLiteral("x86_amd64")
@@ -128,10 +118,12 @@ static void findSupportedArchitectures(MSVC *msvc)
<< QStringLiteral("x86_ia64")
<< QStringLiteral("x86_arm")
<< QStringLiteral("amd64_arm");
+ QStringList result;
for (const QString &knownArchitecture : knownArchitectures) {
- if (QFile::exists(msvc->clPath(knownArchitecture)))
- msvc->architectures += knownArchitecture;
+ if (QFile::exists(msvc->clPathForArchitecture(knownArchitecture)))
+ result += knownArchitecture;
}
+ return result;
}
static QString wow6432Key()
@@ -159,24 +151,26 @@ void msvcProbe(Settings *settings, QList<Profile> &profiles)
foreach (const QString &sdkKey, sdkRegistry.childGroups()) {
WinSDK sdk;
sdk.version = sdkKey;
- sdk.installPath = sdkRegistry.value(sdkKey + QLatin1String("/InstallationFolder")).toString();
- sdk.isDefault = (sdk.installPath == defaultSdkPath);
- if (sdk.installPath.isEmpty())
+ sdk.vcInstallPath = sdkRegistry.value(sdkKey + QLatin1String("/InstallationFolder")).toString();
+ sdk.isDefault = (sdk.vcInstallPath == defaultSdkPath);
+ if (sdk.vcInstallPath.isEmpty())
continue;
- if (sdk.installPath.endsWith(QLatin1Char('\\')))
- sdk.installPath.chop(1);
- findSupportedArchitectures(&sdk);
+ if (sdk.vcInstallPath.endsWith(QLatin1Char('\\')))
+ sdk.vcInstallPath.chop(1);
if (sdk.isDefault)
defaultWinSDK = sdk;
- winSDKs += sdk;
+ foreach (const QString &arch, findSupportedArchitectures(&sdk)) {
+ WinSDK specificSDK = sdk;
+ specificSDK.architecture = arch;
+ specificSDK.binPath = specificSDK.binPathForArchitecture(arch);
+ winSDKs += specificSDK;
+ }
}
}
foreach (const WinSDK &sdk, winSDKs) {
qbsInfo() << Tr::tr(" Windows SDK %1 detected:\n"
- " installed in %2").arg(sdk.version, sdk.installPath);
- if (!sdk.architectures.isEmpty())
- qbsInfo() << Tr::tr(" This SDK contains C++ compiler(s).");
+ " installed in %2").arg(sdk.version, sdk.vcInstallPath);
if (sdk.isDefault)
qbsInfo() << Tr::tr(" This is the default SDK on this machine.");
}
@@ -194,11 +188,10 @@ void msvcProbe(Settings *settings, QList<Profile> &profiles)
continue;
MSVC msvc;
- msvc.installPath = vsRegistry.value(vsName).toString();
- if (!msvc.installPath.endsWith(QLatin1Char('\\')))
- msvc.installPath += QLatin1Char('\\');
- msvc.installPath += QLatin1String("bin");
- findSupportedArchitectures(&msvc);
+ msvc.vcInstallPath = vsRegistry.value(vsName).toString();
+ if (!msvc.vcInstallPath.endsWith(QLatin1Char('\\')))
+ msvc.vcInstallPath += QLatin1Char('\\');
+ msvc.vcInstallPath += QLatin1String("bin");
msvc.version = QString::number(Internal::VisualStudioVersionInfo(
Internal::Version::fromString(vsName)).marketingVersion());
@@ -208,17 +201,22 @@ void msvcProbe(Settings *settings, QList<Profile> &profiles)
}
// Check existence of various install scripts
- const QString vcvars32bat = msvc.installPath + QLatin1String("/vcvars32.bat");
+ const QString vcvars32bat = msvc.vcInstallPath + QLatin1String("/vcvars32.bat");
if (!QFileInfo(vcvars32bat).isFile())
continue;
- msvcs += msvc;
+ foreach (const QString &arch, findSupportedArchitectures(&msvc)) {
+ MSVC specificMSVC = msvc;
+ specificMSVC.architecture = arch;
+ specificMSVC.binPath = specificMSVC.binPathForArchitecture(arch);
+ msvcs += specificMSVC;
+ }
}
foreach (const MSVC &msvc, msvcs) {
- qbsInfo() << Tr::tr(" MSVC detected:\n"
- " version %1\n"
- " installed in %2").arg(msvc.version, msvc.installPath);
+ qbsInfo() << Tr::tr(" MSVC %1 (%2) detected in\n"
+ " %3").arg(msvc.version, msvc.architecture,
+ QDir::toNativeSeparators(msvc.binPath));
}
if (winSDKs.isEmpty() && msvcs.isEmpty()) {
@@ -227,18 +225,18 @@ void msvcProbe(Settings *settings, QList<Profile> &profiles)
return;
}
- foreach (const WinSDK &sdk, winSDKs) {
- foreach (const QString &arch, sdk.architectures) {
- addMSVCPlatform(settings, profiles, QLatin1String("WinSDK") + sdk.version,
- sdk.installPath + QLatin1String("\\bin"), arch);
- }
+ for (int i = 0; i < winSDKs.count(); ++i) {
+ WinSDK &sdk = winSDKs[i];
+ const QString name = QLatin1String("WinSDK") + sdk.version + QLatin1Char('-')
+ + sdk.architecture;
+ addMSVCPlatform(settings, profiles, name, &sdk);
}
- foreach (const MSVC &msvc, msvcs) {
- foreach (const QString &arch, msvc.architectures) {
- addMSVCPlatform(settings, profiles, QLatin1String("MSVC") + msvc.version,
- msvc.installPath, arch);
- }
+ for (int i = 0; i < msvcs.count(); ++i) {
+ MSVC &msvc = msvcs[i];
+ const QString name = QLatin1String("MSVC") + msvc.version + QLatin1Char('-')
+ + msvc.architecture;
+ addMSVCPlatform(settings, profiles, name, &msvc);
}
}
@@ -247,8 +245,7 @@ void createMsvcProfile(const QString &profileName, const QString &compilerFilePa
{
MSVC msvc(compilerFilePath);
QList<Profile> dummy;
- addMSVCPlatform(settings, dummy, profileName, msvc.installPath,
- msvc.architectures.first(), false);
+ addMSVCPlatform(settings, dummy, profileName, &msvc);
qbsInfo() << Tr::tr("Profile '%1' created for '%2'.")
.arg(profileName, QDir::toNativeSeparators(compilerFilePath));
}
diff --git a/src/lib/corelib/jsextensions/utilitiesextension.cpp b/src/lib/corelib/jsextensions/utilitiesextension.cpp
index e8ca1ffe0..1463438fc 100644
--- a/src/lib/corelib/jsextensions/utilitiesextension.cpp
+++ b/src/lib/corelib/jsextensions/utilitiesextension.cpp
@@ -274,18 +274,16 @@ QScriptValue UtilitiesExtension::js_msvcCompilerInfo(QScriptContext *context, QS
const QString compilerFilePath = context->argument(0).toString();
MSVC msvc(compilerFilePath);
- VsEnvironmentDetector envdetector(&msvc);
- if (!envdetector.start())
+ VsEnvironmentDetector envdetector;
+ if (!envdetector.start(&msvc))
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));
+ for (const QString &key : msvc.environment.keys())
+ envMap.insert(key, msvc.environment.value(key));
return engine->toScriptValue(QVariantMap {
{QStringLiteral("buildEnvironment"), envMap},
diff --git a/src/lib/corelib/tools/msvcinfo.cpp b/src/lib/corelib/tools/msvcinfo.cpp
index ce3a540a4..e2862a591 100644
--- a/src/lib/corelib/tools/msvcinfo.cpp
+++ b/src/lib/corelib/tools/msvcinfo.cpp
@@ -167,8 +167,8 @@ static QVariantMap getMsvcDefines(const QString &hostCompilerFilePath,
// 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())
+ VsEnvironmentDetector envdetector;
+ if (!envdetector.start(&msvc2))
throw ErrorInfo(QStringLiteral("Detecting the MSVC build environment failed: ")
+ envdetector.errorString());
runProcess(hostCompilerFilePath, QStringList()
@@ -177,7 +177,7 @@ static QVariantMap getMsvcDefines(const QString &hostCompilerFilePath,
<< (QStringLiteral("/Fo") + qbsClFrontendObj)
<< nativeDummyFilePath
<< QStringLiteral("/link")
- << (QStringLiteral("/out:") + qbsClFrontend), msvc2.environments[QString()]);
+ << (QStringLiteral("/out:") + qbsClFrontend), msvc2.environment);
QStringList out = QString::fromLocal8Bit(runProcess(compilerFilePath, QStringList()
<< QStringLiteral("/nologo")
@@ -209,11 +209,22 @@ static QVariantMap getMsvcDefines(const QString &hostCompilerFilePath,
return map;
}
-QVariantMap MSVC::compilerDefines(const QString &compilerFilePath) const
+QString MSVC::binPathForArchitecture(const QString &arch) const
{
- // Should never happen
- if (architectures.size() != 1)
- throw ErrorInfo(mkStr("Unexpected number of architectures"));
+ QString archSubDir;
+ if (arch != QStringLiteral("x86"))
+ archSubDir = arch;
+ return QDir::cleanPath(vcInstallPath + QLatin1Char('/') + pathPrefix + QLatin1Char('/')
+ + archSubDir);
+}
- return getMsvcDefines(clPath(), compilerFilePath, environments[architectures.first()]);
+QString MSVC::clPathForArchitecture(const QString &arch) const
+{
+ return binPathForArchitecture(arch) + QLatin1String("/cl.exe");
+}
+
+QVariantMap MSVC::compilerDefines(const QString &compilerFilePath) const
+{
+ return getMsvcDefines(clPathForArchitecture(QStringLiteral("x86")), compilerFilePath,
+ environment);
}
diff --git a/src/lib/corelib/tools/msvcinfo.h b/src/lib/corelib/tools/msvcinfo.h
index 8b8f16d6b..9e9c68cf3 100644
--- a/src/lib/corelib/tools/msvcinfo.h
+++ b/src/lib/corelib/tools/msvcinfo.h
@@ -54,39 +54,37 @@ namespace Internal {
class Version;
+/**
+ * Represents one MSVC installation for one specific target architecture.
+ * There are potentially multiple MSVCs in one Visual Studio installation.
+ */
class MSVC
{
public:
QString version;
- QString installPath;
+ QString vcInstallPath;
+ QString binPath;
QString pathPrefix;
- QStringList architectures;
-
- typedef QHash<QString, QProcessEnvironment> EnvironmentPerArch;
- EnvironmentPerArch environments;
+ QString architecture;
+ QProcessEnvironment environment;
MSVC() { }
MSVC(const QString &clPath)
{
QDir parentDir = QFileInfo(clPath).dir();
- QString arch = parentDir.dirName().toLower();
- if (arch == QLatin1String("bin"))
- arch = QString(); // x86
+ QString parentDirName = parentDir.dirName().toLower();
+ if (parentDirName == QLatin1String("bin"))
+ parentDirName = QStringLiteral("x86");
else
parentDir.cdUp();
- architectures << arch;
- installPath = parentDir.path();
- }
-
- QString clPath(const QString &arch = QString()) const {
- return QDir::cleanPath(
- installPath + QLatin1Char('/') +
- pathPrefix + QLatin1Char('/') +
- arch + QLatin1Char('/') +
- QLatin1String("cl.exe"));
+ architecture = parentDirName;
+ vcInstallPath = parentDir.path();
+ binPath = vcInstallPath;
}
+ QBS_EXPORT QString binPathForArchitecture(const QString &arch) const;
+ QBS_EXPORT QString clPathForArchitecture(const QString &arch) const;
QBS_EXPORT QVariantMap compilerDefines(const QString &compilerFilePath) const;
};
diff --git a/src/lib/corelib/tools/vsenvironmentdetector.cpp b/src/lib/corelib/tools/vsenvironmentdetector.cpp
index 5617e0bd7..c4db89fec 100644
--- a/src/lib/corelib/tools/vsenvironmentdetector.cpp
+++ b/src/lib/corelib/tools/vsenvironmentdetector.cpp
@@ -39,7 +39,6 @@
#include "vsenvironmentdetector.h"
-#include "msvcinfo.h"
#include <logging/translator.h>
#include <tools/qbsassert.h>
@@ -67,16 +66,41 @@ static QString windowsSystem32Path()
return QString();
}
-VsEnvironmentDetector::VsEnvironmentDetector(MSVC *msvc)
- : m_msvc(msvc)
- , m_windowsSystemDirPath(windowsSystem32Path())
+VsEnvironmentDetector::VsEnvironmentDetector()
+ : m_windowsSystemDirPath(windowsSystem32Path())
{
}
-bool VsEnvironmentDetector::start()
+bool VsEnvironmentDetector::start(MSVC *msvc)
{
- m_msvc->environments.clear();
- const QString vcvarsallbat = QDir::cleanPath(m_msvc->installPath
+ return start(QVector<MSVC *>() << msvc);
+}
+
+bool VsEnvironmentDetector::start(QVector<MSVC *> msvcs)
+{
+ std::sort(msvcs.begin(), msvcs.end(), [] (const MSVC *a, const MSVC *b) -> bool {
+ return a->vcInstallPath < b->vcInstallPath;
+ });
+
+ QVector<MSVC *> compatibleMSVCs;
+ QString lastVcInstallPath;
+ foreach (MSVC *msvc, msvcs) {
+ if (lastVcInstallPath != msvc->vcInstallPath) {
+ lastVcInstallPath = msvc->vcInstallPath;
+ if (!compatibleMSVCs.isEmpty()) {
+ startDetection(compatibleMSVCs);
+ compatibleMSVCs.clear();
+ }
+ }
+ compatibleMSVCs.append(msvc);
+ }
+ startDetection(compatibleMSVCs);
+ return true;
+}
+
+bool VsEnvironmentDetector::startDetection(const QVector<MSVC *> &compatibleMSVCs)
+{
+ const QString vcvarsallbat = QDir::cleanPath(compatibleMSVCs.first()->vcInstallPath
+ QLatin1String("/../vcvarsall.bat"));
if (!QFile::exists(vcvarsallbat)) {
m_errorString = Tr::tr("Cannot find '%1'.").arg(QDir::toNativeSeparators(vcvarsallbat));
@@ -90,7 +114,7 @@ bool VsEnvironmentDetector::start()
return false;
}
- writeBatchFile(&tmpFile, vcvarsallbat);
+ writeBatchFile(&tmpFile, vcvarsallbat, compatibleMSVCs);
tmpFile.flush();
QProcess process;
@@ -110,8 +134,9 @@ bool VsEnvironmentDetector::start()
m_errorString = Tr::tr("Failed to detect Visual Studio environment.");
return false;
}
- parseBatOutput(process.readAllStandardOutput());
+ parseBatOutput(process.readAllStandardOutput(), compatibleMSVCs);
return true;
+
}
static void batClearVars(QTextStream &s, const QStringList &varnames)
@@ -126,18 +151,17 @@ static void batPrintVars(QTextStream &s, const QStringList &varnames)
s << "echo " << varname << "=%" << varname << '%' << endl;
}
-static QString vcArchitecture(MSVC *msvc, const QString &targetArch)
+static QString vcArchitecture(const MSVC *msvc)
{
- QString vcArch = targetArch;
- if (targetArch == QLatin1String("armv7"))
+ QString vcArch = msvc->architecture;
+ if (msvc->architecture == QLatin1String("armv7"))
vcArch = QLatin1String("arm");
- if (targetArch == QLatin1String("x86_64"))
+ if (msvc->architecture == QLatin1String("x86_64"))
vcArch = QLatin1String("amd64");
- // Empty string for the native compiler (preferred)
for (const QString &hostPrefix :
- QStringList({QString(), QStringLiteral("amd64_"), QStringLiteral("x86_")})) {
- if (QFile::exists(msvc->clPath(hostPrefix + vcArch))) {
+ QStringList({QStringLiteral("x86"), QStringLiteral("amd64_"), QStringLiteral("x86_")})) {
+ if (QFile::exists(msvc->clPathForArchitecture(hostPrefix + vcArch))) {
vcArch.prepend(hostPrefix);
break;
}
@@ -146,25 +170,26 @@ static QString vcArchitecture(MSVC *msvc, const QString &targetArch)
return vcArch;
}
-void VsEnvironmentDetector::writeBatchFile(QIODevice *device, const QString &vcvarsallbat) const
+void VsEnvironmentDetector::writeBatchFile(QIODevice *device, const QString &vcvarsallbat,
+ const QVector<MSVC *> &msvcs) const
{
const QStringList varnames = QStringList() << QLatin1String("PATH")
<< QLatin1String("INCLUDE") << QLatin1String("LIB");
QTextStream s(device);
s << "@echo off" << endl;
- foreach (const QString &architecture, m_msvc->architectures) {
- s << "echo --" << architecture << "--" << endl
+ for (const MSVC *msvc : msvcs) {
+ s << "echo --" << msvc->architecture << "--" << endl
<< "setlocal" << endl;
batClearVars(s, varnames);
s << "set PATH=" << m_windowsSystemDirPath << endl; // vcvarsall.bat needs tools from here
- s << "call \"" << vcvarsallbat << "\" " << vcArchitecture(m_msvc, architecture)
+ s << "call \"" << vcvarsallbat << "\" " << vcArchitecture(msvc)
<< " || exit /b 1" << endl;
batPrintVars(s, varnames);
s << "endlocal" << endl;
}
}
-void VsEnvironmentDetector::parseBatOutput(const QByteArray &output)
+void VsEnvironmentDetector::parseBatOutput(const QByteArray &output, QVector<MSVC *> msvcs)
{
QString arch;
QProcessEnvironment *targetEnv = 0;
@@ -177,7 +202,7 @@ void VsEnvironmentDetector::parseBatOutput(const QByteArray &output)
line.remove(0, 2);
line.chop(2);
arch = QString::fromLocal8Bit(line);
- targetEnv = &m_msvc->environments[arch];
+ targetEnv = &msvcs.takeFirst()->environment;
} else {
int idx = line.indexOf('=');
if (idx < 0)
diff --git a/src/lib/corelib/tools/vsenvironmentdetector.h b/src/lib/corelib/tools/vsenvironmentdetector.h
index 00b2cc9c9..114f792ee 100644
--- a/src/lib/corelib/tools/vsenvironmentdetector.h
+++ b/src/lib/corelib/tools/vsenvironmentdetector.h
@@ -41,6 +41,7 @@
#define QBS_VSENVIRONMENTDETECTOR_H
#include "qbs_export.h"
+#include "msvcinfo.h"
#include <QStringList>
@@ -56,16 +57,17 @@ class MSVC;
class QBS_EXPORT VsEnvironmentDetector
{
public:
- VsEnvironmentDetector(MSVC *msvc);
+ VsEnvironmentDetector();
- bool start();
+ bool start(MSVC *msvc);
+ bool start(QVector<MSVC *> msvcs);
QString errorString() const { return m_errorString; }
private:
- void writeBatchFile(QIODevice *device, const QString &vcvarsallbat) const;
- void parseBatOutput(const QByteArray &output);
+ bool startDetection(const QVector<MSVC *> &compatibleMSVCs);
+ void writeBatchFile(QIODevice *device, const QString &vcvarsallbat, const QVector<MSVC *> &msvcs) const;
+ void parseBatOutput(const QByteArray &output, QVector<MSVC *> msvcs);
- MSVC *m_msvc;
const QString m_windowsSystemDirPath;
QString m_errorString;
};