****************************************************************************/
#include "utils.h"
+#include "qmlutils.h"
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
unsigned additionalLibraries;
unsigned disabledLibraries;
unsigned updateFileFlags;
+ QString qmlDirectory; // Project's QML files.
QString directory;
QString libraryDirectory;
QString binary;
QStringLiteral("Skip library deployment."));
parser->addOption(noLibraryOption);
+ QCommandLineOption qmlDirOption(QStringLiteral("qmldir"),
+ QStringLiteral("Scan for QML-imports starting from directory."),
+ QStringLiteral("directory"));
+ parser->addOption(qmlDirOption);
+
QCommandLineOption noQuickImportOption(QStringLiteral("no-quick-import"),
QStringLiteral("Skip deployment of Qt Quick imports."));
parser->addOption(noQuickImportOption);
if (parser->isSet(dirOption))
options->directory = parser->value(dirOption);
+ if (parser->isSet(qmlDirOption))
+ options->qmlDirectory = parser->value(qmlDirOption);
+
const QString &file = posArgs.front();
const QFileInfo fi(QDir::cleanPath(file));
if (!fi.exists()) {
if (!findDependentQtLibraries(libraryLocation, options.binary, options.platform, errorMessage, &dependentQtLibs, &wordSize, &isDebug, &directDependencyCount))
return result;
+ // Determine application type, check Quick2 is used by looking at the
+ // direct dependencies (do not be fooled by QtWebKit depending on it).
+ for (int m = 0; m < directDependencyCount; ++m)
+ result.directlyUsedQtLibraries |= qtModule(dependentQtLibs.at(m));
+ const bool usesQml2 = !(options.disabledLibraries & QtQmlModule)
+ && ((result.directlyUsedQtLibraries & QtQmlModule)
+ || (options.additionalLibraries & QtQmlModule));
+
if (optVerboseLevel) {
- std::printf("%s: %ubit, %s executable.\n", qPrintable(QDir::toNativeSeparators(options.binary)),
+ std::printf("%s: %ubit, %s executable", qPrintable(QDir::toNativeSeparators(options.binary)),
wordSize, isDebug ? "debug" : "release");
+ if (usesQml2)
+ std::fputs("[QML]", stdout);
+ std::fputc('\n', stdout);
}
if (dependentQtLibs.isEmpty()) {
} // Qt5Core
} // Windows
+ // Scan Quick2 imports
+ QmlImportScanResult qmlScanResult;
+ if (options.quickImports && usesQml2) {
+ const QString qmlDirectory = options.qmlDirectory.isEmpty() ? findQmlDirectory(options.platform, options.directory) : options.qmlDirectory;
+ if (!qmlDirectory.isEmpty()) {
+ qmlScanResult = runQmlImportScanner(qmlDirectory, qmakeVariables.value(QStringLiteral("QT_INSTALL_QML")), options.platform, isDebug, errorMessage);
+ if (!qmlScanResult.ok)
+ return result;
+ // Additional dependencies of QML plugins.
+ foreach (const QString &plugin, qmlScanResult.plugins) {
+ if (!findDependentQtLibraries(libraryLocation, plugin, options.platform, errorMessage, &dependentQtLibs, &wordSize, &isDebug))
+ return result;
+ }
+ if (optVerboseLevel >= 1) {
+ std::fputs("QML imports:\n", stdout);
+ foreach (const QString &mod, qmlScanResult.modulesDirectories)
+ std::printf(" %s\n", qPrintable(QDir::toNativeSeparators(mod)));
+ if (optVerboseLevel >= 2) {
+ std::fputs("QML plugins:\n", stdout);
+ foreach (const QString &p, qmlScanResult.plugins)
+ std::printf(" %s\n", qPrintable(QDir::toNativeSeparators(p)));
+ }
+ }
+ }
+ }
+
// Find the plugins and check whether ANGLE, D3D are required on the platform plugin.
QString platformPlugin;
// Sort apart Qt 5 libraries in the ones that are represented by the
// QtModule enumeration (and thus controlled by flags) and others.
QStringList deployedQtLibraries;
for (int i = 0 ; i < dependentQtLibs.size(); ++i) {
- if (const unsigned qtm = qtModule(dependentQtLibs.at(i))) {
+ if (const unsigned qtm = qtModule(dependentQtLibs.at(i)))
result.usedQtLibraries |= qtm;
- if (i < directDependencyCount)
- result.directlyUsedQtLibraries |= qtm;
- } else {
+ else
deployedQtLibraries.push_back(dependentQtLibs.at(i)); // Not represented by flag.
- }
}
result.deployedQtLibraries = (result.usedQtLibraries | options.additionalLibraries) & ~options.disabledLibraries;
// Apply options flags and re-add library names.
const bool usesQuick1 = result.deployedQtLibraries & QtDeclarativeModule;
// Do not be fooled by QtWebKit.dll depending on Quick into always installing Quick imports
// for WebKit1-applications. Check direct dependency only.
- const bool usesQuick2 = (result.directlyUsedQtLibraries & QtQuickModule)
- || (options.additionalLibraries & QtQuickModule);
- if (options.quickImports && (usesQuick1 || usesQuick2)) {
+ if (options.quickImports && (usesQuick1 || usesQml2)) {
const QmlDirectoryFileEntryFunction qmlFileEntryFunction(options.platform, isDebug);
- if (usesQuick2) {
- const QString quick2ImportPath = qmakeVariables.value(QStringLiteral("QT_INSTALL_QML"));
- QStringList quick2Imports;
- quick2Imports << QStringLiteral("QtQml") << QStringLiteral("QtQuick") << QStringLiteral("QtQuick.2");
- if (result.deployedQtLibraries & QtMultimediaModule)
- quick2Imports << QStringLiteral("QtMultimedia");
- if (result.deployedQtLibraries & QtSensorsModule)
- quick2Imports << QStringLiteral("QtSensors");
- if (result.deployedQtLibraries & QtWebKitModule)
- quick2Imports << QStringLiteral("QtWebKit");
- foreach (const QString &quick2Import, quick2Imports) {
- const QString sourceFile = quick2ImportPath + slash + quick2Import;
- if (!updateFile(sourceFile, qmlFileEntryFunction, options.directory, options.updateFileFlags, options.json, errorMessage))
+ if (usesQml2) {
+ foreach (const QString &module, qmlScanResult.modulesDirectories) {
+ if (!updateFile(module, qmlFileEntryFunction, options.directory, options.updateFileFlags, options.json, errorMessage))
return result;
}
} // Quick 2
--- /dev/null
+/****************************************************************************
+**
+** 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 "qmlutils.h"
+#include "utils.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QJsonDocument>
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+#include <QtCore/QJsonParseError>
+
+QT_BEGIN_NAMESPACE
+
+static QString qmlDirectoryRecursion(Platform platform, const QString &path)
+{
+ QDir dir(path);
+ if (!dir.entryList(QStringList(QStringLiteral("*.qml")), QDir::Files, QDir::NoSort).isEmpty())
+ return dir.path();
+ foreach (const QString &subDir, dir.entryList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot, QDir::NoSort)) {
+ if (!isBuildDirectory(platform, subDir)) {
+ const QString subPath = qmlDirectoryRecursion(platform, dir.path() + QLatin1Char('/') + subDir);
+ if (!subPath.isEmpty())
+ return subPath;
+ }
+ }
+ return QString();
+}
+
+// Find a directory containing QML files in the project
+QString findQmlDirectory(int platform, const QString &startDirectoryName)
+{
+ QDir startDirectory(startDirectoryName);
+ if (isBuildDirectory(Platform(platform), startDirectory.dirName()))
+ startDirectory.cdUp();
+ return qmlDirectoryRecursion(Platform(platform), startDirectory.path());
+}
+
+static void findFileRecursion(const QDir &directory, Platform platform, bool debug, QStringList *matches)
+{
+ foreach (const QString &dll, findSharedLibraries(directory, platform, debug))
+ matches->append(directory.filePath(dll));
+ foreach (const QString &subDir, directory.entryList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks)) {
+ QDir subDirectory = directory;
+ if (subDirectory.cd(subDir))
+ findFileRecursion(subDirectory, platform, debug, matches);
+ }
+}
+
+QmlImportScanResult runQmlImportScanner(const QString &directory, const QString &qmlImportPath,
+ int platform, bool debug, QString *errorMessage)
+{
+ QmlImportScanResult result;
+ QStringList arguments;
+ arguments << QStringLiteral("-importPath") << qmlImportPath << QStringLiteral("-rootPath") << directory;
+ unsigned long exitCode;
+ QByteArray stdOut;
+ QByteArray stdErr;
+ const QString binary = QStringLiteral("qmlimportscanner");
+ if (!runProcess(binary, arguments, directory, &exitCode, &stdOut, &stdErr, errorMessage))
+ return result;
+ if (exitCode) {
+ *errorMessage = binary + QStringLiteral(" returned ") + QString::number(exitCode)
+ + QStringLiteral(": ") + QString::fromLocal8Bit(stdErr);
+ return result;
+ }
+ QJsonParseError jsonParseError;
+ const QJsonDocument data = QJsonDocument::fromJson(stdOut, &jsonParseError);
+ if (data.isNull() ) {
+ *errorMessage = binary + QStringLiteral(" returned invalid JSON output: ")
+ + jsonParseError.errorString() + QStringLiteral(" :\"")
+ + QString::fromLocal8Bit(stdOut) + QLatin1Char('"');
+ return result;
+ }
+ const QJsonArray array = data.array();
+ const int childCount = array.count();
+ for (int c = 0; c < childCount; ++c) {
+ const QJsonObject object = array.at(c).toObject();
+ if (object.value(QStringLiteral("type")).toString() == QLatin1String("module")) {
+ const QString path = object.value(QStringLiteral("path")).toString();
+ result.modulesDirectories.append(path);
+ findFileRecursion(QDir(path), Platform(platform), debug, &result.plugins);
+ }
+ }
+ result.ok = true;
+ return result;
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** 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 QMLUTILS_H
+#define QMLUTILS_H
+
+#include <QStringList>
+
+QT_BEGIN_NAMESPACE
+
+QString findQmlDirectory(int platform, const QString &startDirectoryName);
+
+struct QmlImportScanResult {
+ QmlImportScanResult() : ok(false) {}
+
+ bool ok;
+ QStringList modulesDirectories;
+ QStringList plugins;
+};
+
+QmlImportScanResult runQmlImportScanner(const QString &directory, const QString &qmlImportPath,
+ int platform, bool debug, QString *errorMessage);
+
+QT_END_NAMESPACE
+
+#endif // QMLUTILS_H
int optVerboseLevel = 1;
+bool isBuildDirectory(Platform platform, const QString &dirName)
+{
+ return (platform & WindowsBased) && (dirName == QLatin1String("debug") || dirName == QLatin1String("release"));
+}
+
// Create a symbolic link by changing to the source directory to make sure the
// link uses relative paths only (QFile::link() otherwise uses the absolute path).
bool createSymbolicLink(const QFileInfo &source, const QString &target, QString *errorMessage)
static const char unixSharedLibrarySuffix[] = ".so";
inline QString sharedLibrarySuffix(Platform platform) { return QLatin1String((platform & WindowsBased) ? windowsSharedLibrarySuffix : unixSharedLibrarySuffix); }
+bool isBuildDirectory(Platform platform, const QString &dirName);
bool createSymbolicLink(const QFileInfo &source, const QString &target, QString *errorMessage);
bool createDirectory(const QString &directory, QString *errorMessage);
QT = core-private
DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII
-SOURCES += main.cpp utils.cpp elfreader.cpp
-HEADERS += utils.h elfreader.h
+SOURCES += main.cpp utils.cpp qmlutils.cpp elfreader.cpp
+HEADERS += utils.h qmlutils.h elfreader.h
CONFIG += force_bootstrap