diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2019-09-18 08:45:43 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2019-09-19 11:32:23 +0200 |
commit | d5f3e7a7e319c6bd8fa8b79d8da7a6fd62b50f01 (patch) | |
tree | 00cee94731290b1ade5ee869c0e4adf022f51b59 /tools/qmlcachegen | |
parent | 567fc7b40efb451f12eddd9615bae892dcba707f (diff) |
Fix regression when using CONFIG+=QtQuickCompiler and .qrc files in subdirs
Commit 41864db3b61d9e81a9fe4906918d2cd3d6d32a0c removed the processing
of .qrc files that removed .qml/etc. files. Since the chaining of
resources remains critical to ensure that the cached compilation units
are loaded, the build system copied the input .qrc file to a new one.
That mere copying caused the build to break when the copied .qrc file
was not in the same directory as the original one, as file paths within
the .qrc file are interpreted as relative to the .qrc file, which was
now in a different location. To fix this, this patch brings back the
"filtering" code that rewrites the paths to the source files in the .qrc
file.
Fixes: QTBUG-78253
Change-Id: Ie1d56f3248e713a964260bc2da37c9374f7b6a36
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'tools/qmlcachegen')
-rw-r--r-- | tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in | 2 | ||||
-rw-r--r-- | tools/qmlcachegen/qmlcachegen.cpp | 7 | ||||
-rw-r--r-- | tools/qmlcachegen/qmlcachegen.pro | 1 | ||||
-rw-r--r-- | tools/qmlcachegen/qtquickcompiler.prf | 2 | ||||
-rw-r--r-- | tools/qmlcachegen/resourcefilter.cpp | 172 |
5 files changed, 182 insertions, 2 deletions
diff --git a/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in b/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in index baa437a947..be2113b258 100644 --- a/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in +++ b/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in @@ -50,7 +50,7 @@ but not all the files it references. get_filename_component(input_resource ${_resource} ABSOLUTE) - configure_file(${input_resource} ${new_resource_file} COPYONLY) + execute_process(COMMAND ${compiler_path} --filter-resource-file ${input_resource} -o ${new_resource_file} OUTPUT_VARIABLE remaining_files) list(APPEND filtered_rcc_files ${new_resource_file}) list(APPEND loader_flags \"--resource-file-mapping=${_resource}=${new_resource_file}\") diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp index 41171b3f07..920f451b84 100644 --- a/tools/qmlcachegen/qmlcachegen.cpp +++ b/tools/qmlcachegen/qmlcachegen.cpp @@ -47,6 +47,7 @@ using namespace QQmlJS; +int filterResourceFile(const QString &input, const QString &output); bool generateLoader(const QStringList &compiledFiles, const QString &output, const QStringList &resourceFileMappings, QString *errorString); QString symbolNamespaceForPath(const QString &relativePath); @@ -417,6 +418,8 @@ int main(int argc, char **argv) parser.addHelpOption(); parser.addVersionOption(); + QCommandLineOption filterResourceFileOption(QStringLiteral("filter-resource-file"), QCoreApplication::translate("main", "Filter out QML/JS files from a resource file that can be cached ahead of time instead")); + parser.addOption(filterResourceFileOption); QCommandLineOption resourceFileMappingOption(QStringLiteral("resource-file-mapping"), QCoreApplication::translate("main", "Path from original resource file to new one"), QCoreApplication::translate("main", "old-name:new-name")); parser.addOption(resourceFileMappingOption); QCommandLineOption resourceOption(QStringLiteral("resource"), QCoreApplication::translate("main", "Qt resource file that might later contain one of the compiled files"), QCoreApplication::translate("main", "resource-file-name")); @@ -462,6 +465,10 @@ int main(int argc, char **argv) if (outputFileName.isEmpty()) outputFileName = inputFile + QLatin1Char('c'); + if (parser.isSet(filterResourceFileOption)) { + return filterResourceFile(inputFile, outputFileName); + } + if (target == GenerateLoader) { ResourceFileMapper mapper(sources); diff --git a/tools/qmlcachegen/qmlcachegen.pro b/tools/qmlcachegen/qmlcachegen.pro index 910cb657d7..bee0b9a37e 100644 --- a/tools/qmlcachegen/qmlcachegen.pro +++ b/tools/qmlcachegen/qmlcachegen.pro @@ -4,6 +4,7 @@ QT = qmldevtools-private DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII SOURCES = qmlcachegen.cpp \ + resourcefilter.cpp \ generateloader.cpp \ resourcefilemapper.cpp TARGET = qmlcachegen diff --git a/tools/qmlcachegen/qtquickcompiler.prf b/tools/qmlcachegen/qtquickcompiler.prf index 0129122157..cb3b028e8d 100644 --- a/tools/qmlcachegen/qtquickcompiler.prf +++ b/tools/qmlcachegen/qtquickcompiler.prf @@ -28,7 +28,7 @@ for(res, RESOURCES) { contains(rccContents,.*\\.js$)|contains(rccContents,.*\\.qml$)|contains(rccContents,.*\\.mjs$) { new_resource = $$qmlCacheResourceFileOutputName($$res) mkpath($$dirname(new_resource)) - system($$QMAKE_QMAKE -install qinstall $$system_quote($$absRes) $$system_quote($$new_resource)) + dummy = $$system($$QML_CACHEGEN_FILTER --filter-resource-file -o $$system_quote($$new_resource) $$system_quote($$absRes)) NEWRESOURCES += $$new_resource QMLCACHE_LOADER_FLAGS += --resource-file-mapping=$$shell_quote($$absRes=$$new_resource) diff --git a/tools/qmlcachegen/resourcefilter.cpp b/tools/qmlcachegen/resourcefilter.cpp new file mode 100644 index 0000000000..261102dcbe --- /dev/null +++ b/tools/qmlcachegen/resourcefilter.cpp @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QString> +#include <QXmlStreamReader> +#include <QFile> +#include <QDir> + +int filterResourceFile(const QString &input, const QString &output) +{ + enum State { + InitialState, + InRCC, + InResource, + InFile + }; + State state = InitialState; + + QString prefix; + QString currentFileName; + QXmlStreamAttributes fileAttributes; + + QFile file(input); + if (!file.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Cannot open %s for reading.\n", qPrintable(input)); + return EXIT_FAILURE; + } + + QDir inputDirectory = QFileInfo(file).absoluteDir(); + QDir outputDirectory = QFileInfo(output).absoluteDir(); + + QString outputString; + QXmlStreamWriter writer(&outputString); + writer.setAutoFormatting(true); + + QXmlStreamReader reader(&file); + while (!reader.atEnd()) { + switch (reader.readNext()) { + case QXmlStreamReader::StartDocument: { + QStringRef version = reader.documentVersion(); + if (!version.isEmpty()) + writer.writeStartDocument(version.toString()); + else + writer.writeStartDocument(); + break; + } + case QXmlStreamReader::EndDocument: + writer.writeEndDocument(); + break; + case QXmlStreamReader::StartElement: + if (reader.name() == QStringLiteral("RCC")) { + if (state != InitialState) { + fprintf(stderr, "Unexpected RCC tag in line %d\n", int(reader.lineNumber())); + return EXIT_FAILURE; + } + state = InRCC; + } else if (reader.name() == QStringLiteral("qresource")) { + if (state != InRCC) { + fprintf(stderr, "Unexpected qresource tag in line %d\n", int(reader.lineNumber())); + return EXIT_FAILURE; + } + state = InResource; + QXmlStreamAttributes attributes = reader.attributes(); + if (attributes.hasAttribute(QStringLiteral("prefix"))) + prefix = attributes.value(QStringLiteral("prefix")).toString(); + if (!prefix.startsWith(QLatin1Char('/'))) + prefix.prepend(QLatin1Char('/')); + if (!prefix.endsWith(QLatin1Char('/'))) + prefix.append(QLatin1Char('/')); + } else if (reader.name() == QStringLiteral("file")) { + if (state != InResource) { + fprintf(stderr, "Unexpected file tag in line %d\n", int(reader.lineNumber())); + return EXIT_FAILURE; + } + state = InFile; + fileAttributes = reader.attributes(); + continue; + } + writer.writeStartElement(reader.name().toString()); + writer.writeAttributes(reader.attributes()); + continue; + + case QXmlStreamReader::EndElement: + if (reader.name() == QStringLiteral("file")) { + if (state != InFile) { + fprintf(stderr, "Unexpected end of file tag in line %d\n", int(reader.lineNumber())); + return EXIT_FAILURE; + } + state = InResource; + continue; + } else if (reader.name() == QStringLiteral("qresource")) { + if (state != InResource) { + fprintf(stderr, "Unexpected end of qresource tag in line %d\n", int(reader.lineNumber())); + return EXIT_FAILURE; + } + state = InRCC; + } else if (reader.name() == QStringLiteral("RCC")) { + if (state != InRCC) { + fprintf(stderr, "Unexpected end of RCC tag in line %d\n", int(reader.lineNumber())); + return EXIT_FAILURE; + } + state = InitialState; + } + writer.writeEndElement(); + continue; + + case QXmlStreamReader::Characters: + if (reader.isWhitespace()) + break; + if (state != InFile) + return EXIT_FAILURE; + currentFileName = reader.text().toString(); + if (currentFileName.isEmpty()) + continue; + + writer.writeStartElement(QStringLiteral("file")); + + if (!fileAttributes.hasAttribute(QStringLiteral("alias"))) + fileAttributes.append(QStringLiteral("alias"), currentFileName); + + currentFileName = inputDirectory.absoluteFilePath(currentFileName); + currentFileName = outputDirectory.relativeFilePath(currentFileName); + + writer.writeAttributes(fileAttributes); + writer.writeCharacters(currentFileName); + writer.writeEndElement(); + continue; + + default: break; + } + } + + QFile outputFile(output); + if (!outputFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + fprintf(stderr, "Cannot open %s for writing.\n", qPrintable(output)); + return EXIT_FAILURE; + } + const QByteArray outputStringUtf8 = outputString.toUtf8(); + if (outputFile.write(outputStringUtf8) != outputStringUtf8.size()) + return EXIT_FAILURE; + + outputFile.close(); + if (outputFile.error() != QFileDevice::NoError) + return EXIT_FAILURE; + + + return EXIT_SUCCESS; +} |