diff options
author | Joerg Bornemann <joerg.bornemann@digia.com> | 2014-03-03 17:02:11 +0100 |
---|---|---|
committer | Joerg Bornemann <joerg.bornemann@digia.com> | 2014-04-08 13:56:26 +0200 |
commit | 9c42cb3e891da2fdb915430ecad13120e01eb4ed (patch) | |
tree | 68770756a98dc056a30806e8cd557b3c05cf0444 /src | |
parent | d17ca97abe00313447a60252c5d403f821e75f72 (diff) | |
download | qbs-9c42cb3e891da2fdb915430ecad13120e01eb4ed.tar.gz |
detect Visual Studio build environment using vcvarsall.bat
To provide a consistent build environment for Visual Studio
setup-toolchains now executes the vsvarsall.bat that comes with the
Visual Studio installation. The environment is written to the profile
under the key "buildEnvironment".
The setupBuildEnvironment script in windows-msvc.qbs isn't needed
anymore.
Task-number: QBS-444
Task-number: QBS-508
Change-Id: I3191f5ff127bed6b96ce5ea5520b20fc9646364f
Reviewed-by: Christian Kandeler <christian.kandeler@digia.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/app/qbs-setup-toolchains/msvcinfo.h | 5 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/msvcprobe.cpp | 24 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro | 2 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs | 2 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/vsenvironmentdetector.cpp | 172 | ||||
-rw-r--r-- | src/app/qbs-setup-toolchains/vsenvironmentdetector.h | 58 | ||||
-rw-r--r-- | src/lib/corelib/language/loader.cpp | 17 |
7 files changed, 274 insertions, 6 deletions
diff --git a/src/app/qbs-setup-toolchains/msvcinfo.h b/src/app/qbs-setup-toolchains/msvcinfo.h index 7a32af6eb..f36163590 100644 --- a/src/app/qbs-setup-toolchains/msvcinfo.h +++ b/src/app/qbs-setup-toolchains/msvcinfo.h @@ -30,6 +30,8 @@ #ifndef QBS_MSVCINFO_H #define QBS_MSVCINFO_H +#include <QHash> +#include <QProcessEnvironment> #include <QStringList> class MSVC @@ -38,6 +40,9 @@ public: QString version; QString installPath; QStringList architectures; + + typedef QHash<QString, QProcessEnvironment> EnvironmentPerArch; + EnvironmentPerArch environments; }; class WinSDK : public MSVC diff --git a/src/app/qbs-setup-toolchains/msvcprobe.cpp b/src/app/qbs-setup-toolchains/msvcprobe.cpp index 5a0ba4072..b4e07eb4d 100644 --- a/src/app/qbs-setup-toolchains/msvcprobe.cpp +++ b/src/app/qbs-setup-toolchains/msvcprobe.cpp @@ -31,6 +31,7 @@ #include "msvcinfo.h" #include "probe.h" +#include "vsenvironmentdetector.h" #include "../shared/logging/consolelogger.h" #include <logging/translator.h> @@ -52,9 +53,14 @@ 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) +{ + foreach (const QString &name, env.keys()) + p.setValue(QLatin1String("buildEnvironment.") + name, env.value(name)); +} + static void addMSVCPlatform(const MSVC &msvc, Settings *settings, QList<Profile> &profiles, - QString name, const QString &installPath, const QString &winSDKPath, - const QString &architecture) + QString name, const QString &installPath, const QString &architecture) { name.append(QLatin1Char('_') + architecture); qbsInfo() << Tr::tr("Setting up profile '%1'.").arg(name); @@ -63,7 +69,6 @@ static void addMSVCPlatform(const MSVC &msvc, Settings *settings, QList<Profile> 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("cpp.windowsSDKPath"), winSDKPath); p.setValue(QLatin1String("qbs.architecture"), Internal::HostOsInfo::canonicalArchitecture(architecture)); p.setValue(QLatin1String("qbs.endianness"), @@ -73,6 +78,7 @@ static void addMSVCPlatform(const MSVC &msvc, Settings *settings, QList<Profile> p.setValue(QLatin1String("cpp.platformCFlags"), flags); p.setValue(QLatin1String("cpp.platformCxxFlags"), flags); } + writeEnvironment(p, msvc.environments.value(architecture)); profiles << p; } @@ -179,6 +185,14 @@ 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; } @@ -197,14 +211,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, - sdk.installPath + QLatin1String("\\bin"), defaultWinSDK.installPath, arch); + sdk.installPath + QLatin1String("\\bin"), arch); } } foreach (const MSVC &msvc, msvcs) { foreach (const QString &arch, msvc.architectures) { addMSVCPlatform(msvc, settings, profiles, QLatin1String("MSVC") + msvc.version, - msvc.installPath, defaultWinSDK.installPath, arch); + msvc.installPath, arch); } } } diff --git a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro index c113242a6..9a082763a 100644 --- a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro +++ b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro @@ -8,6 +8,7 @@ HEADERS += \ msvcinfo.h \ msvcprobe.h \ probe.h \ + vsenvironmentdetector.h \ xcodeprobe.h SOURCES += \ @@ -15,6 +16,7 @@ SOURCES += \ 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 130978e2f..f0da9076a 100644 --- a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs +++ b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs @@ -13,6 +13,8 @@ QbsApp { "msvcprobe.h", "probe.cpp", "probe.h", + "vsenvironmentdetector.cpp", + "vsenvironmentdetector.h", "xcodeprobe.cpp", "xcodeprobe.h" ] diff --git a/src/app/qbs-setup-toolchains/vsenvironmentdetector.cpp b/src/app/qbs-setup-toolchains/vsenvironmentdetector.cpp new file mode 100644 index 000000000..68692a7ab --- /dev/null +++ b/src/app/qbs-setup-toolchains/vsenvironmentdetector.cpp @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt 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(const QString &arch) +{ + if (arch == QLatin1String("x86_64")) + return QLatin1String("amd64"); + return arch; +} + +void VsEnvironmentDetector::writeBatchFile(QIODevice *device, const QString &vcvarsallbat) const +{ + const QStringList varnames = QStringList() << "PATH" << "INCLUDE" << "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(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 new file mode 100644 index 000000000..6421385e3 --- /dev/null +++ b/src/app/qbs-setup-toolchains/vsenvironmentdetector.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt 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 diff --git a/src/lib/corelib/language/loader.cpp b/src/lib/corelib/language/loader.cpp index 58ca3a7a6..baf30c474 100644 --- a/src/lib/corelib/language/loader.cpp +++ b/src/lib/corelib/language/loader.cpp @@ -83,11 +83,26 @@ void Loader::setSearchPaths(const QStringList &_searchPaths) m_moduleLoader->setSearchPaths(searchPaths); } +static QProcessEnvironment adjustedEnvironment(const QProcessEnvironment &environment, + const QVariantMap &environmentFromProfile) +{ + QProcessEnvironment result = environment; + for (QVariantMap::const_iterator it = environmentFromProfile.begin(); + it != environmentFromProfile.end(); ++it) { + result.insert(it.key(), it.value().toString()); + } + return result; +} + TopLevelProjectPtr Loader::loadProject(const SetupProjectParameters ¶meters) { QBS_CHECK(QFileInfo(parameters.projectFilePath()).isAbsolute()); - m_engine->setEnvironment(parameters.environment()); + m_engine->setEnvironment( + adjustedEnvironment( + parameters.environment(), + parameters.buildConfigurationTree().value(QLatin1String("buildEnvironment")) + .toMap())); m_engine->clearExceptions(); // At this point, we cannot set a sensible total effort, because we know nothing about |