diff options
author | Friedemann Kleint <Friedemann.Kleint@digia.com> | 2013-04-08 15:30:14 +0200 |
---|---|---|
committer | Maurice Kalinowski <maurice.kalinowski@digia.com> | 2013-04-12 13:56:38 +0200 |
commit | efce618caabbc93b0f9d1297f04c3e8beeb9d7c0 (patch) | |
tree | 5f8ed4545ddc82132ff9a2252df494d1bc31db4d | |
parent | eec0eaed067dc1b421e12530c70b3a4ee01affee (diff) | |
download | qttools-efce618caabbc93b0f9d1297f04c3e8beeb9d7c0.tar.gz |
Say hello to winrtdeployqt.
Add tool winrtdepploy to copy/update Qt libraries and plugins.
Change-Id: Ida204de92df0bc06464259df679cd70db4ffcea5
Reviewed-by: Maurice Kalinowski <maurice.kalinowski@digia.com>
-rw-r--r-- | src/src.pro | 2 | ||||
-rw-r--r-- | src/winrtdeployqt/main.cpp | 190 | ||||
-rw-r--r-- | src/winrtdeployqt/utils.cpp | 324 | ||||
-rw-r--r-- | src/winrtdeployqt/utils.h | 62 | ||||
-rw-r--r-- | src/winrtdeployqt/winrtdeployqt.pro | 12 |
5 files changed, 590 insertions, 0 deletions
diff --git a/src/src.pro b/src/src.pro index 37995679f..ca72cfa95 100644 --- a/src/src.pro +++ b/src/src.pro @@ -15,6 +15,8 @@ qtHaveModule(widgets) { SUBDIRS += linguist +win32:SUBDIRS += winrtdeployqt + mac { SUBDIRS += macdeployqt } diff --git a/src/winrtdeployqt/main.cpp b/src/winrtdeployqt/main.cpp new file mode 100644 index 000000000..9e8865bfc --- /dev/null +++ b/src/winrtdeployqt/main.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "utils.h" + +#include <QtCore/QDir> +#include <QtCore/QFileInfo> +#include <QtCore/QCoreApplication> + +#include <cstdio> + +bool optPlugins = true; +bool optLibraries = true; +bool optHelp = false; + +QString optDirectory; + +static const char usageC[] = +"Usage: winrtdeployqt build-directory [options]\n\n" +"Copies/updates the dependent Qt libraries and plugins required for\n" +"a WinRT application to the build-directory.\n\n" +"Options: -no-plugins : Skip plugin deployment\n" +" -no-libraries : Skip library deployment\n" +" -h : Display help\n" +" -verbose=<0-3> : 0 = no output, 1 = progress (default),\n" +" 2 = normal, 3 = debug\n"; + +static inline bool parseArguments(const QStringList &arguments) +{ + for (int i = 1; i < arguments.size(); ++i) { + const QString argument = arguments.at(i); + if (argument == QLatin1String("-no-plugins")) { + optPlugins = false; + } else if (argument == QLatin1String("-no-libraries")) { + optLibraries = false; + } else if (argument.startsWith(QLatin1String("-h"))) { + optHelp = true; + } else if (argument.startsWith(QLatin1String("-verbose"))) { + const int index = argument.indexOf(QLatin1Char('=')); + bool ok = false; + optVerboseLevel = argument.mid(index + 1).toInt(&ok); + if (!ok) { + std::fprintf(stderr, "Could not parse verbose level.\n"); + return false; + } + } else { + if (!optDirectory.isEmpty()) + return false; + optDirectory = QDir::cleanPath(argument); + if (optDirectory.endsWith(QLatin1Char('/'))) + optDirectory.chop(1); + } + } + return !optDirectory.isEmpty(); +} + +// Return binary from folder +static inline QString findBinary(const QString &directory) +{ + QDir dir(QDir::cleanPath(directory)); + const QStringList exes = dir.entryList(QStringList(QLatin1String("*.exe"))); + return exes.isEmpty() ? QString() : dir.filePath(exes.front()); +} + +int main(int argc, char **argv) +{ + QCoreApplication a(argc, argv); + + const QChar slash = QLatin1Char('/'); + + if (!parseArguments(QCoreApplication::arguments()) || optHelp) { + std::printf("\nwinrtdeployqt based on Qt %s\n\n%s", QT_VERSION_STR, usageC); + return optHelp ? 0 : 1; + } + + const QString binary = findBinary(optDirectory); + if (binary.isEmpty()) { + std::fprintf(stderr, "Unable to find binary in %s.\n", qPrintable(optDirectory)); + return 1; + } + QString errorMessage; + const QString qtBinDir = queryQMake(QStringLiteral("QT_INSTALL_BINS"), &errorMessage); + + if (qtBinDir.isEmpty()) { + std::fprintf(stderr, "Unable to find Qt bin directory: %s\n", qPrintable(errorMessage)); + return 1; + } + + if (optVerboseLevel > 1) + std::fprintf(stderr, "Qt binaries in %s\n", qPrintable(QDir::toNativeSeparators(qtBinDir))); + + const QStringList dependentLibs = findDependentLibs(binary, &errorMessage); + if (dependentLibs.isEmpty()) { + std::fprintf(stderr, "Unable to find dependent libraries of %s: %s\n", + qPrintable(binary), qPrintable(errorMessage)); + return 1; + } + + // Filter out the Qt libraries. Note that depends.exe finds libs from optDirectory if we + // are run the 2nd time (updating). We want to check against the Qt bin dir libraries + QStringList dependentQtLibs; + const QRegExp filterRegExp(QRegExp(QStringLiteral("Qt5"), Qt::CaseInsensitive, QRegExp::FixedString)); + foreach (const QString &qtLib, dependentLibs.filter(filterRegExp)) + dependentQtLibs.push_back(normalizeFileName(qtBinDir + slash + QFileInfo(qtLib).fileName())); + + if (optVerboseLevel > 1) + std::fprintf(stderr, "Qt libraries required: %s\n", qPrintable(dependentQtLibs.join(QLatin1Char(',')))); + + if (dependentQtLibs.isEmpty()) { + std::fprintf(stderr, "%s does not seem to be a Qt executable\n", + qPrintable(QDir::toNativeSeparators(binary))); + return 1; + } + const bool isDebug = + !dependentQtLibs.filter(QRegExp(QStringLiteral("Qt5Cored.dll"), + Qt::CaseInsensitive, QRegExp::FixedString)).isEmpty(); + if (optLibraries) { + foreach (const QString &qtLib, dependentQtLibs) { + if (!updateFile(qtLib, optDirectory, &errorMessage)) { + std::fprintf(stderr, "%s\n", qPrintable(errorMessage)); + return 1; + } + } + } // optLibraries + + if (optPlugins) { + const QStringList plugins = findQtPlugins(isDebug, &errorMessage); + if (optVerboseLevel > 1) + std::fprintf(stderr, "Plugins: %s\n", qPrintable(plugins.join(QLatin1Char(',')))); + + if (plugins.isEmpty()) { + std::fprintf(stderr, "%s\n", qPrintable(errorMessage)); + return 1; + } + QDir dir(optDirectory); + foreach (const QString &plugin, plugins) { + const QString targetDirName = plugin.section(slash, -2, -2); + if (!dir.exists(targetDirName)) { + std::printf("Creating directory %s.\n", qPrintable(targetDirName)); + if (!dir.mkdir(targetDirName)) { + std::fprintf(stderr, "Cannot create %s.\n", qPrintable(targetDirName)); + return -1; + } + } + if (!updateFile(plugin, optDirectory + slash + targetDirName, &errorMessage)) { + std::fprintf(stderr, "%s\n", qPrintable(errorMessage)); + return 1; + } + } + } // optPlugins + return 0; +} diff --git a/src/winrtdeployqt/utils.cpp b/src/winrtdeployqt/utils.cpp new file mode 100644 index 000000000..0c5ed0e5d --- /dev/null +++ b/src/winrtdeployqt/utils.cpp @@ -0,0 +1,324 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "utils.h" + +#include <QtCore/QString> +#include <QtCore/QFileInfo> +#include <QtCore/qt_windows.h> +#include <QtCore/QTemporaryFile> +#include <QtCore/QFile> +#include <QtCore/QDir> +#include <QtCore/QScopedPointer> +#include <QtCore/QDateTime> +#include <QtCore/QStandardPaths> + +#include <cstdio> + +int optVerboseLevel = 1; + +QString winErrorMessage(unsigned long error) +{ + QString rc = QString::fromLatin1("#%1: ").arg(error); + ushort *lpMsgBuf; + + const int len = FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL); + if (len) { + rc = QString::fromUtf16(lpMsgBuf, len); + LocalFree(lpMsgBuf); + } else { + rc += QString::fromLatin1("<unknown error>"); + } + return rc; +} + +// Case-Normalize file name via GetShortPathNameW()/GetLongPathNameW() +QString normalizeFileName(const QString &name) +{ + wchar_t shortBuffer[MAX_PATH]; + const QString nativeFileName = QDir::toNativeSeparators(name); + if (!GetShortPathNameW((wchar_t *)nativeFileName.utf16(), shortBuffer, MAX_PATH)) + return name; + wchar_t result[MAX_PATH]; + if (!GetLongPathNameW(shortBuffer, result, MAX_PATH)) + return name; + return QDir::fromNativeSeparators(QString::fromWCharArray(result)); +} + +// Find a tool binary in the Windows SDK 8 +QString findSdkTool(const QString &tool) +{ + QStringList paths = QString::fromLocal8Bit(qgetenv("PATH")).split(QLatin1Char(';')); + const QByteArray sdkDir = qgetenv("WindowsSdkDir"); + if (!sdkDir.isEmpty()) + paths.prepend(QDir::cleanPath(QString::fromLocal8Bit(sdkDir)) + QLatin1String("/Tools/x64")); + return QStandardPaths::findExecutable(tool, paths); +} + +// runProcess helper: Create a temporary file for stdout/stderr redirection. +static HANDLE createInheritableTemporaryFile() +{ + wchar_t path[MAX_PATH]; + if (!GetTempPath(MAX_PATH, path)) + return INVALID_HANDLE_VALUE; + wchar_t name[MAX_PATH]; + if (!GetTempFileName(path, L"temp", 0, name)) // Creates file. + return INVALID_HANDLE_VALUE; + SECURITY_ATTRIBUTES securityAttributes; + ZeroMemory(&securityAttributes, sizeof(securityAttributes)); + securityAttributes.nLength = sizeof(securityAttributes); + securityAttributes.bInheritHandle = TRUE; + return CreateFile(name, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes, + TRUNCATE_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL); +} + +// runProcess helper: Rewind and read out a temporary file for stdout/stderr. +static inline void readTemporaryProcessFile(HANDLE handle, QByteArray *result) +{ + if (SetFilePointer(handle, 0, 0, FILE_BEGIN) == 0xFFFFFFFF) + return; + char buf[1024]; + DWORD bytesRead; + while (ReadFile(handle, buf, sizeof(buf), &bytesRead, NULL) && bytesRead) + result->append(buf, bytesRead); + CloseHandle(handle); +} + +// runProcess: Run a command line process (replacement for QProcess which +// does not exist in the bootstrap library). +bool runProcess(const QString &commandLine, const QString &workingDirectory, + unsigned long *exitCode, QByteArray *stdOut, QByteArray *stdErr, + QString *errorMessage) +{ + if (exitCode) + *exitCode = 0; + + if (optVerboseLevel > 1) + std::fprintf(stderr, "Running: %s\n", qPrintable(commandLine)); + + STARTUPINFO si; + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags |= STARTF_USESTDHANDLES; + si.hStdError = si.hStdOutput = si.hStdInput = INVALID_HANDLE_VALUE; + PROCESS_INFORMATION pi; + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + const QChar backSlash = QLatin1Char('\\'); + QString nativeWorkingDir = QDir::toNativeSeparators(workingDirectory.isEmpty() ? QDir::currentPath() : workingDirectory); + if (!nativeWorkingDir.endsWith(backSlash)) + nativeWorkingDir += backSlash; + + if (stdOut) { + si.hStdOutput = createInheritableTemporaryFile(); + if (si.hStdOutput == INVALID_HANDLE_VALUE) { + if (errorMessage) + *errorMessage = QStringLiteral("Error creating stdout temporary file"); + return false; + } + si.dwFlags |= STARTF_USESTDHANDLES; + } + + if (stdErr) { + si.hStdError = createInheritableTemporaryFile(); + if (si.hStdError == INVALID_HANDLE_VALUE) { + if (errorMessage) + *errorMessage = QStringLiteral("Error creating stderr temporary file"); + return false; + } + si.dwFlags |= STARTF_USESTDHANDLES; + } + + if (!CreateProcessW(0, (WCHAR*)commandLine.utf16(), 0, 0, /* InheritHandles */ TRUE, 0, 0, 0, &si, &pi)) { + if (si.hStdOutput != INVALID_HANDLE_VALUE) + CloseHandle(si.hStdOutput); + if (si.hStdError != INVALID_HANDLE_VALUE) + CloseHandle(si.hStdError); + if (errorMessage) + *errorMessage = QStringLiteral("CreateProcessW failed: ") + winErrorMessage(GetLastError()); + return false; + } + + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hThread); + if (exitCode) + GetExitCodeProcess(pi.hProcess, exitCode); + CloseHandle(pi.hProcess); + + if (stdOut) + readTemporaryProcessFile(si.hStdOutput, stdOut); + if (stdErr) + readTemporaryProcessFile(si.hStdError, stdErr); + return true; +} + +QString queryQMake(const QString &variable, QString *errorMessage) +{ + QByteArray stdOut; + QByteArray stdErr; + unsigned long exitCode; + const QString commandLine = QStringLiteral("qmake.exe -query ") + variable; + if (!runProcess(commandLine, QString(), &exitCode, &stdOut, &stdErr, errorMessage)) + return QString(); + if (exitCode) { + *errorMessage = commandLine + QStringLiteral(" returns ") + QString::number(exitCode) + + QStringLiteral(": ") + QString::fromLocal8Bit(stdErr); + return QString(); + } + return QString::fromLocal8Bit(stdOut).trimmed(); +} + +// run "depends.exe" in command line mode to find dependent libs. +// Note that this returns non-normalized (all CAPS) file names. +QStringList findDependentLibs(const QString &binary, QString *errorMessage) +{ + const QString depends = QStringLiteral("depends.exe"); + const QString dependsPath = findSdkTool(depends); + if (dependsPath.isEmpty()) { + *errorMessage = QString::fromLatin1("Cannot find %1.").arg(depends); + return QStringList(); + } + QString tempPattern = QDir::tempPath(); + if (!tempPattern.endsWith(QLatin1Char('/'))) + tempPattern += QLatin1Char('/'); + tempPattern += QLatin1String("dependsXXXXXX.csv"); + QScopedPointer<QTemporaryFile> temporaryFile(new QTemporaryFile(tempPattern)); + if (!temporaryFile->open()) { + *errorMessage = QString::fromLatin1("Cannot open temporary file."); + return QStringList(); + } + const QString fileName = temporaryFile->fileName(); + temporaryFile->close(); + temporaryFile.reset(); + + const QString commandLine = QLatin1Char('"') + QDir::toNativeSeparators(dependsPath) + + QStringLiteral("\" /c /f:1 \"/oc:") + QDir::toNativeSeparators(fileName) + + QStringLiteral("\" \"") + QDir::toNativeSeparators(binary) + QLatin1Char('"'); + + if (!runProcess(commandLine, QString(), 0, 0, 0, errorMessage)) + return QStringList(); + // Ignore return codes by missing dependencies (iexplorer,etc). + QFile resultFile(fileName); + if (!resultFile.open(QIODevice::Text | QIODevice::ReadOnly)) { + *errorMessage = QString::fromLatin1("Cannot open %1: %2") + .arg(QDir::toNativeSeparators(fileName), resultFile.errorString()); + return QStringList(); + } + // Read CSV lines: 0,"c:\x.dll",...' + QStringList result; + resultFile.readLine(); // Skip header + for (int l = 0; ; ++l) { + const QByteArray line = resultFile.readLine(); + if (line.isEmpty() ) + break; + if (l > 1) { // Skip header and exe + int start = line.indexOf(','); + if (start < 0) + continue; + ++start; + if (line.at(start) == '"') + ++start; + int end = line.indexOf(',', start + 1); + if (end < 0) + continue; + if (line.at(end - 1) == '"') + --end; + result.push_back(QDir::cleanPath(QString::fromLocal8Bit(line.mid(start, end - start)))); + } + } + return result; +} + +QStringList findQtPlugins(bool debug, QString *errorMessage) +{ + const QString qtPluginsDirName = queryQMake(QStringLiteral("QT_INSTALL_PLUGINS"), errorMessage); + if (qtPluginsDirName.isEmpty()) + return QStringList(); + QDir pluginsDir(qtPluginsDirName); + QStringList result; + const QString filter = QLatin1Char('*') + QLatin1String(debug ? "d" : "[^d]") + QStringLiteral(".dll"); + foreach (const QString &subDirName, pluginsDir.entryList(QStringList(QLatin1String("*")), QDir::Dirs | QDir::NoDotAndDotDot)) { + if (subDirName != QLatin1String("designer")) { + const QString subDirPath = qtPluginsDirName + QLatin1Char('/') + subDirName; + QDir subDir(subDirPath); + // Use only the 'winrt' plugin from "platforms". + const QString effectiveFilter = subDirName == QLatin1String("platforms") ? + (QStringLiteral("qwinrt") + filter) : filter; + foreach (const QString &dll, subDir.entryList(QStringList(effectiveFilter), QDir::Files)) + result.push_back(subDirPath + QLatin1Char('/') + dll); + } + } + return result; +} + +// Update a file +bool updateFile(const QString &sourceFileName, const QString &targetDirectory, QString *errorMessage) +{ + const QFileInfo sourceFileInfo(sourceFileName); + const QString targetFileName = targetDirectory + QLatin1Char('/') + sourceFileInfo.fileName(); + if (optVerboseLevel > 1) + std::fprintf(stderr, "Checking %s, %s\n", qPrintable(sourceFileName), qPrintable(targetFileName)); + if (!sourceFileInfo.exists()) { + *errorMessage = QString::fromLatin1("%1 does not exist.").arg(QDir::toNativeSeparators(sourceFileName)); + return false; + } + const QFileInfo targetFileInfo(targetFileName); + if (targetFileInfo.exists() && targetFileInfo.lastModified() >= sourceFileInfo.lastModified()) { + if (optVerboseLevel) + std::printf("%s is up to date.\n", qPrintable(sourceFileInfo.fileName())); + return true; + } + QFile file(sourceFileName); + if (optVerboseLevel) + std::printf("Updating %s.\n", qPrintable(sourceFileInfo.fileName())); + if (!file.copy(targetFileName)) { + *errorMessage = QString::fromLatin1("Cannot copy %1 to %2: %3") + .arg(QDir::toNativeSeparators(sourceFileName), + QDir::toNativeSeparators(targetFileName), + file.errorString()); + return false; + } + return true; +} + +QT_END_NAMESPACE diff --git a/src/winrtdeployqt/utils.h b/src/winrtdeployqt/utils.h new file mode 100644 index 000000000..b3d4d515f --- /dev/null +++ b/src/winrtdeployqt/utils.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef UTILS_H +#define UTILS_H + +#include <QString> + +QT_FORWARD_DECLARE_CLASS(QStringList) + +QString normalizeFileName(const QString &name); +QString findSdkTool(const QString &tool); +QString queryQMake(const QString &variable, QString *errorMessage); +QStringList findDependentLibs(const QString &binary, QString *errorMessage); +QStringList findQtPlugins(bool debug, QString *errorMessage); +bool updateFile(const QString &sourceFileName, const QString &targetDirectory, QString *errorMessage); +bool runProcess(const QString &commandLine, const QString &workingDirectory = QString(), + unsigned long *exitCode = 0, QByteArray *stdOut = 0, QByteArray *stdErr = 0, + QString *errorMessage = 0); +QString winErrorMessage(unsigned long error); + +extern int optVerboseLevel; + +#endif // UTILS_H diff --git a/src/winrtdeployqt/winrtdeployqt.pro b/src/winrtdeployqt/winrtdeployqt.pro new file mode 100644 index 000000000..edf87f491 --- /dev/null +++ b/src/winrtdeployqt/winrtdeployqt.pro @@ -0,0 +1,12 @@ +option(host_build) +QT = core-private +DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII + +SOURCES += main.cpp utils.cpp +HEADERS += utils.h + +CONFIG += force_bootstrap console + +INCLUDEPATH += $$QT_BUILD_TREE/src/corelib/global + +load(qt_tool) |