aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/corelib/tools
diff options
context:
space:
mode:
authorJake Petroules <jake.petroules@qt.io>2016-05-22 15:37:18 -0700
committerJoerg Bornemann <joerg.bornemann@qt.io>2016-06-27 13:13:52 +0000
commit129e7a8ab1edfb583157db6050ab3f1bd426279e (patch)
tree6f3634e0c1ce07501a1368a774ef62fe1106f065 /src/lib/corelib/tools
parent2ea9e28a6963cae217923d77fd00f581306b1980 (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/lib/corelib/tools')
-rw-r--r--src/lib/corelib/tools/msvcinfo.cpp206
-rw-r--r--src/lib/corelib/tools/msvcinfo.h98
-rw-r--r--src/lib/corelib/tools/tools.pri8
-rw-r--r--src/lib/corelib/tools/vsenvironmentdetector.cpp191
-rw-r--r--src/lib/corelib/tools/vsenvironmentdetector.h67
5 files changed, 568 insertions, 2 deletions
diff --git a/src/lib/corelib/tools/msvcinfo.cpp b/src/lib/corelib/tools/msvcinfo.cpp
new file mode 100644
index 000000000..0ea4e11f2
--- /dev/null
+++ b/src/lib/corelib/tools/msvcinfo.cpp
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "msvcinfo.h"
+
+#include <tools/error.h>
+#include <tools/profile.h>
+#include <tools/version.h>
+#include <tools/vsenvironmentdetector.h>
+
+#include <QByteArray>
+#include <QDir>
+#include <QProcess>
+#include <QScopedPointer>
+#include <QStringList>
+#include <QTemporaryFile>
+
+#ifdef Q_OS_WIN
+#include <qt_windows.h>
+#endif
+
+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(),
+ bool allowFailure = false)
+{
+ 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 && !allowFailure) {
+ 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 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")));
+ if (!dummyFile->open()) {
+ throw ErrorInfo(mkStr("Could not create temporary file (%1)")
+ .arg(dummyFile->errorString()));
+ }
+ 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
+ // 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 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());
+ }
+
+ return map;
+}
+
+QVariantMap MSVC::compilerDefines(const QString &compilerFilePath) const
+{
+ // 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/lib/corelib/tools/msvcinfo.h b/src/lib/corelib/tools/msvcinfo.h
new file mode 100644
index 000000000..8c5c288b6
--- /dev/null
+++ b/src/lib/corelib/tools/msvcinfo.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** 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>
+
+namespace qbs {
+namespace Internal {
+
+class Version;
+
+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 = QString(); // 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"));
+ }
+
+ QBS_EXPORT QVariantMap compilerDefines(const QString &compilerFilePath) const;
+};
+
+class WinSDK : public MSVC
+{
+public:
+ bool isDefault;
+
+ WinSDK()
+ {
+ pathPrefix = QLatin1String("bin");
+ }
+};
+
+} // 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/lib/corelib/tools/vsenvironmentdetector.cpp b/src/lib/corelib/tools/vsenvironmentdetector.cpp
new file mode 100644
index 000000000..1958d2c23
--- /dev/null
+++ b/src/lib/corelib/tools/vsenvironmentdetector.cpp
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** 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
+
+namespace qbs {
+namespace Internal {
+
+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);
+ }
+ }
+}
+
+} // namespace Internal
+} // namespace qbs
diff --git a/src/lib/corelib/tools/vsenvironmentdetector.h b/src/lib/corelib/tools/vsenvironmentdetector.h
new file mode 100644
index 000000000..d9856402d
--- /dev/null
+++ b/src/lib/corelib/tools/vsenvironmentdetector.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** 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 "qbs_export.h"
+
+#include <QStringList>
+
+QT_BEGIN_NAMESPACE
+class QIODevice;
+QT_END_NAMESPACE
+
+namespace qbs {
+namespace Internal {
+
+class MSVC;
+
+class QBS_EXPORT 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;
+};
+
+} // namespace Internal
+} // namespace qbs
+
+#endif // QBS_VSENVIRONMENTDETECTOR_H