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/app | |
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/app')
-rw-r--r-- | src/app/qbs-setup-toolchains/compilerversion.cpp | 169 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/compilerversion.h | 47 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/msvcinfo.h | 88 | ||||
-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/app/qbs-setup-toolchains/vsenvironmentdetector.cpp | 187 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/vsenvironmentdetector.h | 59 |
9 files changed, 52 insertions, 605 deletions
diff --git a/src/app/qbs-setup-toolchains/compilerversion.cpp b/src/app/qbs-setup-toolchains/compilerversion.cpp deleted file mode 100644 index 8de5f3ba5..000000000 --- a/src/app/qbs-setup-toolchains/compilerversion.cpp +++ /dev/null @@ -1,169 +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. -** -****************************************************************************/ -#include "compilerversion.h" - -#include <tools/error.h> -#include <tools/profile.h> -#include <tools/version.h> - -#include <QByteArray> -#include <QDir> -#include <QProcess> -#include <QScopedPointer> -#include <QStringList> -#include <QTemporaryFile> - -using namespace qbs; -using namespace qbs::Internal; - -static QString mkStr(const char *s) { return QString::fromLocal8Bit(s); } -static QString mkStr(const QByteArray &ba) { return mkStr(ba.constData()); } - -class TemporaryEnvChanger -{ -public: - TemporaryEnvChanger(const QProcessEnvironment &envChanges) - { - QProcessEnvironment currentEnv = QProcessEnvironment::systemEnvironment(); - foreach (const QString &key, envChanges.keys()) { - m_changesToRestore.insert(key, currentEnv.value(key)); - qputenv(qPrintable(key), qPrintable(envChanges.value(key))); - } - } - - ~TemporaryEnvChanger() - { - foreach (const QString &key, m_changesToRestore.keys()) - qputenv(qPrintable(key), qPrintable(m_changesToRestore.value(key))); - } - -private: - QProcessEnvironment m_changesToRestore; -}; - -static QByteArray runProcess(const QString &exeFilePath, const QStringList &args, - const QProcessEnvironment &env = QProcessEnvironment()) -{ - TemporaryEnvChanger envChanger(env); - QProcess process; - process.start(exeFilePath, args); - if (!process.waitForStarted() || !process.waitForFinished() - || process.exitStatus() != QProcess::NormalExit) { - throw ErrorInfo(mkStr("Could not run %1 (%2)").arg(exeFilePath, process.errorString())); - } - if (process.exitCode() != 0) { - ErrorInfo e(mkStr("Process '%1' failed with exit code %2.") - .arg(exeFilePath).arg(process.exitCode())); - const QByteArray stdErr = process.readAllStandardError(); - if (!stdErr.isEmpty()) - e.append(mkStr("stderr was: %1").arg(mkStr(stdErr))); - const QByteArray stdOut = process.readAllStandardOutput(); - if (!stdOut.isEmpty()) - e.append(mkStr("stdout was: %1").arg(mkStr(stdOut))); - throw e; - } - return process.readAllStandardOutput().trimmed(); -} - -class DummyFile { -public: - DummyFile(const QString &fp) : filePath(fp) { } - ~DummyFile() { QFile::remove(filePath); } - const QString filePath; -}; - -static Version getMsvcVersion(const QString &compilerFilePath, - const QProcessEnvironment &compilerEnv) -{ - const QScopedPointer<QTemporaryFile> dummyFile( - new QTemporaryFile(QDir::tempPath() + QLatin1String("/qbs_dummy"))); - if (!dummyFile->open()) { - 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->close(); - - // We cannot use the temporary file itself, as Qt has a lock on it - // even after it was closed, causing a "Permission denied" message from MSVC. - const QString actualDummyFilePath = dummyFile->fileName() + QLatin1String(".1"); - const QString nativeDummyFilePath = QDir::toNativeSeparators(actualDummyFilePath); - if (!QFile::copy(dummyFile->fileName(), actualDummyFilePath)) { - throw ErrorInfo(mkStr("Could not create source '%1' file for compiler.") - .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; - } - } - 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; -} - - -void setCompilerVersion(const QString &compilerFilePath, const QStringList &qbsToolchain, - Profile &profile, const QProcessEnvironment &compilerEnv) -{ - 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())); - } -} 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/msvcinfo.h b/src/app/qbs-setup-toolchains/msvcinfo.h deleted file mode 100644 index aab1bb57e..000000000 --- a/src/app/qbs-setup-toolchains/msvcinfo.h +++ /dev/null @@ -1,88 +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_MSVCINFO_H -#define QBS_MSVCINFO_H - -#include <logging/translator.h> -#include <tools/error.h> - -#include <QDir> -#include <QFileInfo> -#include <QHash> -#include <QProcessEnvironment> -#include <QStringList> - -class MSVC -{ -public: - QString version; - QString installPath; - QString pathPrefix; - QStringList architectures; - - typedef QHash<QString, QProcessEnvironment> EnvironmentPerArch; - EnvironmentPerArch environments; - - MSVC() { } - - MSVC(const QString &clPath) - { - QDir parentDir = QFileInfo(clPath).dir(); - QString arch = parentDir.dirName().toLower(); - if (arch == QLatin1String("bin")) - arch = QLatin1String("x86"); - else - parentDir.cdUp(); - architectures << arch; - installPath = parentDir.path(); - } - - QString clPath(const QString &arch = QString()) { - return QDir::cleanPath( - installPath + QLatin1Char('/') + - pathPrefix + QLatin1Char('/') + - arch + QLatin1Char('/') + - QLatin1String("cl.exe")); - } -}; - -class WinSDK : public MSVC -{ -public: - bool isDefault; - - WinSDK() - { - pathPrefix = QLatin1String("bin"); - } -}; - -#endif // QBS_MSVCINFO_H 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/app/qbs-setup-toolchains/vsenvironmentdetector.cpp b/src/app/qbs-setup-toolchains/vsenvironmentdetector.cpp deleted file mode 100644 index b754f23ae..000000000 --- a/src/app/qbs-setup-toolchains/vsenvironmentdetector.cpp +++ /dev/null @@ -1,187 +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. -** -****************************************************************************/ - -#include "vsenvironmentdetector.h" - -#include "msvcinfo.h" -#include <logging/translator.h> -#include <tools/qbsassert.h> - -#include <QDebug> -#include <QDir> -#include <QProcess> -#include <QTemporaryFile> -#include <QTextStream> - -#ifdef Q_OS_WIN -#include <qt_windows.h> -#include <ShlObj.h> -#endif - -using qbs::Internal::Tr; - -static QString windowsSystem32Path() -{ -#ifdef Q_OS_WIN - wchar_t str[MAX_PATH]; - if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_SYSTEM, NULL, 0, str))) - return QString::fromUtf16(reinterpret_cast<ushort*>(str)); -#endif - return QString(); -} - -VsEnvironmentDetector::VsEnvironmentDetector(MSVC *msvc) - : m_msvc(msvc) - , m_windowsSystemDirPath(windowsSystem32Path()) -{ -} - -bool VsEnvironmentDetector::start() -{ - m_msvc->environments.clear(); - const QString vcvarsallbat = QDir::cleanPath(m_msvc->installPath - + QLatin1String("/../vcvarsall.bat")); - if (!QFile::exists(vcvarsallbat)) { - m_errorString = Tr::tr("Cannot find '%1'.").arg(QDir::toNativeSeparators(vcvarsallbat)); - return false; - } - - QTemporaryFile tmpFile(QDir::tempPath() + QLatin1Char('/') + QLatin1String("XXXXXX.bat")); - if (!tmpFile.open()) { - m_errorString = Tr::tr("Cannot open temporary file '%1' for writing.").arg( - tmpFile.fileName()); - return false; - } - - writeBatchFile(&tmpFile, vcvarsallbat); - tmpFile.flush(); - - QProcess process; - const QString shellFilePath = QLatin1String("cmd.exe"); - process.start(shellFilePath, QStringList() - << QLatin1String("/C") << tmpFile.fileName()); - if (!process.waitForStarted()) { - m_errorString = Tr::tr("Failed to start '%1'.").arg(shellFilePath); - return false; - } - process.waitForFinished(-1); - if (process.exitStatus() != QProcess::NormalExit) { - m_errorString = Tr::tr("Process '%1' did not exit normally.").arg(shellFilePath); - return false; - } - if (process.exitCode() != 0) { - m_errorString = Tr::tr("Failed to detect Visual Studio environment."); - return false; - } - parseBatOutput(process.readAllStandardOutput()); - return true; -} - -static void batClearVars(QTextStream &s, const QStringList &varnames) -{ - foreach (const QString &varname, varnames) - s << "set " << varname << '=' << endl; -} - -static void batPrintVars(QTextStream &s, const QStringList &varnames) -{ - foreach (const QString &varname, varnames) - s << "echo " << varname << "=%" << varname << '%' << endl; -} - -static QString vcArchitecture(MSVC *msvc, const QString &targetArch) -{ - QString vcArch = targetArch; - if (targetArch == QLatin1String("armv7")) - vcArch = QLatin1String("arm"); - if (targetArch == 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))) { - vcArch.prepend(hostPrefix); - break; - } - } - - return vcArch; -} - -void VsEnvironmentDetector::writeBatchFile(QIODevice *device, const QString &vcvarsallbat) 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 - << "setlocal" << endl; - batClearVars(s, varnames); - s << "set PATH=" << m_windowsSystemDirPath << endl; // vcvarsall.bat needs tools from here - s << "call \"" << vcvarsallbat << "\" " << vcArchitecture(m_msvc, architecture) - << " || exit /b 1" << endl; - batPrintVars(s, varnames); - s << "endlocal" << endl; - } -} - -void VsEnvironmentDetector::parseBatOutput(const QByteArray &output) -{ - QString arch; - QProcessEnvironment *targetEnv = 0; - foreach (QByteArray line, output.split('\n')) { - line = line.trimmed(); - if (line.isEmpty()) - continue; - - if (line.startsWith("--") && line.endsWith("--")) { - line.remove(0, 2); - line.chop(2); - arch = QString::fromLocal8Bit(line); - targetEnv = &m_msvc->environments[arch]; - } else { - int idx = line.indexOf('='); - if (idx < 0) - continue; - QBS_CHECK(targetEnv); - const QString name = QString::fromLocal8Bit(line.left(idx)); - QString value = QString::fromLocal8Bit(line.mid(idx + 1)); - if (name.compare(QLatin1String("PATH"), Qt::CaseInsensitive) == 0) - value.remove(m_windowsSystemDirPath); - if (value.endsWith(QLatin1Char(';'))) - value.chop(1); - if (value.endsWith(QLatin1Char('\\'))) - value.chop(1); - targetEnv->insert(name, value); - } - } -} diff --git a/src/app/qbs-setup-toolchains/vsenvironmentdetector.h b/src/app/qbs-setup-toolchains/vsenvironmentdetector.h deleted file mode 100644 index 2aced981d..000000000 --- a/src/app/qbs-setup-toolchains/vsenvironmentdetector.h +++ /dev/null @@ -1,59 +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_VSENVIRONMENTDETECTOR_H -#define QBS_VSENVIRONMENTDETECTOR_H - -#include <QStringList> - -QT_BEGIN_NAMESPACE -class QIODevice; -QT_END_NAMESPACE - -class MSVC; - -class VsEnvironmentDetector -{ -public: - VsEnvironmentDetector(MSVC *msvc); - - bool start(); - QString errorString() const { return m_errorString; } - -private: - void writeBatchFile(QIODevice *device, const QString &vcvarsallbat) const; - void parseBatOutput(const QByteArray &output); - - MSVC *m_msvc; - const QString m_windowsSystemDirPath; - QString m_errorString; -}; - -#endif // QBS_VSENVIRONMENTDETECTOR_H |