qtbase/src/corelib/Qt6WasmMacros.cmake
Piotr Wierciński 06ab82d945 wasm: Add helper for pluging preloads
Dynamic linking on WebAssembly involves preloading .so libraries
during startup of application. Normally, those plugin preload
lists are generating manually by user, which can be tedious.
Add a bash script which demonstrates how to call python
programs to generate preload lists.

Change-Id: I0a9869ad0d26606f8b33af2c38248cec3088dd0d
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
(cherry picked from commit 010ed1788402bf98d9b98500fdb1f61c333cebe5)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2025-01-13 20:27:15 +00:00

211 lines
9.5 KiB
CMake

# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
# Copy in Qt HTML/JS launch files for apps.
function(_qt_internal_wasm_add_target_helpers target)
_qt_test_emscripten_version()
get_target_property(targetType "${target}" TYPE)
if("${targetType}" STREQUAL "EXECUTABLE")
if(QT6_INSTALL_PREFIX)
set(WASM_BUILD_DIR "${QT6_INSTALL_PREFIX}")
elseif(QT_BUILD_DIR)
set(WASM_BUILD_DIR "${QT_BUILD_DIR}")
endif()
get_target_property(output_name ${target} OUTPUT_NAME)
if(output_name)
set(_target_output_name "${output_name}")
else()
set(_target_output_name "${target}")
endif()
set(APPNAME ${_target_output_name})
_qt_internal_wasm_export_name_for_target(_export_name ${target})
set(APPEXPORTNAME ${_export_name})
# Shared library builds preload plugins and qml imports by default.
# The json files are generated by scripts in qtbase/util/wasm/preload
if (QT_FEATURE_shared)
set(PRELOAD "preload: ['qt_plugins.json', 'qt_qml_imports.json'],")
else()
set(PRELOAD "")
endif()
get_target_property(target_output_directory ${target} RUNTIME_OUTPUT_DIRECTORY)
get_target_property(is_test ${target} _qt_is_test_executable)
get_target_property(is_manual_test ${target} _qt_is_manual_test)
if(is_test AND NOT is_manual_test)
# Keep in sync with testrunner_files in testlib/CMakeLists.txt
configure_file("${WASM_BUILD_DIR}/libexec/batchedtestrunner.html"
"${target_output_directory}/${_target_output_name}.html" COPYONLY)
configure_file("${WASM_BUILD_DIR}/libexec/qtestoutputreporter.css"
"${target_output_directory}/qtestoutputreporter.css" COPYONLY)
configure_file("${WASM_BUILD_DIR}/libexec/batchedtestrunner.js"
"${target_output_directory}/batchedtestrunner.js" COPYONLY)
configure_file("${WASM_BUILD_DIR}/libexec/emrunadapter.js"
"${target_output_directory}/emrunadapter.js" COPYONLY)
configure_file("${WASM_BUILD_DIR}/libexec/qwasmjsruntime.js"
"${target_output_directory}/qwasmjsruntime.js" COPYONLY)
configure_file("${WASM_BUILD_DIR}/libexec/qwasmtestmain.js"
"${target_output_directory}/qwasmtestmain.js" COPYONLY)
configure_file("${WASM_BUILD_DIR}/libexec/qtestoutputreporter.js"
"${target_output_directory}/qtestoutputreporter.js" COPYONLY)
configure_file("${WASM_BUILD_DIR}/libexec/util.js"
"${target_output_directory}/util.js" COPYONLY)
else()
get_target_property(no_wasm_files ${target} NO_WASM_DEFAULT_FILES)
if(target_output_directory)
set(_target_directory "${target_output_directory}")
else()
set(_target_directory "${CMAKE_CURRENT_BINARY_DIR}")
endif()
if (NOT no_wasm_files)
configure_file("${WASM_BUILD_DIR}/plugins/platforms/wasm_shell.html"
"${_target_directory}/${_target_output_name}.html" @ONLY)
if(CMAKE_CONFIGURATION_TYPES) # if multiconfig generator
add_custom_command(
TARGET ${target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${_target_directory}/${_target_output_name}.html"
${_target_directory}/$<CONFIG>/${_target_output_name}.html
)
add_custom_command(
TARGET ${target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${WASM_BUILD_DIR}/plugins/platforms/qtloader.js"
${_target_directory}/$<CONFIG>/qtloader.js
)
add_custom_command(
TARGET ${target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${WASM_BUILD_DIR}/plugins/platforms/qtlogo.svg"
${_target_directory}/$<CONFIG>/qtlogo.svg
)
else()
configure_file("${WASM_BUILD_DIR}/plugins/platforms/qtloader.js"
${_target_directory}/qtloader.js COPYONLY)
configure_file("${WASM_BUILD_DIR}/plugins/platforms/qtlogo.svg"
${_target_directory}/qtlogo.svg COPYONLY)
if(QT_FEATURE_shared)
set(TARGET_DIR "${_target_directory}")
set(SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(QT_HOST_DIR "${QT_HOST_PATH}")
set(QT_WASM_DIR "${WASM_BUILD_DIR}")
set(QT_INSTALL_DIR "${QT6_INSTALL_PREFIX}")
configure_file("${WASM_BUILD_DIR}/libexec/generate_default_preloads.sh.in"
"${_target_directory}/generate_default_preloads_for_${target}.sh" @ONLY)
endif()
endif()
endif()
endif()
if(QT_FEATURE_thread)
set(POOL_SIZE 4)
get_target_property(_tmp_poolSize "${target}" QT_WASM_PTHREAD_POOL_SIZE)
if(_tmp_poolSize)
set(POOL_SIZE ${_tmp_poolSize})
elseif(DEFINED QT_WASM_PTHREAD_POOL_SIZE)
set(POOL_SIZE ${QT_WASM_PTHREAD_POOL_SIZE})
endif()
target_link_options("${target}" PRIVATE "SHELL:-s PTHREAD_POOL_SIZE=${POOL_SIZE}")
message(DEBUG "Setting PTHREAD_POOL_SIZE to ${POOL_SIZE} for ${target}")
endif()
# Set initial memory size, either from user setting or to a minimum amount required by Qt.
get_target_property(_tmp_initialMemory "${target}" QT_WASM_INITIAL_MEMORY)
if(_tmp_initialMemory)
set(QT_WASM_INITIAL_MEMORY "${_tmp_initialMemory}")
elseif(NOT DEFINED QT_WASM_INITIAL_MEMORY)
set(QT_WASM_INITIAL_MEMORY "50MB")
endif()
target_link_options("${target}" PRIVATE "SHELL:-s INITIAL_MEMORY=${QT_WASM_INITIAL_MEMORY}")
# Set maximum memory size, either from user setting or to 4GB (the 32-bit maximum)
get_target_property(_tmp_maximumMemory "${target}" QT_WASM_MAXIMUM_MEMORY)
if(_tmp_maximumMemory)
set(QT_WASM_MAXIMUM_MEMORY "${_tmp_maximumMemory}")
elseif(NOT DEFINED QT_WASM_MAXIMUM_MEMORY)
if(QT_FEATURE_wasm_jspi)
# Work around Emscripten >2GB and JSPI compatibility issue.
set(QT_WASM_MAXIMUM_MEMORY "2GB")
else()
set(QT_WASM_MAXIMUM_MEMORY "4GB")
endif()
endif()
target_link_options("${target}" PRIVATE "SHELL:-s MAXIMUM_MEMORY=${QT_WASM_MAXIMUM_MEMORY}")
endif()
endfunction()
function(_qt_internal_add_wasm_extra_exported_methods target)
get_target_property(wasm_extra_exported_methods "${target}" QT_WASM_EXTRA_EXPORTED_METHODS)
set(wasm_default_exported_methods "UTF16ToString,stringToUTF16,JSEvents,specialHTMLTargets,FS,callMain")
if(NOT wasm_extra_exported_methods)
set(wasm_extra_exported_methods ${QT_WASM_EXTRA_EXPORTED_METHODS})
endif()
if(wasm_extra_exported_methods)
target_link_options("${target}" PRIVATE
"SHELL:-s EXPORTED_RUNTIME_METHODS=${wasm_default_exported_methods},${wasm_extra_exported_methods}"
)
else()
# an errant dangling comma will break this
target_link_options("${target}" PRIVATE
"SHELL:-s EXPORTED_RUNTIME_METHODS=${wasm_default_exported_methods}"
)
endif()
# TODO: Remove these flags when LLVM got fixed - QTBUG-131279
if(QT_FEATURE_thread)
target_link_options("${target}" PRIVATE
"SHELL:-s EXPORTED_FUNCTIONS=_main,__embind_initialize_bindings")
endif()
endfunction()
function(_qt_internal_set_wasm_export_name target)
_qt_internal_wasm_export_name_for_target(export_name ${target})
target_link_options("${target}" PRIVATE "SHELL:-s MODULARIZE=1")
target_link_options("${target}" PRIVATE "SHELL:-s EXPORT_NAME=${export_name}")
endfunction()
function(_qt_internal_wasm_export_name_for_target out target)
get_target_property(export_name "${target}" QT_WASM_EXPORT_NAME)
if(export_name)
set(${out} "${export_name}" PARENT_SCOPE)
else()
# Modify target name to remove characters which are not valid in
# JavaScript identifiers.
# Prefix leading digit with '_' (2dpaint -> _2dpaint)
if("${target}" MATCHES "^[0-9]")
set(targ "_${target}")
else()
set(targ "${target}")
endif()
# Replace remaining non-legal chars with '_' (target-foo -> target_foo)
string(REGEX REPLACE "[^a-zA-Z0-9_]" "_" targ "${targ}")
# Append "_entry" and return
set(${out} "${targ}_entry" PARENT_SCOPE)
endif()
endfunction()
function(_qt_internal_set_wasm_embind_option target)
target_link_libraries("${target}" PRIVATE embind)
endfunction()
function(_qt_internal_finalize_wasm_app target)
_qt_internal_set_wasm_export_name("${target}")
_qt_internal_add_wasm_extra_exported_methods("${target}")
_qt_internal_wasm_add_target_helpers("${target}")
_qt_internal_set_wasm_embind_option("${target}")
endfunction()