wasm: make qtloader.js use FS.createPreloadedFile when preloading

Currently qtloader.js fetches and copies the files manually. By doing
so we are missing some preproccessing by Emscripten preload plugins.
Use Emscripten API to preload files, so preload plugin for .so can
download, compile and resolve dependencies of imported shared libraries.

This makes looking for dependencies in preload_qml_import.py no longer
needed. Remove redundant code.

Fixes: QTBUG-121817
Change-Id: Idd35f25d5f54123910f813a636407eea23e157cb
Reviewed-by: Piotr Wierciński <piotr.wiercinski@qt.io>
This commit is contained in:
Piotr Wiercinski 2024-02-23 17:14:08 +01:00 committed by Piotr Wierciński
parent 0c85b69b86
commit a6e7274704
2 changed files with 19 additions and 35 deletions

View File

@ -120,14 +120,15 @@ async function qtLoad(config)
}
}
}
const fetchJsonHelper = async path => (await fetch(path)).json();
const filesToPreload = (await Promise.all(config.qt.preload.map(fetchJsonHelper))).flat();
const qtPreRun = (instance) => {
// Copy qt.environment to instance.ENV
throwIfEnvUsedButNotExported(instance, config);
for (const [name, value] of Object.entries(config.qt.environment ?? {}))
instance.ENV[name] = value;
// Copy self.preloadData to MEMFS
// Preload files from qt.preload
const makeDirs = (FS, filePath) => {
const parts = filePath.split("/");
let path = "/";
@ -146,14 +147,25 @@ async function qtLoad(config)
}
}
const extractFilenameAndDir = (path) => {
const parts = path.split('/');
const filename = parts.pop();
const dir = parts.join('/');
return {
filename: filename,
dir: dir
};
}
const preloadFile = (file) => {
makeDirs(instance.FS, file.destination);
const source = file.source.replace('$QTDIR', config.qt.qtdir);
const filenameAndDir = extractFilenameAndDir(file.destination);
instance.FS.createPreloadedFile(filenameAndDir.dir, filenameAndDir.filename, source, true, true);
}
const isFsExported = typeof instance.FS === 'object';
if (!isFsExported)
throw new Error('FS must be exported if preload is used');
for ({destination, data} of self.preloadData) {
makeDirs(instance.FS, destination);
instance.FS.writeFile(destination, new Uint8Array(data));
}
filesToPreload.forEach(preloadFile);
}
if (!config.preRun)
@ -197,22 +209,6 @@ async function qtLoad(config)
}
};
const fetchPreloadFiles = async () => {
const fetchJson = async path => (await fetch(path)).json();
const fetchArrayBuffer = async path => (await fetch(path)).arrayBuffer();
const loadFiles = async (paths) => {
const source = paths['source'].replace('$QTDIR', config.qt.qtdir);
return {
destination: paths['destination'],
data: await fetchArrayBuffer(source)
};
}
const fileList = (await Promise.all(config.qt.preload.map(fetchJson))).flat();
self.preloadData = (await Promise.all(fileList.map(loadFiles))).flat();
}
await fetchPreloadFiles();
// Call app/emscripten module entry function. It may either come from the emscripten
// runtime script or be customized as needed.
let instance;

View File

@ -6,9 +6,6 @@ import os
import sys
import subprocess
import json
import re
from wasm_binary_tools import WasmBinary
# Paths to shared libraries and qml imports on the Qt installation on the web server.
# "$QTDIR" is replaced by qtloader.js at load time (defaults to "qt"), and makes
@ -30,11 +27,6 @@ def preload_file(source, destination):
preload_files.append({"source": source, "destination": destination})
def find_dependencies(filepath):
binary = WasmBinary(filepath)
return binary.get_dependencies()
def extract_preload_files_from_imports(imports):
libraries = []
for qml_import in imports:
@ -55,10 +47,6 @@ def extract_preload_files_from_imports(imports):
so_plugin_qt_install_path = os.path.join(
qt_wasm_path, "qml", relative_path, plugin_filename
)
deps = find_dependencies(so_plugin_qt_install_path)
if plugin_filename in deps: # sometimes plugin file itself is found as its dependency
deps.remove(plugin_filename)
libraries.extend(deps)
# qmldir file
qmldir_source_path = os.path.join(qt_qml_path, relative_path, "qmldir")