From ab3e8e80fbd81a38039c713189b0422972e0963e Mon Sep 17 00:00:00 2001 From: Friedemann Kleint <Friedemann.Kleint@digia.com> Date: Tue, 3 Dec 2013 18:23:31 +0200 Subject: [PATCH] Completely bootstrap idc. idc dynamically loads libraries depending on QtCore.dll whose static instances can then cause clashes. Task-number: QTBUG-35275 Change-Id: Icd219a2bb36b0a5c3927c3163e93dc07bb5317aa Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com> --- src/tools/idc/idc.pro | 4 +- src/tools/idc/main.cpp | 99 ++++++++++++++++++++++++++++++++---------- 2 files changed, 76 insertions(+), 27 deletions(-) diff --git a/src/tools/idc/idc.pro b/src/tools/idc/idc.pro index b9d8dee4..1898ed53 100644 --- a/src/tools/idc/idc.pro +++ b/src/tools/idc/idc.pro @@ -1,7 +1,5 @@ option(host_build) - -QT = core - +CONFIG += force_bootstrap SOURCES = main.cpp load(qt_tool) diff --git a/src/tools/idc/main.cpp b/src/tools/idc/main.cpp index a28d56c4..987d829b 100644 --- a/src/tools/idc/main.cpp +++ b/src/tools/idc/main.cpp @@ -41,8 +41,8 @@ #include <QDir> #include <QFile> -#include <QProcess> -#include <QLibraryInfo> +#include <QDir> +#include <QScopedArrayPointer> #include <qt_windows.h> #include <io.h> @@ -70,33 +70,84 @@ static bool hasDllExtension(const QString &filePath) return hasFileExtension(filePath, QStringLiteral(".dll")); } +// Prepend the Qt binary directory to PATH. +static bool prependPath() +{ + enum { maxEnvironmentSize = 32767 }; + wchar_t buffer[maxEnvironmentSize]; + if (!GetModuleFileName(NULL, buffer, maxEnvironmentSize)) + return false; + wchar_t *ptr = wcsrchr(buffer, L'\\'); + if (!ptr) + return false; + *ptr++ = L';'; + const wchar_t pathVariable[] = L"PATH"; + if (!GetEnvironmentVariable(pathVariable, ptr, maxEnvironmentSize - (ptr - buffer)) + || !SetEnvironmentVariable(pathVariable, buffer)) { + return false; + } + return true; +} + +static QString errorString(DWORD errorCode) +{ + wchar_t *resultW = 0; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, + NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR)&resultW, 0, NULL); + const QString result = QString::fromWCharArray(resultW); + LocalFree((HLOCAL)resultW); + return result; +} + static bool runWithQtInEnvironment(const QString &cmd) { - QProcess proc; + enum { timeOutMs = 30000 }; + static const bool pathSet = prependPath(); + if (!pathSet) + return false; - // prepend the qt binary directory to the path - QStringList env = QProcess::systemEnvironment(); - for (int i=0; i<env.count(); ++i) { - QString var = env.at(i); - int setidx = var.indexOf(QLatin1Char('=')); - if (setidx != -1) { - QString varname = var.left(setidx).trimmed().toUpper(); - if (varname == QLatin1String("PATH")) { - var = var.mid(setidx + 1); - var = QLatin1String("PATH=") + - QLibraryInfo::location(QLibraryInfo::BinariesPath) + - QLatin1Char(';') + var; - env[i] = var; - break; - } - } - } + STARTUPINFO si; + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); - proc.setEnvironment(env); - proc.start(cmd); - proc.waitForFinished(-1); + STARTUPINFO myInfo; + GetStartupInfo(&myInfo); + si.hStdInput = myInfo.hStdInput; + si.hStdOutput = myInfo.hStdOutput; + si.hStdError = myInfo.hStdError; - return (proc.exitCode() == 0); + PROCESS_INFORMATION pi; + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + + QScopedArrayPointer<wchar_t> commandLineW(new wchar_t[cmd.size() + 1]); + cmd.toWCharArray(commandLineW.data()); + commandLineW[cmd.size()] = 0; + if (!CreateProcessW(0, commandLineW.data(), 0, 0, /* InheritHandles */ TRUE, 0, 0, 0, &si, &pi)) { + fprintf(stderr, "Unable to execute \"%s\": %s\n", qPrintable(cmd), + qPrintable(errorString(GetLastError()))); + return false; + } + + DWORD exitCode = 1; + switch (WaitForSingleObject(pi.hProcess, timeOutMs)) { + case WAIT_OBJECT_0: + GetExitCodeProcess(pi.hProcess, &exitCode); + break; + case WAIT_TIMEOUT: + fprintf(stderr, "Timed out after %d ms out waiting for \"%s\".\n", + int(timeOutMs), qPrintable(cmd)); + TerminateProcess(pi.hProcess, 1); + break; + default: + fprintf(stderr, "Error waiting for \"%s\": %s\n", + qPrintable(cmd), qPrintable(errorString(GetLastError()))); + TerminateProcess(pi.hProcess, 1); + break; + } + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + return exitCode == 0; } static bool attachTypeLibrary(const QString &applicationName, int resource, const QByteArray &data, QString *errorMessage) -- GitLab