Revision control
++ # 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 builds preload the Qt plugin and qml manifests that wasmdeployqt
++ # generates. Apps add their own manifests through qt_add_wasm_preload,
++ # which are collected here.
++ set(_wasm_preload_files "")
++ if(QT_FEATURE_shared)
++ list(APPEND _wasm_preload_files "qt_plugins.json" "qt_qml_imports.json")
++ endif()
++
++ get_target_property(_app_preload_manifest "${target}" _qt_wasm_app_preload_manifest)
++ if(_app_preload_manifest)
++ list(APPEND _wasm_preload_files "${_app_preload_manifest}")
++ endif()
++
++ if(_wasm_preload_files)
++ set(_preload_js "")
++ foreach(_f IN LISTS _wasm_preload_files)
++ string(APPEND _preload_js "'${_f}', ")
++ endforeach()
++ set(PRELOAD "preload: [${_preload_js}],")
++ else()
++ set(PRELOAD "")
++ endif()
++
++ if(DEFINED QT_WASM_SOURCE_MAP_BASE)
++ set(WASM_SOURCE_MAP_BASE "${QT_WASM_SOURCE_MAP_BASE}")
++ target_link_options("${target}"
++ PRIVATE
++ "-gsource-map"
++ "--source-map-base"
++ "${WASM_SOURCE_MAP_BASE}")
++
++ 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" @ONLY)
++ 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}/$/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}/$/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)
++ endif()
++ endif()
++ endif()
++
++ # Convenience deploy target for shared MAIN_MODULE apps, so that
++ # cmake --build . --target <app>_deploy produces a runnable directory.
++ if(QT_FEATURE_shared AND NOT is_test AND QT_HOST_PATH)
++ if(target_output_directory)
++ set(_deploy_workdir "${target_output_directory}")
++ else()
++ set(_deploy_workdir "${CMAKE_CURRENT_BINARY_DIR}")
++ endif()
++ add_custom_target("${target}_deploy"
++ COMMAND "${QT_HOST_PATH}/bin/wasmdeployqt"
++ "$<TARGET_FILE_DIR:${target}>/$<TARGET_FILE_BASE_NAME:${target}>.wasm"
++ "--qt-wasm-dir=${WASM_BUILD_DIR}/bin"
++ "--qt-host-dir=${QT_HOST_PATH}/bin"
++ WORKING_DIRECTORY "${_deploy_workdir}"
++ DEPENDS "${target}"
++ VERBATIM)
++ 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)
++ if (QT_FEATURE_sanitize_address OR QT_FEATURE_sanitize_undefined)
++ set(QT_WASM_INITIAL_MEMORY "200MB")
++ else()
++ set(QT_WASM_INITIAL_MEMORY "50MB")
++ endif()
++ 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(WASM64)
++ set(QT_WASM_MAXIMUM_MEMORY "16GB")
++ 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,stringToNewUTF8,JSEvents,specialHTMLTargets,FS,SOCKFS,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()
++ 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()
++
++ # Declare files or side module targets to preload into the app's in-memory
++ # filesystem at startup. Each item is copied next to the app at build time and
++ # a manifest is generated and added to the app's qtLoad preload list.
++ # Preloading is one way to make app private plugins and other data that
++ # wasmdeployqt does not handle, available to the app, as an alternative to
++ # loading them on demand at runtime.
++ function(qt_add_wasm_preload target)
++ cmake_parse_arguments(arg "" "DESTINATION" "FILES;TARGETS" ${ARGN})
++ if(NOT arg_DESTINATION)
++ message(FATAL_ERROR "qt_add_wasm_preload requires a DESTINATION directory.")
++ endif()
++
++ get_target_property(_out_dir "${target}" RUNTIME_OUTPUT_DIRECTORY)
++ if(NOT _out_dir)
++ set(_out_dir "${CMAKE_CURRENT_BINARY_DIR}")
++ endif()
++ get_target_property(_out_name "${target}" OUTPUT_NAME)
++ if(NOT _out_name)
++ set(_out_name "${target}")
++ endif()
++
++ set(_entries "")
++
++ # Plain files are copied verbatim next to the app and preloaded from there.
++ foreach(_file IN LISTS arg_FILES)
++ get_filename_component(_base "${_file}" NAME)
++ add_custom_command(TARGET "${target}" POST_BUILD
++ COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${_file}" "${_out_dir}/${_base}")
++ string(APPEND _entries
++ " { \"source\": \"${_base}\", \"destination\": \"${arg_DESTINATION}/${_base}\" },\n")
++ endforeach()
++
++ # Side module targets are copied by their built file name.
++ foreach(_tgt IN LISTS arg_TARGETS)
++ add_custom_command(TARGET "${target}" POST_BUILD
++ COMMAND "${CMAKE_COMMAND}" -E copy_if_different
++ "$<TARGET_FILE:${_tgt}>" "${_out_dir}/$<TARGET_FILE_NAME:${_tgt}>")
++ string(APPEND _entries
++ " { \"source\": \"$<TARGET_FILE_NAME:${_tgt}>\", \"destination\": \"${arg_DESTINATION}/$<TARGET_FILE_NAME:${_tgt}>\" },\n")
++ endforeach()
++
++ # Drop the trailing comma so the generated array is valid JSON.
++ string(REGEX REPLACE ",\n$" "\n" _entries "${_entries}")
++
++ set(_manifest "${_out_name}_preload.json")
++ file(GENERATE OUTPUT "${_out_dir}/${_manifest}" CONTENT "[\n${_entries}]\n")
++
++ set_target_properties("${target}" PROPERTIES _qt_wasm_app_preload_manifest "${_manifest}")
++ endfunction()
++