aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoerg Bornemann <joerg.bornemann@digia.com>2014-03-03 17:02:11 +0100
committerJoerg Bornemann <joerg.bornemann@digia.com>2014-04-08 13:56:26 +0200
commit9c42cb3e891da2fdb915430ecad13120e01eb4ed (patch)
tree68770756a98dc056a30806e8cd557b3c05cf0444
parentd17ca97abe00313447a60252c5d403f821e75f72 (diff)
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>
-rw-r--r--share/qbs/modules/cpp/windows-msvc.qbs41
-rw-r--r--src/app/qbs-setup-toolchains/msvcinfo.h5
-rw-r--r--src/app/qbs-setup-toolchains/msvcprobe.cpp24
-rw-r--r--src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro2
-rw-r--r--src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs2
-rw-r--r--src/app/qbs-setup-toolchains/vsenvironmentdetector.cpp172
-rw-r--r--src/app/qbs-setup-toolchains/vsenvironmentdetector.h58
-rw-r--r--src/lib/corelib/language/loader.cpp17
8 files changed, 275 insertions, 46 deletions
diff --git a/share/qbs/modules/cpp/windows-msvc.qbs b/share/qbs/modules/cpp/windows-msvc.qbs
index ac7f81571..1896eb14c 100644
--- a/share/qbs/modules/cpp/windows-msvc.qbs
+++ b/share/qbs/modules/cpp/windows-msvc.qbs
@@ -20,7 +20,7 @@ CppModule {
property bool generateManifestFiles: true
property path toolchainInstallPath
- property path windowsSDKPath
+ property path windowsSDKPath // ### remove in 1.3
architecture: qbs.architecture
staticLibraryPrefix: ""
dynamicLibraryPrefix: ""
@@ -30,45 +30,6 @@ CppModule {
executableSuffix: ".exe"
property string dynamicLibraryImportSuffix: ".lib"
- setupBuildEnvironment: {
- var vcDir = toolchainInstallPath.replace(/[\\/]bin$/i, "");
- var vcRootDir = vcDir.replace(/[\\/]VC$/i, "");
-
- var v = new ModUtils.EnvironmentVariable("INCLUDE", ";", true)
- v.prepend(vcDir + "/ATLMFC/INCLUDE")
- v.prepend(vcDir + "/INCLUDE")
- v.prepend(windowsSDKPath + "/include")
- v.set()
-
- if (architecture == 'x86') {
- v = new ModUtils.EnvironmentVariable("PATH", ";", true)
- v.prepend(windowsSDKPath + "/bin")
- v.prepend(vcRootDir + "/Common7/IDE")
- v.prepend(vcDir + "/bin")
- v.prepend(vcRootDir + "/Common7/Tools")
- v.set()
-
- v = new ModUtils.EnvironmentVariable("LIB", ";", true)
- v.prepend(vcDir + "/ATLMFC/LIB")
- v.prepend(vcDir + "/LIB")
- v.prepend(windowsSDKPath + "/lib")
- v.set()
- } else if (architecture == 'x86_64') {
- v = new ModUtils.EnvironmentVariable("PATH", ";", true)
- v.prepend(windowsSDKPath + "/bin/x64")
- v.prepend(vcRootDir + "/Common7/IDE")
- v.prepend(vcDir + "/bin/amd64")
- v.prepend(vcRootDir + "/Common7/Tools")
- v.set()
-
- v = new ModUtils.EnvironmentVariable("LIB", ";", true)
- v.prepend(vcDir + "/ATLMFC/LIB/amd64")
- v.prepend(vcDir + "/LIB/amd64")
- v.prepend(windowsSDKPath + "/lib/x64")
- v.set()
- }
- }
-
Transformer {
condition: cPrecompiledHeader !== undefined
inputs: cPrecompiledHeader
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 &parameters)
{
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