diff options
author | Jake Petroules <jake.petroules@qt.io> | 2016-05-22 15:37:18 -0700 |
---|---|---|
committer | Joerg Bornemann <joerg.bornemann@qt.io> | 2016-06-27 13:13:52 +0000 |
commit | 129e7a8ab1edfb583157db6050ab3f1bd426279e (patch) | |
tree | 6f3634e0c1ce07501a1368a774ef62fe1106f065 /src | |
parent | 2ea9e28a6963cae217923d77fd00f581306b1980 (diff) |
Determine Visual Studio architecture & build environment automatically.
This moves one step further to making the setup-toolchains tool
unnecessary and also makes the toolchainInstallPath of MSVC
profiles consistent with what Qt Creator sets.
Change-Id: I3eb11b456bf02bde8993ec0dac7e0f9950174a08
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/app/qbs-setup-toolchains/compilerversion.h | 47 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/msvcprobe.cpp | 92 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/probe.cpp | 2 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro | 5 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs | 8 | ||||
-rw-r--r-- | src/lib/corelib/corelib.pro | 2 | ||||
-rw-r--r-- | src/lib/corelib/corelib.qbs | 6 | ||||
-rw-r--r-- | src/lib/corelib/jsextensions/utilitiesextension.cpp | 45 | ||||
-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.pri | 8 | ||||
-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 |
13 files changed, 221 insertions, 159 deletions
diff --git a/src/app/qbs-setup-toolchains/compilerversion.h b/src/app/qbs-setup-toolchains/compilerversion.h deleted file mode 100644 index df9f66045..000000000 --- a/src/app/qbs-setup-toolchains/compilerversion.h +++ /dev/null @@ -1,47 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing -** -** This file is part of Qbs. -** -** 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 http://www.qt.io/terms-conditions. For further information -** use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** 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> - -namespace qbs { class Profile; } - -QT_BEGIN_NAMESPACE -class QString; -class QStringList; -QT_END_NAMESPACE - -void setCompilerVersion(const QString &compilerFilePath, const QStringList &qbsToolchain, - qbs::Profile &profile, - const QProcessEnvironment &compilerEnv = QProcessEnvironment()); - -#endif // Include guard 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 |