qt 6.6.0 clean

This commit is contained in:
kleuter
2023-11-01 22:23:55 +01:00
parent 7b5ada15e7
commit 5d8194efa7
1449 changed files with 134276 additions and 31391 deletions

View File

@ -68,9 +68,9 @@ export class BatchedTestRunner {
get errorDetails() { return this.#errorDetails; }
async run(targetIsBatch, testName, testOutputFormat) {
async run(targetIsBatch, testName, functions, testOutputFormat) {
try {
await this.#doRun(targetIsBatch, testName, testOutputFormat);
await this.#doRun(targetIsBatch, testName, functions, testOutputFormat);
} catch (e) {
this.#setTestRunnerError(e.message);
return;
@ -93,7 +93,7 @@ export class BatchedTestRunner {
this.#setTestRunnerStatus(status.code, status.numberOfFailed);
}
async #doRun(targetIsBatch, testName, testOutputFormat) {
async #doRun(targetIsBatch, testName, functions, testOutputFormat) {
const module = await this.#loader.loadEmscriptenModule(
targetIsBatch ? BatchedTestRunner.#TestBatchModuleName : testName,
() => { }
@ -111,6 +111,7 @@ export class BatchedTestRunner {
const LogToStdoutSpecialFilename = '-';
result = await module.exec({
args: [...(targetIsBatch ? [testClassName] : []),
...(functions ?? []),
'-o', `${LogToStdoutSpecialFilename},${testOutputFormat}`],
onStdout: (output) => {
this.#addTestOutput(testClassName, output);

View File

@ -5,8 +5,13 @@ import { RunnerStatus, TestStatus } from './batchedtestrunner.js';
// Sends messages to the running emrun instance via POST requests.
export class EmrunCommunication {
static #BATCHING_DELAY = 300;
#indexOfMessage = 0;
#postOutputPromises = [];
#postOutputPromise;
// Accumulate output in a batch that gets sent with a delay so that the emrun http server
// does not get pounded with requests.
#nextOutputBatch = null;
#post(body) {
return fetch('stdio.html', {
@ -15,10 +20,11 @@ export class EmrunCommunication {
});
}
// Returns a promise whose resolution signals that all outstanding traffic to the emrun instance
// has been completed.
waitUntilAllSent() {
return Promise.all(this.#postOutputPromises);
// Waits for the output sending to finish, if any output transfer is still in progress.
async waitUntilAllSent()
{
if (this.#postOutputPromise)
await this.#postOutputPromise;
}
// Posts the exit status to the running emrun instance. Emrun will drop connection unless it is
@ -29,13 +35,25 @@ export class EmrunCommunication {
// Posts an indexed output chunk to the running emrun instance. Each consecutive call to this
// method increments the output index by 1.
postOutput(output) {
const newPromise = this.#post(`^out^${this.#indexOfMessage++}^${output}`);
this.#postOutputPromises.push(newPromise);
newPromise.finally(() => {
this.#postOutputPromises.splice(this.#postOutputPromises.indexOf(newPromise), 1);
});
return newPromise;
postOutput(output)
{
if (this.#nextOutputBatch) {
this.#nextOutputBatch += output;
} else {
this.#nextOutputBatch = output;
this.#postOutputPromise = new Promise(resolve =>
{
window.setTimeout(() =>
{
const toSend = this.#nextOutputBatch;
this.#nextOutputBatch = null;
this.#post(`^out^${this.#indexOfMessage++}^${toSend}$`)
.finally(resolve);
}, EmrunCommunication.#BATCHING_DELAY);
});
}
return this.#postOutputPromise;
}
}

View File

@ -176,12 +176,6 @@ export class CompiledModule {
instanceParams.monitorRunDependencies = (name) => { };
instanceParams.print = (text) => true && console.log(text);
instanceParams.printErr = (text) => true && console.warn(text);
instanceParams.preRun = [
(instance) => {
const env = {};
instance.ENV = env;
},
];
instanceParams.mainScriptUrlOrBlob = new Blob([this.#js], {
type: 'text/javascript',

View File

@ -11,6 +11,22 @@ import {
import { parseQuery } from './util.js';
import { VisualOutputProducer, UI, ScannerFactory } from './qtestoutputreporter.js'
const StandardArg = {
qVisualOutput: 'qvisualoutput',
qTestName: 'qtestname',
qBatchedTest: 'qbatchedtest',
qUseEmrun: 'quseemrun',
qTestOutputFormat: 'qtestoutputformat',
}
const allArgs = new Set(Object.getOwnPropertyNames(StandardArg).map(arg => StandardArg[arg]));
Object.defineProperty(StandardArg, 'isKnown', {
get()
{
return name => allArgs.has(name);
},
});
(() => {
const setPageTitle = (useEmrun, testName, isBatch) => {
document.title = 'Qt WASM test runner';
@ -24,10 +40,11 @@ import { VisualOutputProducer, UI, ScannerFactory } from './qtestoutputreporter.
}
const parsed = parseQuery(location.search);
const outputInPage = parsed.get('qvisualoutput') !== undefined;
const testName = parsed.get('qtestname');
const isBatch = parsed.get('qbatchedtest') !== undefined;
const useEmrun = parsed.get('quseemrun') !== undefined;
const outputInPage = parsed.has(StandardArg.qVisualOutput);
const testName = parsed.get(StandardArg.qTestName);
const isBatch = parsed.has(StandardArg.qBatchedTest);
const useEmrun = parsed.has(StandardArg.qUseEmrun);
const functions = [...parsed.keys()].filter(arg => !StandardArg.isKnown(arg));
if (testName === undefined) {
if (!isBatch)
@ -37,7 +54,7 @@ import { VisualOutputProducer, UI, ScannerFactory } from './qtestoutputreporter.
}
const testOutputFormat = (() => {
const format = parsed.get('qtestoutputformat') ?? 'txt';
const format = parsed.get(StandardArg.qTestOutputFormat) ?? 'txt';
if (-1 === ['txt', 'xml', 'lightxml', 'junitxml', 'tap'].indexOf(format))
throw new Error(`Bad file format: ${format}`);
return format;
@ -65,5 +82,5 @@ import { VisualOutputProducer, UI, ScannerFactory } from './qtestoutputreporter.
}
setPageTitle(useEmrun, testName, isBatch);
testRunner.run(isBatch, testName, testOutputFormat);
testRunner.run(isBatch, testName, functions, testOutputFormat);
})();

View File

@ -0,0 +1,120 @@
#!/usr/bin/env python3
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import os
import sys
import subprocess
import json
import re
# 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
# possible to relocate the application build relative to the Qt build on the web server.
qt_lib_path = "$QTDIR/lib"
qt_qml_path = "$QTDIR/qml"
# Path to QML imports on the in-memory file system provided by Emscripten. This script emits
# preload commands which copies QML imports to this directory. In addition, preload_qt_plugins.py
# creates (and preloads) a qt.conf file which makes Qt load QML plugins from this location.
qt_deploy_qml_path = "/qt/qml"
def eprint(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
def preload_file(source, destination):
preload_files.append({"source": source, "destination": destination})
def find_dependencies(filepath):
# Very basic dependency finder which scans for ".so" strings in the file
try:
with open(filepath, "rb") as file:
content = file.read()
return [
m.group(0).decode("utf-8")
for m in re.finditer(rb"[\w\-.]+\.so", content)
]
except IOError as e:
eprint(f"Error: {e}")
return []
def extract_preload_files_from_imports(imports):
libraries = []
files = []
for qml_import in imports:
try:
relative_path = qml_import["relativePath"]
plugin = qml_import["plugin"]
# plugin .so
so_plugin_source_path = os.path.join(
qt_qml_path, relative_path, "lib" + plugin + ".so"
)
so_plugin_destination_path = os.path.join(
qt_deploy_qml_path, relative_path, "lib" + plugin + ".so"
)
preload_file(so_plugin_source_path, so_plugin_destination_path)
so_plugin_qt_install_path = os.path.join(
qt_wasm_path, "qml", relative_path, "lib" + plugin + ".so"
)
deps = find_dependencies(so_plugin_qt_install_path)
libraries.extend(deps)
# qmldir file
qmldir_source_path = os.path.join(qt_qml_path, relative_path, "qmldir")
qmldir_destination_path = os.path.join(
qt_deploy_qml_path, relative_path, "qmldir"
)
preload_file(qmldir_source_path, qmldir_destination_path)
except Exception as e:
eprint(e)
continue
return files, libraries
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: python make_qt_symlinks.py <qt-host-path> <qt-wasm-path>")
sys.exit(1)
qt_host_path = sys.argv[1]
qt_wasm_path = sys.argv[2]
qml_import_path = os.path.join(qt_wasm_path, "qml")
qmlimportsscanner_path = os.path.join(qt_host_path, "libexec/qmlimportscanner")
eprint("runing qmlimportsscanner")
result = subprocess.run(
[qmlimportsscanner_path, "-rootPath", ".", "-importPath", qml_import_path],
stdout=subprocess.PIPE,
)
imports = json.loads(result.stdout)
preload_files = []
libraries = []
files, libraries = extract_preload_files_from_imports(imports)
# Deploy plugin dependencies, that is, shared libraries used by the plugins.
# Skip some of the obvious libraries which will be
skip_libraries = [
"libQt6Core.so",
"libQt6Gui.so",
"libQt6Quick.so",
"libQt6Qml.so" "libQt6Network.so",
"libQt6OpenGL.so",
]
libraries = set(libraries) - set(skip_libraries)
for library in libraries:
source = os.path.join(qt_lib_path, library)
# Emscripten looks for shared libraries on "/", shared libraries
# most be deployed there instead of at /qt/lib
destination = os.path.join("/", library)
preload_file(source, destination)
print(json.dumps(preload_files, indent=2))

View File

@ -0,0 +1,54 @@
#!/usr/bin/env python3
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import os
import sys
import json
# Path to plugins on the Qt installation on the web server. "$QTPATH" is replaced by qtloader.js
# at load time (defaults to "qt"), which makes it possible to relocate the application build relative
# to the Qt build on the web server.
qt_plugins_path = "$QTDIR/plugins"
# Path to plugins on the in-memory file system provided by Emscripten. This script emits
# preload commands which copies plugins to this directory.
qt_deploy_plugins_path = "/qt/plugins"
def find_so_files(directory):
so_files = []
for root, dirs, files in os.walk(directory):
for file in files:
if file.endswith(".so"):
relative_path = os.path.relpath(os.path.join(root, file), directory)
so_files.append(relative_path)
return so_files
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python make_qt_symlinks.py <qt-wasm-path>")
sys.exit(1)
qt_wasm_path = sys.argv[1]
# preload all plugins
plugins = find_so_files(os.path.join(qt_wasm_path, "plugins"))
preload = [
{
"source": os.path.join(qt_plugins_path, plugin),
"destination": os.path.join(qt_deploy_plugins_path, plugin),
}
for plugin in plugins
]
# Create and preload qt.conf which will tell Qt to look for plugins
# and QML imports in /qt/plugins and /qt/qml. The qt.conf file is
# written to the current directory.
qtconf = "[Paths]\nPrefix = /qt\n"
with open("qt.conf", "w") as f:
f.write(qtconf)
preload.append({"source": "qt.conf", "destination": "/qt.conf"})
print(json.dumps(preload, indent=2))