Skip to content

Commit 41864db

Browse files
committed
Fix *.js files disappearing from RESOURCES when not using QtQml
[ChangeLog][QtQml][Important Behavior Changes] Using the Qt Quick Compiler would exclude the original .qml files from the resource system. This made it impossible to change the Qt library binary later as the program binary was tied the to the exact Qt version. In addition sometimes unrelated files (QTBUG-73669) were removed. For the latter scenario, retain and skip options were added for the Qt Quick Compiler. In Qt 5.15 the Qt Quick Compiler does not remove the input files anymore. All files are retained and the compiler merely adds the more efficient binary representation to the application. Task-number: QTBUG-73669 Change-Id: I5a523bfc69d4f48a1451bd880616c82fd73b8d15 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
1 parent c716753 commit 41864db

File tree

7 files changed

+18
-483
lines changed

7 files changed

+18
-483
lines changed

tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ static QQmlPrivate::CachedQmlUnit *temporaryModifiedCachedUnit = nullptr;
360360
void tst_qmlcachegen::versionChecksForAheadOfTimeUnits()
361361
{
362362
QVERIFY(QFile::exists(":/data/versionchecks.qml"));
363-
QCOMPARE(QFileInfo(":/data/versionchecks.qml").size(), 0);
363+
QVERIFY(QFileInfo(":/data/versionchecks.qml").size() > 0);
364364

365365
Q_ASSERT(!temporaryModifiedCachedUnit);
366366
QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
@@ -387,12 +387,8 @@ void tst_qmlcachegen::versionChecksForAheadOfTimeUnits()
387387

388388
{
389389
QQmlEngine engine;
390-
QQmlComponent component(&engine, QUrl("qrc:/data/versionchecks.qml"));
391-
QCOMPARE(component.status(), QQmlComponent::Error);
392-
QCOMPARE(component.errorString(),
393-
QString("qrc:/data/versionchecks.qml:-1 File was compiled ahead of time with an "
394-
"incompatible version of Qt and the original file cannot be found. Please "
395-
"recompile\n"));
390+
CleanlyLoadingComponent component(&engine, QUrl("qrc:/data/versionchecks.qml"));
391+
QCOMPARE(component.status(), QQmlComponent::Ready);
396392
}
397393

398394
Q_ASSERT(temporaryModifiedCachedUnit);
@@ -414,7 +410,7 @@ void tst_qmlcachegen::workerScripts()
414410
{
415411
QVERIFY(QFile::exists(":/workerscripts/data/worker.js"));
416412
QVERIFY(QFile::exists(":/workerscripts/data/worker.qml"));
417-
QCOMPARE(QFileInfo(":/workerscripts/data/worker.js").size(), 0);
413+
QVERIFY(QFileInfo(":/workerscripts/data/worker.js").size() > 0);
418414

419415
QQmlEngine engine;
420416
CleanlyLoadingComponent component(&engine, QUrl("qrc:///workerscripts/data/worker.qml"));
@@ -503,7 +499,7 @@ void tst_qmlcachegen::trickyPaths()
503499
{
504500
QFETCH(QString, filePath);
505501
QVERIFY2(QFile::exists(filePath), qPrintable(filePath));
506-
QCOMPARE(QFileInfo(filePath).size(), 0);
502+
QVERIFY(QFileInfo(filePath).size() > 0);
507503
QQmlEngine engine;
508504
QQmlComponent component(&engine, QUrl("qrc" + filePath));
509505
QScopedPointer<QObject> obj(component.create());
@@ -584,7 +580,7 @@ void tst_qmlcachegen::moduleScriptImport()
584580
QTRY_VERIFY(obj->property("ok").toBool());
585581

586582
QVERIFY(QFile::exists(":/data/script.mjs"));
587-
QCOMPARE(QFileInfo(":/data/script.mjs").size(), 0);
583+
QVERIFY(QFileInfo(":/data/script.mjs").size() > 0);
588584

589585
{
590586
auto componentPrivate = QQmlComponentPrivate::get(&component);
@@ -617,7 +613,7 @@ void tst_qmlcachegen::enums()
617613
void tst_qmlcachegen::sourceFileIndices()
618614
{
619615
QVERIFY(QFile::exists(":/data/versionchecks.qml"));
620-
QCOMPARE(QFileInfo(":/data/versionchecks.qml").size(), 0);
616+
QVERIFY(QFileInfo(":/data/versionchecks.qml").size() > 0);
621617

622618
QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
623619
const QV4::CompiledData::Unit *unitFromResources = QQmlMetaType::findCachedCompilationUnit(

tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,9 @@ but not all the files it references.
5050

5151
get_filename_component(input_resource ${_resource} ABSOLUTE)
5252

53-
execute_process(COMMAND ${compiler_path} -filter-resource-file ${input_resource} -o ${new_resource_file} OUTPUT_VARIABLE remaining_files)
54-
if(remaining_files)
55-
list(APPEND filtered_rcc_files ${new_resource_file})
56-
list(APPEND loader_flags \"--resource-file-mapping=${_resource}=${new_resource_file}\")
57-
else()
58-
list(APPEND loader_flags \"--resource-file-mapping=${_resource}\")
59-
endif()
53+
configure_file(${input_resource} ${new_resource_file} COPYONLY)
54+
list(APPEND filtered_rcc_files ${new_resource_file})
55+
list(APPEND loader_flags \"--resource-file-mapping=${_resource}=${new_resource_file}\")
6056

6157
set(rcc_file_with_compilation_units)
6258

tools/qmlcachegen/generateloader.cpp

Lines changed: 2 additions & 231 deletions
Original file line numberDiff line numberDiff line change
@@ -100,228 +100,6 @@ QString symbolNamespaceForPath(const QString &relativePath)
100100
return mangledIdentifier(symbol);
101101
}
102102

103-
struct VirtualDirectoryEntry
104-
{
105-
QString name;
106-
QVector<VirtualDirectoryEntry*> dirEntries;
107-
int firstChildIndex = -1; // node index inside generated data
108-
bool isDirectory = true;
109-
110-
VirtualDirectoryEntry()
111-
{}
112-
113-
~VirtualDirectoryEntry()
114-
{
115-
qDeleteAll(dirEntries);
116-
}
117-
118-
VirtualDirectoryEntry *append(const QString &name)
119-
{
120-
for (QVector<VirtualDirectoryEntry*>::Iterator it = dirEntries.begin(), end = dirEntries.end();
121-
it != end; ++it) {
122-
if ((*it)->name == name)
123-
return *it;
124-
}
125-
126-
VirtualDirectoryEntry *subEntry = new VirtualDirectoryEntry;
127-
subEntry->name = name;
128-
dirEntries.append(subEntry);
129-
return subEntry;
130-
}
131-
132-
void appendEmptyFile(const QString &name)
133-
{
134-
VirtualDirectoryEntry *subEntry = new VirtualDirectoryEntry;
135-
subEntry->name = name;
136-
subEntry->isDirectory = false;
137-
dirEntries.append(subEntry);
138-
}
139-
140-
bool isEmpty() const { return dirEntries.isEmpty(); }
141-
};
142-
143-
struct DataStream
144-
{
145-
DataStream(QVector<unsigned char > *data = nullptr)
146-
: data(data)
147-
{}
148-
149-
qint64 currentOffset() const { return data->size(); }
150-
151-
DataStream &operator<<(quint16 value)
152-
{
153-
unsigned char d[2];
154-
qToBigEndian(value, d);
155-
data->append(d[0]);
156-
data->append(d[1]);
157-
return *this;
158-
}
159-
DataStream &operator<<(quint32 value)
160-
{
161-
unsigned char d[4];
162-
qToBigEndian(value, d);
163-
data->append(d[0]);
164-
data->append(d[1]);
165-
data->append(d[2]);
166-
data->append(d[3]);
167-
return *this;
168-
}
169-
private:
170-
QVector<unsigned char> *data;
171-
};
172-
173-
static bool resource_sort_order(const VirtualDirectoryEntry *lhs, const VirtualDirectoryEntry *rhs)
174-
{
175-
return qt_hash(lhs->name) < qt_hash(rhs->name);
176-
}
177-
178-
struct ResourceTree
179-
{
180-
ResourceTree()
181-
{}
182-
183-
void serialize(VirtualDirectoryEntry &root, QVector<unsigned char> *treeData, QVector<unsigned char> *stringData)
184-
{
185-
treeStream = DataStream(treeData);
186-
stringStream = DataStream(stringData);
187-
188-
QStack<VirtualDirectoryEntry *> directories;
189-
190-
{
191-
directories.push(&root);
192-
while (!directories.isEmpty()) {
193-
VirtualDirectoryEntry *entry = directories.pop();
194-
registerString(entry->name);
195-
if (entry->isDirectory)
196-
directories << entry->dirEntries;
197-
}
198-
}
199-
200-
{
201-
quint32 currentDirectoryIndex = 1;
202-
directories.push(&root);
203-
while (!directories.isEmpty()) {
204-
VirtualDirectoryEntry *entry = directories.pop();
205-
entry->firstChildIndex = currentDirectoryIndex;
206-
currentDirectoryIndex += entry->dirEntries.count();
207-
std::sort(entry->dirEntries.begin(), entry->dirEntries.end(), resource_sort_order);
208-
209-
for (QVector<VirtualDirectoryEntry*>::ConstIterator child = entry->dirEntries.constBegin(), end = entry->dirEntries.constEnd();
210-
child != end; ++child) {
211-
if ((*child)->isDirectory)
212-
directories << *child;
213-
}
214-
}
215-
}
216-
217-
{
218-
writeTreeEntry(&root);
219-
directories.push(&root);
220-
while (!directories.isEmpty()) {
221-
VirtualDirectoryEntry *entry = directories.pop();
222-
223-
for (QVector<VirtualDirectoryEntry*>::ConstIterator child = entry->dirEntries.constBegin(), end = entry->dirEntries.constEnd();
224-
child != end; ++child) {
225-
writeTreeEntry(*child);
226-
if ((*child)->isDirectory)
227-
directories << (*child);
228-
}
229-
}
230-
}
231-
}
232-
233-
private:
234-
DataStream treeStream;
235-
DataStream stringStream;
236-
QHash<QString, qint64> stringOffsets;
237-
238-
void registerString(const QString &name)
239-
{
240-
if (stringOffsets.contains(name))
241-
return;
242-
const qint64 offset = stringStream.currentOffset();
243-
stringOffsets.insert(name, offset);
244-
245-
stringStream << quint16(name.length())
246-
<< quint32(qt_hash(name));
247-
for (int i = 0; i < name.length(); ++i)
248-
stringStream << quint16(name.at(i).unicode());
249-
}
250-
251-
void writeTreeEntry(VirtualDirectoryEntry *entry)
252-
{
253-
treeStream << quint32(stringOffsets.value(entry->name))
254-
<< quint16(entry->isDirectory ? 0x2 : 0x0); // Flags: File or Directory
255-
256-
if (entry->isDirectory) {
257-
treeStream << quint32(entry->dirEntries.count())
258-
<< quint32(entry->firstChildIndex);
259-
} else {
260-
treeStream << quint16(QLocale::AnyCountry) << quint16(QLocale::C)
261-
<< quint32(0x0);
262-
}
263-
}
264-
};
265-
266-
static QByteArray generateResourceDirectoryTree(QTextStream &code, const QStringList &qrcFiles,
267-
const QStringList &sortedRetainedFiles)
268-
{
269-
QByteArray call;
270-
if (qrcFiles.isEmpty())
271-
return call;
272-
273-
VirtualDirectoryEntry resourceDirs;
274-
resourceDirs.name = QStringLiteral("/");
275-
276-
for (const QString &entry : qrcFiles) {
277-
const QStringList segments = entry.split(QLatin1Char('/'), QString::SkipEmptyParts);
278-
279-
VirtualDirectoryEntry *dirEntry = &resourceDirs;
280-
281-
for (int i = 0; i < segments.count() - 1; ++i)
282-
dirEntry = dirEntry->append(segments.at(i));
283-
if (!std::binary_search(sortedRetainedFiles.begin(), sortedRetainedFiles.end(), entry))
284-
dirEntry->appendEmptyFile(segments.last());
285-
}
286-
287-
if (resourceDirs.isEmpty())
288-
return call;
289-
290-
QVector<unsigned char> names;
291-
QVector<unsigned char> tree;
292-
ResourceTree().serialize(resourceDirs, &tree, &names);
293-
294-
code << "static const unsigned char qt_resource_tree[] = {\n";
295-
for (int i = 0; i < tree.count(); ++i) {
296-
code << uint(tree.at(i));
297-
if (i < tree.count() - 1)
298-
code << ',';
299-
if (i % 16 == 0)
300-
code << '\n';
301-
}
302-
code << "};\n";
303-
304-
code << "static const unsigned char qt_resource_names[] = {\n";
305-
for (int i = 0; i < names.count(); ++i) {
306-
code << uint(names.at(i));
307-
if (i < names.count() - 1)
308-
code << ',';
309-
if (i % 16 == 0)
310-
code << '\n';
311-
}
312-
code << "};\n";
313-
314-
code << "static const unsigned char qt_resource_empty_payout[] = { 0, 0, 0, 0, 0 };\n";
315-
316-
code << "QT_BEGIN_NAMESPACE\n";
317-
code << "extern Q_CORE_EXPORT bool qRegisterResourceData(int, const unsigned char *, const unsigned char *, const unsigned char *);\n";
318-
code << "QT_END_NAMESPACE\n";
319-
320-
call = "QT_PREPEND_NAMESPACE(qRegisterResourceData)(/*version*/0x01, qt_resource_tree, qt_resource_names, qt_resource_empty_payout);\n";
321-
322-
return call;
323-
}
324-
325103
static QString qtResourceNameForFile(const QString &fileName)
326104
{
327105
QFileInfo fi(fileName);
@@ -332,9 +110,8 @@ static QString qtResourceNameForFile(const QString &fileName)
332110
return name;
333111
}
334112

335-
bool generateLoader(const QStringList &compiledFiles, const QStringList &sortedRetainedFiles,
336-
const QString &outputFileName, const QStringList &resourceFileMappings,
337-
QString *errorString)
113+
bool generateLoader(const QStringList &compiledFiles, const QString &outputFileName,
114+
const QStringList &resourceFileMappings, QString *errorString)
338115
{
339116
QByteArray generatedLoaderCode;
340117

@@ -345,9 +122,6 @@ bool generateLoader(const QStringList &compiledFiles, const QStringList &sortedR
345122
stream << "#include <QtCore/qurl.h>\n";
346123
stream << "\n";
347124

348-
QByteArray resourceRegisterCall = generateResourceDirectoryTree(stream, compiledFiles,
349-
sortedRetainedFiles);
350-
351125
stream << "namespace QmlCacheGeneratedCode {\n";
352126
for (int i = 0; i < compiledFiles.count(); ++i) {
353127
const QString compiledFile = compiledFiles.at(i);
@@ -385,9 +159,6 @@ bool generateLoader(const QStringList &compiledFiles, const QStringList &sortedR
385159
stream << " registration.lookupCachedQmlUnit = &lookupCachedUnit;\n";
386160
stream << " QQmlPrivate::qmlregister(QQmlPrivate::QmlUnitCacheHookRegistration, &registration);\n";
387161

388-
if (!resourceRegisterCall.isEmpty())
389-
stream << resourceRegisterCall;
390-
391162
stream << "}\n\n";
392163
stream << "Registry::~Registry() {\n";
393164
stream << " QQmlPrivate::qmlunregister(QQmlPrivate::QmlUnitCacheHookRegistration, quintptr(&lookupCachedUnit));\n";

tools/qmlcachegen/qmlcachegen.cpp

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,8 @@
4747

4848
using namespace QQmlJS;
4949

50-
int filterResourceFile(const QString &input, const QString &output);
51-
bool generateLoader(const QStringList &compiledFiles, const QStringList &retainedFiles,
52-
const QString &output, const QStringList &resourceFileMappings,
53-
QString *errorString);
50+
bool generateLoader(const QStringList &compiledFiles, const QString &output,
51+
const QStringList &resourceFileMappings, QString *errorString);
5452
QString symbolNamespaceForPath(const QString &relativePath);
5553

5654
QSet<QString> illegalNames;
@@ -419,14 +417,10 @@ int main(int argc, char **argv)
419417
parser.addHelpOption();
420418
parser.addVersionOption();
421419

422-
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"));
423-
parser.addOption(filterResourceFileOption);
424420
QCommandLineOption resourceFileMappingOption(QStringLiteral("resource-file-mapping"), QCoreApplication::translate("main", "Path from original resource file to new one"), QCoreApplication::translate("main", "old-name:new-name"));
425421
parser.addOption(resourceFileMappingOption);
426422
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"));
427423
parser.addOption(resourceOption);
428-
QCommandLineOption retainOption(QStringLiteral("retain"), QCoreApplication::translate("main", "Qt resource file the contents of which should not be replaced by empty stubs"), QCoreApplication::translate("main", "resource-file-name"));
429-
parser.addOption(retainOption);
430424
QCommandLineOption resourcePathOption(QStringLiteral("resource-path"), QCoreApplication::translate("main", "Qt resource file path corresponding to the file being compiled"), QCoreApplication::translate("main", "resource-path"));
431425
parser.addOption(resourcePathOption);
432426

@@ -468,18 +462,11 @@ int main(int argc, char **argv)
468462
if (outputFileName.isEmpty())
469463
outputFileName = inputFile + QLatin1Char('c');
470464

471-
if (parser.isSet(filterResourceFileOption)) {
472-
return filterResourceFile(inputFile, outputFileName);
473-
}
474-
475465
if (target == GenerateLoader) {
476466
ResourceFileMapper mapper(sources);
477-
ResourceFileMapper retain(parser.values(retainOption));
478467

479468
Error error;
480-
QStringList retainedFiles = retain.qmlCompilerFiles();
481-
std::sort(retainedFiles.begin(), retainedFiles.end());
482-
if (!generateLoader(mapper.qmlCompilerFiles(), retainedFiles, outputFileName,
469+
if (!generateLoader(mapper.qmlCompilerFiles(), outputFileName,
483470
parser.values(resourceFileMappingOption), &error.message)) {
484471
error.augment(QLatin1String("Error generating loader stub: ")).print();
485472
return EXIT_FAILURE;

tools/qmlcachegen/qmlcachegen.pro

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ QT = qmldevtools-private
44
DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII
55

66
SOURCES = qmlcachegen.cpp \
7-
resourcefilter.cpp \
87
generateloader.cpp \
98
resourcefilemapper.cpp
109
TARGET = qmlcachegen

0 commit comments

Comments
 (0)