From 269ee96ab9eadae10eb7482109a17f734c7232c1 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 30 Nov 2016 11:36:51 +0100 Subject: Simplify determination of MSVC compiler defines Do not compile a helper program to output a specific environment variable. Use cmd.exe as compiler backend and pipe commands to it. This accelerates the whole stunt, and removes the need for determining the location of a host compiler. It might be that there is none installed. Change-Id: I1847feadada42ea009aafc730815207edf7e7ff0 Reviewed-by: Christian Kandeler Reviewed-by: Jake Petroules --- src/lib/corelib/tools/msvcinfo.cpp | 86 +++++++++++++------------------------- 1 file changed, 29 insertions(+), 57 deletions(-) diff --git a/src/lib/corelib/tools/msvcinfo.cpp b/src/lib/corelib/tools/msvcinfo.cpp index d464f001e..878b0e616 100644 --- a/src/lib/corelib/tools/msvcinfo.cpp +++ b/src/lib/corelib/tools/msvcinfo.cpp @@ -41,7 +41,6 @@ #include #include -#include #include #include @@ -54,6 +53,8 @@ #include #endif +#include + using namespace qbs; using namespace qbs::Internal; @@ -84,15 +85,20 @@ private: static QByteArray runProcess(const QString &exeFilePath, const QStringList &args, const QProcessEnvironment &env = QProcessEnvironment(), - bool allowFailure = false) + bool allowFailure = false, + const QByteArray &pipeData = QByteArray()) { 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.waitForStarted()) + throw ErrorInfo(mkStr("Could not start %1 (%2)").arg(exeFilePath, process.errorString())); + if (!pipeData.isEmpty()) { + process.write(pipeData); + process.closeWriteChannel(); } + if (!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())); @@ -133,68 +139,30 @@ static QStringList parseCommandLine(const QString &commandLine) return list; } -static QVariantMap getMsvcDefines(const QString &hostCompilerFilePath, - const QString &compilerFilePath, +static QVariantMap getMsvcDefines(const QString &compilerFilePath, const QProcessEnvironment &compilerEnv) { - const QScopedPointer 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 \n"); - dummyFile->write("#include \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"); - const QString qbsClFrontendObj = nativeDummyFilePath + QStringLiteral(".obj"); - DummyFile actualQbsClFrontend(qbsClFrontend); - DummyFile actualQbsClFrontendObj(qbsClFrontendObj); - - // 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; - if (!envdetector.start(&msvc2)) - throw ErrorInfo(QStringLiteral("Detecting the MSVC build environment failed: ") - + envdetector.errorString()); - runProcess(hostCompilerFilePath, QStringList() - << QStringLiteral("/nologo") - << QStringLiteral("/TC") - << (QStringLiteral("/Fo") + qbsClFrontendObj) - << nativeDummyFilePath - << QStringLiteral("/link") - << (QStringLiteral("/out:") + qbsClFrontend), msvc2.environment); - +#ifdef Q_OS_WIN + const QByteArray commands("set MSC_CMD_FLAGS\n"); QStringList out = QString::fromLocal8Bit(runProcess(compilerFilePath, QStringList() << QStringLiteral("/nologo") << QStringLiteral("/B1") - << qbsClFrontend + << QString::fromWCharArray(_wgetenv(L"COMSPEC")) << QStringLiteral("/c") << QStringLiteral("/TC") - << QStringLiteral("NUL"), compilerEnv, true)).split(QStringLiteral("\r\n")); + << QStringLiteral("NUL"), + compilerEnv, true, commands)).split(QLatin1Char('\n')); - if (out.size() != 2) + auto findResult = std::find_if(out.cbegin(), out.cend(), [] (const QString &line) { + return line.startsWith(QLatin1String("MSC_CMD_FLAGS=")); + }); + if (findResult == out.cend()) { 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()); + const QStringList args = parseCommandLine(findResult->trimmed()); for (const QString &arg : args) { if (!arg.startsWith(QStringLiteral("-D"))) continue; @@ -206,6 +174,11 @@ static QVariantMap getMsvcDefines(const QString &hostCompilerFilePath, } return map; +#else + Q_UNUSED(compilerFilePath); + Q_UNUSED(compilerEnv); + return QVariantMap(); +#endif } void MSVC::init() @@ -229,8 +202,7 @@ QString MSVC::clPathForArchitecture(const QString &arch) const QVariantMap MSVC::compilerDefines(const QString &compilerFilePath) const { - return getMsvcDefines(clPathForArchitecture(QStringLiteral("x86")), compilerFilePath, - environment); + return getMsvcDefines(compilerFilePath, environment); } void MSVC::determineCompilerVersion() -- cgit v1.2.3