wasm: add cmake build support

A few configure defines get changed:
QMAKE_WASM_PTHREAD_POOL_SIZE is now QT_WASM_PTHREAD_POOL_SIZE
QMAKE_WASM_TOTAL_MEMORY is now QT_WASM_INITIAL_MEMORY
QMAKE_WASM_SOURCE_MAP_BASE is now QT_WASM_SOURCE_MAP_BASE

device-option EMSCRIPTEN_ASYNCIFY=1 is QT_EMSCRIPTEN_ASYNCIFY=1

To create source maps for debugging. use
device-option QT_WASM_SOURCE_MAP=1

Task-number: QTBUG-78647
Change-Id: If9f30cd7fb408c386d6d69b5f7b1beecf1ab44b5
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
This commit is contained in:
Lorn Potter 2020-09-03 18:29:41 +10:00
parent 5bf4133c17
commit 4972fdb350
26 changed files with 370 additions and 42 deletions

View File

@ -341,7 +341,7 @@ qt_feature("android-style-assets" PRIVATE
) )
qt_feature("shared" PUBLIC qt_feature("shared" PUBLIC
LABEL "Building shared libraries" LABEL "Building shared libraries"
AUTODETECT NOT UIKIT AUTODETECT NOT UIKIT AND NOT WASM
CONDITION BUILD_SHARED_LIBS CONDITION BUILD_SHARED_LIBS
) )
qt_feature_definition("shared" "QT_STATIC" NEGATE PREREQUISITE "!defined(QT_SHARED) && !defined(QT_STATIC)") qt_feature_definition("shared" "QT_STATIC" NEGATE PREREQUISITE "!defined(QT_SHARED) && !defined(QT_STATIC)")
@ -837,7 +837,7 @@ qt_feature_definition("concurrent" "QT_NO_CONCURRENT" NEGATE VALUE "1")
qt_feature("dbus" PUBLIC PRIVATE qt_feature("dbus" PUBLIC PRIVATE
LABEL "Qt D-Bus" LABEL "Qt D-Bus"
AUTODETECT NOT UIKIT AND NOT ANDROID AUTODETECT NOT UIKIT AND NOT ANDROID
CONDITION QT_FEATURE_thread CONDITION QT_FEATURE_thread AND NOT WASM
) )
qt_feature_definition("dbus" "QT_NO_DBUS" NEGATE VALUE "1") qt_feature_definition("dbus" "QT_NO_DBUS" NEGATE VALUE "1")
qt_feature("dbus-linked" PRIVATE qt_feature("dbus-linked" PRIVATE
@ -866,7 +866,7 @@ qt_feature("printsupport" PRIVATE
) )
qt_feature("sql" PRIVATE qt_feature("sql" PRIVATE
LABEL "Qt Sql" LABEL "Qt Sql"
CONDITION QT_FEATURE_thread CONDITION QT_FEATURE_thread AND NOT WASM
) )
qt_feature("testlib" PRIVATE qt_feature("testlib" PRIVATE
LABEL "Qt Testlib" LABEL "Qt Testlib"
@ -1034,12 +1034,18 @@ qt_configure_add_summary_entry(ARGS "pkg-config")
qt_configure_add_summary_entry(ARGS "libudev") qt_configure_add_summary_entry(ARGS "libudev")
qt_configure_add_summary_entry(ARGS "system-zlib") qt_configure_add_summary_entry(ARGS "system-zlib")
qt_configure_add_summary_entry(ARGS "zstd") qt_configure_add_summary_entry(ARGS "zstd")
qt_configure_add_summary_entry(ARGS "thread")
qt_configure_end_summary_section() # end of "Support enabled for" section qt_configure_end_summary_section() # end of "Support enabled for" section
qt_configure_add_report_entry( qt_configure_add_report_entry(
TYPE NOTE TYPE NOTE
MESSAGE "Using static linking will disable the use of dynamically loaded plugins. Make sure to import all needed static plugins, or compile needed modules into the library." MESSAGE "Using static linking will disable the use of dynamically loaded plugins. Make sure to import all needed static plugins, or compile needed modules into the library."
CONDITION NOT QT_FEATURE_shared CONDITION NOT QT_FEATURE_shared
) )
qt_configure_add_report_entry(
TYPE NOTE
MESSAGE "Using pthreads"
CONDITION QT_FEATURE_thread
)
qt_configure_add_report_entry( qt_configure_add_report_entry(
TYPE ERROR TYPE ERROR
MESSAGE "Debug build wihtout Release build is not currently supported on ios see QTBUG-71990. Use -debug-and-release." MESSAGE "Debug build wihtout Release build is not currently supported on ios see QTBUG-71990. Use -debug-and-release."

View File

@ -94,6 +94,12 @@ if(NOT QT_BUILD_STANDALONE_TESTS)
# Needed when building qtbase for android. # Needed when building qtbase for android.
include(src/corelib/Qt6AndroidMacros.cmake) include(src/corelib/Qt6AndroidMacros.cmake)
if(WASM)
# Needed when building for WebAssembly.
include(cmake/QtWasmHelpers.cmake)
qt_internal_setup_wasm_target_properties(Platform)
endif()
# Set up optimization flags like in qmake. # Set up optimization flags like in qmake.
# This function must be called after the global QT_FEATURE_xxx variables have been set up, # This function must be called after the global QT_FEATURE_xxx variables have been set up,
# aka after QtBaseGlobalTargets is processed. # aka after QtBaseGlobalTargets is processed.

View File

@ -5,6 +5,64 @@
# Make sure to not run detection when building standalone tests, because the detection was already # Make sure to not run detection when building standalone tests, because the detection was already
# done when initially configuring qtbase. # done when initially configuring qtbase.
function(qt_auto_detect_wasm)
if("${QT_QMAKE_TARGET_MKSPEC}" STREQUAL "wasm-emscripten" AND DEFINED ENV{EMSDK})
if(NOT DEFINED QT_AUTODETECT_WASM)
set(QT_AUTODETECT_WASM TRUE CACHE BOOL "")
# detect EMSCRIPTEN_ROOT path
file(READ "$ENV{EMSDK}/.emscripten" ver)
string(REGEX MATCH "EMSCRIPTEN_ROOT.*$" EMROOT "${ver}")
string(REGEX MATCH "'([^' ]*)'" EMROOT2 "${EMROOT}")
string(REPLACE "'" "" EMROOT_PATH "${EMROOT2}")
# get emscripten version
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set (EXECUTE_COMMANDPATH "$ENV{EMSDK}/${EMROOT_PATH}/emcc.bat")
else()
set (EXECUTE_COMMANDPATH "$ENV{EMSDK}/${EMROOT_PATH}/emcc")
endif()
file(TO_NATIVE_PATH "${EXECUTE_COMMANDPATH}" EXECUTE_COMMAND)
execute_process(COMMAND ${EXECUTE_COMMAND} --version
OUTPUT_VARIABLE emOutput
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_VARIABLE emrun_error
RESULT_VARIABLE result)
if(NOT emOutput)
message(FATAL_ERROR
"Can't determine Emscripten version! Error: ${emrun_error}")
endif()
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" CMAKE_EMSDK_REGEX_VERSION "${emOutput}")
set(EMCC_VERSION "${CMAKE_EMSDK_REGEX_VERSION}" CACHE STRING INTERNAL FORCE)
# find toolchain file
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
set(wasm_toolchain_file "$ENV{EMSDK}/${EMROOT_PATH}/cmake/Modules/Platform/Emscripten.cmake")
set(CMAKE_TOOLCHAIN_FILE "${wasm_toolchain_file}" CACHE STRING "" FORCE)
endif()
if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
message(STATUS "Emscripten ${CMAKE_EMSDK_REGEX_VERSION} toolchain file detected at ${CMAKE_TOOLCHAIN_FILE}")
else()
message(FATAL_ERROR "Cannot find the toolchain file Emscripten.cmake. "
"Please specify the toolchain file with -DCMAKE_TOOLCHAIN_FILE=<file>.")
endif()
if(NOT DEFINED BUILD_SHARED_LIBS)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build Qt statically or dynamically" FORCE)
endif()
if(BUILD_SHARED_LIBS)
message(FATAL_ERROR
"Building Qt for ${CMAKE_SYSTEM_NAME} as shared libraries is not supported.")
endif()
# this version of Qt needs this version of emscripten
set(QT_EMCC_RECOMMENDED_VERSION 2.0.14 CACHE STRING INTERNAL FORCE)
endif()
endif()
endfunction()
function(qt_auto_detect_cmake_generator) function(qt_auto_detect_cmake_generator)
if(NOT CMAKE_GENERATOR MATCHES "Ninja" AND NOT QT_SILENCE_CMAKE_GENERATOR_WARNING) if(NOT CMAKE_GENERATOR MATCHES "Ninja" AND NOT QT_SILENCE_CMAKE_GENERATOR_WARNING)
message(WARNING message(WARNING
@ -340,3 +398,4 @@ qt_auto_detect_ios()
qt_auto_detect_android() qt_auto_detect_android()
qt_auto_detect_vpckg() qt_auto_detect_vpckg()
qt_auto_detect_pch() qt_auto_detect_pch()
qt_auto_detect_wasm()

View File

@ -32,7 +32,7 @@ function(qt_run_config_test_architecture)
# With emscripten the application entry point is a .js file (to be run with node for example), # With emscripten the application entry point is a .js file (to be run with node for example),
# but the real "data" is in the .wasm file, so that's where we need to look for the ABI, etc. # but the real "data" is in the .wasm file, so that's where we need to look for the ABI, etc.
# information. # information.
if (EMSCRIPTEN) if (WASM)
set(_arch_file_suffix ".wasm") set(_arch_file_suffix ".wasm")
endif() endif()

View File

@ -214,6 +214,7 @@ qt_copy_or_install(FILES
cmake/QtTestHelpers.cmake cmake/QtTestHelpers.cmake
cmake/QtToolchainHelpers.cmake cmake/QtToolchainHelpers.cmake
cmake/QtToolHelpers.cmake cmake/QtToolHelpers.cmake
cmake/QtWasmHelpers.cmake
cmake/QtWrapperScriptHelpers.cmake cmake/QtWrapperScriptHelpers.cmake
cmake/QtWriteArgsFile.cmake cmake/QtWriteArgsFile.cmake
DESTINATION "${__GlobalConfig_install_dir}" DESTINATION "${__GlobalConfig_install_dir}"

View File

@ -302,7 +302,7 @@ elseif(IOS)
set(QT_DEFAULT_MKSPEC macx-ios-clang) set(QT_DEFAULT_MKSPEC macx-ios-clang)
elseif(APPLE) elseif(APPLE)
set(QT_DEFAULT_MKSPEC macx-clang) set(QT_DEFAULT_MKSPEC macx-clang)
elseif(EMSCRIPTEN) elseif(WASM)
set(QT_DEFAULT_MKSPEC wasm-emscripten) set(QT_DEFAULT_MKSPEC wasm-emscripten)
elseif(QNX) elseif(QNX)
# Certain POSIX defines are not set if we don't compile with -std=gnuXX # Certain POSIX defines are not set if we don't compile with -std=gnuXX

View File

@ -120,7 +120,7 @@ function(qt_build_internals_disable_pkg_config_if_needed)
set(pkg_config_enabled ON) set(pkg_config_enabled ON)
qt_build_internals_find_pkg_config_executable() qt_build_internals_find_pkg_config_executable()
if(APPLE OR WIN32 OR QNX OR ANDROID OR (NOT PKG_CONFIG_EXECUTABLE)) if(APPLE OR WIN32 OR QNX OR ANDROID OR WASM OR (NOT PKG_CONFIG_EXECUTABLE))
set(pkg_config_enabled OFF) set(pkg_config_enabled OFF)
endif() endif()

View File

@ -136,7 +136,7 @@ endif()
# TODO: Missing mkspecs flags we don't handle below: win32-clang-g++, win32-clang-msvc, rtems-base # TODO: Missing mkspecs flags we don't handle below: win32-clang-g++, win32-clang-msvc, rtems-base
# #
# gcc and clang base # gcc and clang base
if(GCC OR CLANG) if(GCC OR CLANG AND NOT WASM)
set(QT_CFLAGS_OPTIMIZE "-O2") set(QT_CFLAGS_OPTIMIZE "-O2")
set(QT_CFLAGS_OPTIMIZE_FULL "-O3") set(QT_CFLAGS_OPTIMIZE_FULL "-O3")
set(QT_CFLAGS_OPTIMIZE_DEBUG "-Og") set(QT_CFLAGS_OPTIMIZE_DEBUG "-Og")
@ -187,3 +187,10 @@ if(ICC)
set(QT_CFLAGS_OPTIMIZE_SIZE "-Os") set(QT_CFLAGS_OPTIMIZE_SIZE "-Os")
endif() endif()
endif() endif()
if(WASM)
set(QT_CFLAGS_OPTIMIZE "-O2")
set(QT_CFLAGS_OPTIMIZE_FULL "-O3")
set(QT_CFLAGS_OPTIMIZE_SIZE "-Os")
set(QT_CFLAGS_OPTIMIZE_DEBUG "-g2")
endif()

View File

@ -33,6 +33,9 @@ function(qt_internal_add_executable name)
PROPERTY EXCLUDE_FROM_ALL "$<NOT:$<CONFIG:${QT_MULTI_CONFIG_FIRST_CONFIG}>>") PROPERTY EXCLUDE_FROM_ALL "$<NOT:$<CONFIG:${QT_MULTI_CONFIG_FIRST_CONFIG}>>")
endif() endif()
if(WASM)
qt6_wasm_add_target_helpers("${name}")
endif()
if (arg_VERSION) if (arg_VERSION)
if(arg_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+") if(arg_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+")
# nothing to do # nothing to do

View File

@ -88,7 +88,7 @@ function(qt_internal_apply_gc_binaries target visibility)
message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.") message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.")
endif() endif()
if ((GCC OR CLANG) AND NOT EMSCRIPTEN AND NOT UIKIT AND NOT MSVC) if ((GCC OR CLANG) AND NOT WASM AND NOT UIKIT AND NOT MSVC)
if(APPLE) if(APPLE)
set(gc_sections_flag "-Wl,-dead_strip") set(gc_sections_flag "-Wl,-dead_strip")
elseif(SOLARIS) elseif(SOLARIS)
@ -101,7 +101,7 @@ function(qt_internal_apply_gc_binaries target visibility)
target_link_options("${target}" ${visibility} "${gc_sections_flag}") target_link_options("${target}" ${visibility} "${gc_sections_flag}")
endif() endif()
if((GCC OR CLANG OR ICC) AND NOT EMSCRIPTEN AND NOT UIKIT AND NOT MSVC) if((GCC OR CLANG OR ICC) AND NOT WASM AND NOT UIKIT AND NOT MSVC)
set(split_sections_flags "-ffunction-sections" "-fdata-sections") set(split_sections_flags "-ffunction-sections" "-fdata-sections")
endif() endif()
if(split_sections_flags) if(split_sections_flags)

View File

@ -552,7 +552,9 @@ set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})")
PRIVATE_HEADER DESTINATION ${INSTALL_INCLUDEDIR}/${module_include_name}/${PROJECT_VERSION}/${module}/private PRIVATE_HEADER DESTINATION ${INSTALL_INCLUDEDIR}/${module_include_name}/${PROJECT_VERSION}/${module}/private
) )
qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${INSTALL_LIBDIR}" RELATIVE_RPATH) if(BUILD_SHARED_LIBS)
qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${INSTALL_LIBDIR}" RELATIVE_RPATH)
endif()
if (ANDROID AND NOT arg_HEADER_MODULE) if (ANDROID AND NOT arg_HEADER_MODULE)
# Record install library location so it can be accessed by # Record install library location so it can be accessed by

View File

@ -16,7 +16,7 @@ qt_set01(QNX CMAKE_SYSTEM_NAME STREQUAL "QNX") # FIXME: How to identify this?
qt_set01(OPENBSD CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") # FIXME: How to identify this? qt_set01(OPENBSD CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") # FIXME: How to identify this?
qt_set01(FREEBSD CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") # FIXME: How to identify this? qt_set01(FREEBSD CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") # FIXME: How to identify this?
qt_set01(NETBSD CMAKE_SYSTEM_NAME STREQUAL "NetBSD") # FIXME: How to identify this? qt_set01(NETBSD CMAKE_SYSTEM_NAME STREQUAL "NetBSD") # FIXME: How to identify this?
qt_set01(WASM CMAKE_SYSTEM_NAME STREQUAL "Emscripten") qt_set01(WASM CMAKE_SYSTEM_NAME STREQUAL "Emscripten" OR EMSCRIPTEN)
qt_set01(BSD APPLE OR OPENBSD OR FREEBSD OR NETBSD) qt_set01(BSD APPLE OR OPENBSD OR FREEBSD OR NETBSD)

View File

@ -338,7 +338,9 @@ function(qt_internal_add_plugin target)
NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}:: NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}::
DESTINATION "${config_install_dir}" DESTINATION "${config_install_dir}"
) )
qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${install_directory}" RELATIVE_RPATH) if(BUILD_SHARED_LIBS)
qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${install_directory}" RELATIVE_RPATH)
endif()
endif() endif()
if (NOT arg_ALLOW_UNDEFINED_SYMBOLS) if (NOT arg_ALLOW_UNDEFINED_SYMBOLS)

View File

@ -563,7 +563,6 @@ QT_PATCH_VERSION = ${PROJECT_VERSION_PATCH}
list(APPEND extra_statements "QT_LIBINFIX = ${QT_LIBINFIX}") list(APPEND extra_statements "QT_LIBINFIX = ${QT_LIBINFIX}")
endif() endif()
# TODO: Add QT_EMCC_VERSION when WASM is ported over.
if(APPLECLANG) if(APPLECLANG)
set(compiler_version_major_var_name "QT_APPLE_CLANG_MAJOR_VERSION") set(compiler_version_major_var_name "QT_APPLE_CLANG_MAJOR_VERSION")
set(compiler_version_minor_var_name "QT_APPLE_CLANG_MINOR_VERSION") set(compiler_version_minor_var_name "QT_APPLE_CLANG_MINOR_VERSION")
@ -603,6 +602,10 @@ QT_PATCH_VERSION = ${PROJECT_VERSION_PATCH}
list(APPEND extra_statements "QT_EDITION = Open Source") list(APPEND extra_statements "QT_EDITION = Open Source")
if(WASM)
list(APPEND extra_statements
"QT_EMCC_VERSION = ${EMCC_VERSION}")
endif()
if(extra_statements) if(extra_statements)
string(REPLACE ";" "\n" extra_statements "${extra_statements}") string(REPLACE ";" "\n" extra_statements "${extra_statements}")
string(APPEND content "\n${extra_statements}\n") string(APPEND content "\n${extra_statements}\n")

92
cmake/QtWasmHelpers.cmake Normal file
View File

@ -0,0 +1,92 @@
function (qt_internal_setup_wasm_target_properties wasmTarget)
target_link_options("${wasmTarget}" INTERFACE "SHELL:-s EXIT_RUNTIME=1"
"SHELL:-s ERROR_ON_UNDEFINED_SYMBOLS=1"
"SHELL:-s EXTRA_EXPORTED_RUNTIME_METHODS=[UTF16ToString,stringToUTF16]"
"SHELL:-s USE_WEBGL2=1"
"--bind"
"SHELL:-s FETCH=1")
# Hardcode wasm memory size. Emscripten does not currently support memory growth
# (ALLOW_MEMORY_GROWTH) in pthreads mode, and requires specifying the memory size
# at build time. Further, browsers limit the maximum initial memory size to 1GB.
# QT_WASM_INITIAL_MEMORY must be a multiple of 64KB (i.e. 65536)
if(NOT DEFINED QT_WASM_INITIAL_MEMORY AND QT_FEATURE_thread)
set(QT_WASM_INITIAL_MEMORY "1GB")
endif()
if(DEFINED QT_WASM_INITIAL_MEMORY)
target_link_options("${wasmTarget}" INTERFACE "SHELL:-s INITIAL_MEMORY=${QT_WASM_INITIAL_MEMORY}")
message("Setting INITIAL_MEMORY to ${QT_WASM_INITIAL_MEMORY}")
endif()
if (QT_FEATURE_opengles3)
target_link_options("${wasmTarget}" INTERFACE "SHELL:-s FULL_ES3=1")
target_link_options("${wasmTarget}" INTERFACE "SHELL:-s FULL_ES3=1"
"SHELL:-s MAX_WEBGL_VERSION=2"
"SHELL:-s WEBGL2_BACKWARDS_COMPATIBILITY_EMULATION=1")
else()
target_link_options("${wasmTarget}" INTERFACE "SHELL:-s FULL_ES2=1")
endif()
set(disable_exceptions_catching 1)
if (QT_FEATURE_exceptions)
set(disable_exceptions_catching 0)
endif()
target_link_options("${wasmTarget}" INTERFACE "SHELL:-s DISABLE_EXCEPTION_CATCHING=${disable_exceptions_catching}")
if (QT_FEATURE_thread)
target_compile_options("${wasmTarget}" INTERFACE "SHELL:-s USE_PTHREADS=1")
target_link_options("${wasmTarget}" INTERFACE "SHELL:-s USE_PTHREADS=1")
if(DEFINED QT_WASM_PTHREAD_POOL_SIZE)
target_link_options("${wasmTarget}" INTERFACE "SHELL:-s PTHREAD_POOL_SIZE=${QT_WASM_PTHREAD_POOL_SIZE}")
message("Setting PTHREAD_POOL_SIZE to ${QT_WASM_PTHREAD_POOL_SIZE}")
endif()
else()
target_link_options("${wasmTarget}" INTERFACE "SHELL:-s ALLOW_MEMORY_GROWTH=1")
endif()
# debug add_compile_options
if ("QT_WASM_SOURCE_MAP=1" IN_LIST QT_QMAKE_DEVICE_OPTIONS)
set(WASM_SOURCE_MAP_BASE "http://localhost:8000/")
if(DEFINED QT_WASM_SOURCE_MAP_BASE)
set(WASM_SOURCE_MAP_BASE "${QT_WASM_SOURCE_MAP_BASE}")
endif()
# Pass --source-map-base on the linker line. This informs the
# browser where to find the source files when debugging.
# -g4 to make source maps for debugging
target_link_options("${wasmTarget}" INTERFACE "-g4" "--source-map-base" "${WASM_SOURCE_MAP_BASE}")
endif()
# a few good defaults to make console more verbose while debugging
target_link_options("${wasmTarget}" INTERFACE $<$<CONFIG:Debug>:
SHELL:"-s DEMANGLE_SUPPORT=1"
SHELL:"-s GL_DEBUG=1"
SHELL:"-s ASSERTIONS=2"
--profiling-funcs>)
# target_link_options("${wasmTarget}" INTERFACE "SHELL:-s LIBRARY_DEBUG=1") # print out library calls, verbose
# target_link_options("${wasmTarget}" INTERFACE "SHELL:-s SYSCALL_DEBUG=1") # print out sys calls, verbose
# target_link_options("${wasmTarget}" INTERFACE "SHELL:-s FS_LOG=1") # print out filesystem ops, verbose
# target_link_options("${wasmTarget}" INTERFACE "SHELL:-s SOCKET_DEBUG") # print out socket,network data transfer
if ("QT_EMSCRIPTEN_ASYNCIFY=1" IN_LIST QT_QMAKE_DEVICE_OPTIONS)
# Emscripten recommends building with optimizations when using asyncify
# in order to reduce wasm file size, and may also generate broken wasm
# (with "wasm validation error: too many locals" type errors) if optimizations
# are omitted. Enable optimizations also for debug builds.
set(QT_CFLAGS_OPTIMIZE_DEBUG "-Os" CACHE STRING INTERNAL FORCE)
set(QT_FEATURE_optimize_debug ON CACHE BOOL INTERNAL FORCE)
target_link_options("${wasmTarget}" INTERFACE "SHELL:-s ASYNCIFY" "-Os")
target_compile_definitions("${wasmTarget}" INTERFACE QT_HAVE_EMSCRIPTEN_ASYNCIFY)
endif()
endfunction()

View File

@ -339,7 +339,7 @@ qt_feature("android-style-assets" PRIVATE
) )
qt_feature("shared" PUBLIC qt_feature("shared" PUBLIC
LABEL "Building shared libraries" LABEL "Building shared libraries"
AUTODETECT NOT UIKIT AUTODETECT NOT UIKIT AND NOT WASM
CONDITION BUILD_SHARED_LIBS CONDITION BUILD_SHARED_LIBS
) )
qt_feature_definition("shared" "QT_STATIC" NEGATE PREREQUISITE "!defined(QT_SHARED) && !defined(QT_STATIC)") qt_feature_definition("shared" "QT_STATIC" NEGATE PREREQUISITE "!defined(QT_SHARED) && !defined(QT_STATIC)")
@ -600,6 +600,7 @@ qt_feature("c11" PUBLIC
qt_feature("precompile_header" qt_feature("precompile_header"
LABEL "Using precompiled headers" LABEL "Using precompiled headers"
CONDITION BUILD_WITH_PCH CONDITION BUILD_WITH_PCH
AUTODETECT NOT WASM
) )
qt_feature_config("precompile_header" QMAKE_PRIVATE_CONFIG) qt_feature_config("precompile_header" QMAKE_PRIVATE_CONFIG)
set(__qt_ltcg_detected FALSE) set(__qt_ltcg_detected FALSE)
@ -848,7 +849,7 @@ qt_feature_definition("concurrent" "QT_NO_CONCURRENT" NEGATE VALUE "1")
qt_feature("dbus" PUBLIC PRIVATE qt_feature("dbus" PUBLIC PRIVATE
LABEL "Qt D-Bus" LABEL "Qt D-Bus"
AUTODETECT NOT UIKIT AND NOT ANDROID AUTODETECT NOT UIKIT AND NOT ANDROID
CONDITION QT_FEATURE_thread CONDITION QT_FEATURE_thread AND NOT WASM
) )
qt_feature_definition("dbus" "QT_NO_DBUS" NEGATE VALUE "1") qt_feature_definition("dbus" "QT_NO_DBUS" NEGATE VALUE "1")
qt_feature("dbus-linked" PRIVATE qt_feature("dbus-linked" PRIVATE
@ -877,7 +878,7 @@ qt_feature("printsupport" PRIVATE
) )
qt_feature("sql" PRIVATE qt_feature("sql" PRIVATE
LABEL "Qt Sql" LABEL "Qt Sql"
CONDITION QT_FEATURE_thread CONDITION QT_FEATURE_thread AND NOT WASM
) )
qt_feature("testlib" PRIVATE qt_feature("testlib" PRIVATE
LABEL "Qt Testlib" LABEL "Qt Testlib"
@ -1050,6 +1051,7 @@ qt_configure_add_summary_entry(ARGS "pkg-config")
qt_configure_add_summary_entry(ARGS "libudev") qt_configure_add_summary_entry(ARGS "libudev")
qt_configure_add_summary_entry(ARGS "system-zlib") qt_configure_add_summary_entry(ARGS "system-zlib")
qt_configure_add_summary_entry(ARGS "zstd") qt_configure_add_summary_entry(ARGS "zstd")
qt_configure_add_summary_entry(ARGS "thread")
qt_configure_end_summary_section() # end of "Support enabled for" section qt_configure_end_summary_section() # end of "Support enabled for" section
qt_configure_add_report_entry( qt_configure_add_report_entry(
TYPE NOTE TYPE NOTE
@ -1094,9 +1096,22 @@ qt_configure_add_report_entry(
MESSAGE "Setting a library infix is not supported for framework builds." MESSAGE "Setting a library infix is not supported for framework builds."
CONDITION QT_FEATURE_framework AND DEFINED QT_LIBINFIX CONDITION QT_FEATURE_framework AND DEFINED QT_LIBINFIX
) )
qt_configure_add_report_entry(
TYPE NOTE
MESSAGE "Using pthreads"
CONDITION QT_FEATURE_thread
)
qt_configure_add_report_entry(
TYPE WARNING
MESSAGE "You should use the recommended Wasm version ${QT_EMCC_RECOMMENDED_VERSION} with this Qt. You have ${EMCC_VERSION}."
CONDITION WASM AND NOT ${EMCC_VERSION} MATCHES ${QT_EMCC_RECOMMENDED_VERSION}
)
if(WASM)
qt_extra_definition("QT_EMCC_VERSION" "\"${EMCC_VERSION}\"" PUBLIC)
endif()
# special case end # special case end
qt_extra_definition("QT_VERSION_STR" "\"${PROJECT_VERSION}\"" PUBLIC) qt_extra_definition("QT_VERSION_STR" "\"${PROJECT_VERSION}\"" PUBLIC)
qt_extra_definition("QT_VERSION_MAJOR" ${PROJECT_VERSION_MAJOR} PUBLIC) qt_extra_definition("QT_VERSION_MAJOR" ${PROJECT_VERSION_MAJOR} PUBLIC)
qt_extra_definition("QT_VERSION_MINOR" ${PROJECT_VERSION_MINOR} PUBLIC) qt_extra_definition("QT_VERSION_MINOR" ${PROJECT_VERSION_MINOR} PUBLIC)
qt_extra_definition("QT_VERSION_PATCH" ${PROJECT_VERSION_PATCH} PUBLIC) qt_extra_definition("QT_VERSION_PATCH" ${PROJECT_VERSION_PATCH} PUBLIC)

View File

@ -677,7 +677,7 @@
}, },
"shared": { "shared": {
"label": "Building shared libraries", "label": "Building shared libraries",
"autoDetect": "!config.uikit", "autoDetect": "!config.uikit && !config.wasm",
"condition": "!config.integrity && !config.wasm && !config.rtems", "condition": "!config.integrity && !config.wasm && !config.rtems",
"output": [ "output": [
"shared", "shared",
@ -1010,6 +1010,7 @@
"precompile_header": { "precompile_header": {
"label": "Using precompiled headers", "label": "Using precompiled headers",
"condition": "tests.precompile_header", "condition": "tests.precompile_header",
"autodetect": "!config.wasm",
"output": [ "output": [
"privateConfig", "privateConfig",
{ "type": "varRemove", "negative": true, "name": "CONFIG", "value": "'precompile_header'" } { "type": "varRemove", "negative": true, "name": "CONFIG", "value": "'precompile_header'" }
@ -1337,7 +1338,7 @@
"dbus": { "dbus": {
"label": "Qt D-Bus", "label": "Qt D-Bus",
"autoDetect": "!config.uikit && !config.android", "autoDetect": "!config.uikit && !config.android",
"condition": "features.thread", "condition": "features.thread && !config.wasm",
"output": [ "privateFeature", "feature" ] "output": [ "privateFeature", "feature" ]
}, },
"dbus-linked": { "dbus-linked": {
@ -1378,7 +1379,7 @@
}, },
"sql": { "sql": {
"label": "Qt Sql", "label": "Qt Sql",
"condition": "features.thread", "condition": "features.thread && !config.wasm",
"output": [ "privateFeature" ] "output": [ "privateFeature" ]
}, },
"testlib": { "testlib": {
@ -1512,8 +1513,9 @@
"message": "Qt requires a compliant STL library." "message": "Qt requires a compliant STL library."
}, },
{ {
"type": "emccVersion", "type": "note",
"condition": "config.wasm" "condition": "features.thread",
"message": "Using pthreads"
}, },
{ {
"type": "error", "type": "error",
@ -1673,7 +1675,8 @@
"pkg-config", "pkg-config",
"libudev", "libudev",
"system-zlib", "system-zlib",
"zstd" "zstd",
"thread"
] ]
} }
] ]

View File

@ -13,8 +13,8 @@ exists($$QMAKE_QT_CONFIG) {
# Create worker threads at startup. This is supposed to be an optimization, # Create worker threads at startup. This is supposed to be an optimization,
# however exceeding the pool size has been obesverved to hang the application. # however exceeding the pool size has been obesverved to hang the application.
POOL_SIZE = 4 POOL_SIZE = 4
!isEmpty(QMAKE_WASM_PTHREAD_POOL_SIZE) { !isEmpty(QT_WASM_PTHREAD_POOL_SIZE) {
POOL_SIZE = $$QMAKE_WASM_PTHREAD_POOL_SIZE POOL_SIZE = $$QT_WASM_PTHREAD_POOL_SIZE
} }
message("Setting PTHREAD_POOL_SIZE to" $$POOL_SIZE) message("Setting PTHREAD_POOL_SIZE to" $$POOL_SIZE)
@ -23,18 +23,18 @@ exists($$QMAKE_QT_CONFIG) {
EMCC_THREAD_LFLAGS += -s ALLOW_MEMORY_GROWTH=1 EMCC_THREAD_LFLAGS += -s ALLOW_MEMORY_GROWTH=1
} }
qtConfig(thread) | !isEmpty(QMAKE_WASM_TOTAL_MEMORY) { qtConfig(thread) | !isEmpty(QT_WASM_INITIAL_MEMORY) {
# Hardcode wasm memory size. Emscripten does not currently support memory growth # Hardcode wasm memory size. Emscripten does not currently support memory growth
# (ALLOW_MEMORY_GROWTH) in pthreads mode, and requires specifying the memory size # (ALLOW_MEMORY_GROWTH) in pthreads mode, and requires specifying the memory size
# at build time. Further, browsers limit the maximum initial memory size to 1GB. # at build time. Further, browsers limit the maximum initial memory size to 1GB.
# QMAKE_WASM_TOTAL_MEMORY must be a multiple of 64KB # QT_WASM_INITIAL_MEMORY must be a multiple of 64KB
TOTAL_MEMORY = 1GB INITIAL_MEMORY = 1GB
!isEmpty(QMAKE_WASM_TOTAL_MEMORY) { !isEmpty(QT_WASM_INITIAL_MEMORY) {
TOTAL_MEMORY = $$QMAKE_WASM_TOTAL_MEMORY INITIAL_MEMORY = $$QT_WASM_INITIAL_MEMORY
} }
message("Setting TOTAL_MEMORY to" $$TOTAL_MEMORY) message("Setting INITIAL_MEMORY to" $$INITIAL_MEMORY)
EMCC_THREAD_LFLAGS += -s TOTAL_MEMORY=$$TOTAL_MEMORY EMCC_THREAD_LFLAGS += -s INITIAL_MEMORY=$$INITIAL_MEMORY
} }
QMAKE_LFLAGS += $$EMCC_THREAD_LFLAGS QMAKE_LFLAGS += $$EMCC_THREAD_LFLAGS
QMAKE_LFLAGS_DEBUG += $$EMCC_THREAD_LFLAGS QMAKE_LFLAGS_DEBUG += $$EMCC_THREAD_LFLAGS
@ -117,9 +117,9 @@ qtConfTest_emccVersion()
# Pass --source-map-base on the linker line. This informs the # Pass --source-map-base on the linker line. This informs the
# browser where to find the source files when debugging. # browser where to find the source files when debugging.
WASM_SOURCE_MAP_BASE = http://localhost:8000/ WASM_SOURCE_MAP_BASE = http://localhost:8000/
!isEmpty(QMAKE_WASM_SOURCE_MAP_BASE):\ !isEmpty(QT_WASM_SOURCE_MAP_BASE):\
WASM_SOURCE_MAP_BASE = $$QMAKE_WASM_SOURCE_MAP_BASE WASM_SOURCE_MAP_BASE = $$QT_WASM_SOURCE_MAP_BASE
CONFIG(debug): QMAKE_LFLAGS += --source-map-base $$WASM_SOURCE_MAP_BASE CONFIG(debug): QMAKE_LFLAGS += -g4 --source-map-base $$WASM_SOURCE_MAP_BASE
# Creates the stand-alone version of the library from bitcode # Creates the stand-alone version of the library from bitcode
!static:contains(TEMPLATE, .*lib): { !static:contains(TEMPLATE, .*lib): {

View File

@ -8,11 +8,11 @@ include(../common/clang.conf)
load(device_config) load(device_config)
load(emcc_ver) load(emcc_ver)
# Support enabling asyncify by configuring with "-device-option EMSCRIPTEN_ASYNCIFY=1" # Support enabling asyncify by configuring with "-device-option QT_EMSCRIPTEN_ASYNCIFY=1"
!isEmpty(EMSCRIPTEN_ASYNCIFY): { !isEmpty(QT_EMSCRIPTEN_ASYNCIFY): {
!equals(EMSCRIPTEN_ASYNCIFY, 1):!equals(EMSCRIPTEN_ASYNCIFY, 0): \ !equals(QT_EMSCRIPTEN_ASYNCIFY, 1):!equals(QT_EMSCRIPTEN_ASYNCIFY, 0): \
message(Error: The value for EMSCRIPTEN_ASYNCIFY must be 0 or 1) message(Error: The value for QT_EMSCRIPTEN_ASYNCIFY must be 0 or 1)
equals(EMSCRIPTEN_ASYNCIFY, 1): { equals(QT_EMSCRIPTEN_ASYNCIFY, 1): {
QMAKE_CFLAGS += -DQT_HAVE_EMSCRIPTEN_ASYNCIFY QMAKE_CFLAGS += -DQT_HAVE_EMSCRIPTEN_ASYNCIFY
QMAKE_CXXFLAGS += -DQT_HAVE_EMSCRIPTEN_ASYNCIFY QMAKE_CXXFLAGS += -DQT_HAVE_EMSCRIPTEN_ASYNCIFY
QMAKE_LFLAGS += -s ASYNCIFY QMAKE_LFLAGS += -s ASYNCIFY
@ -56,7 +56,7 @@ EMCC_COMMON_LFLAGS_DEBUG = \
-s GL_DEBUG=1 \ -s GL_DEBUG=1 \
--profiling-funcs --profiling-funcs
QMAKE_LFLAGS_DEBUG += -g4 QMAKE_LFLAGS_DEBUG += -g2
QMAKE_LFLAGS_RELEASE += -O2 QMAKE_LFLAGS_RELEASE += -O2
QMAKE_COMPILER += emscripten QMAKE_COMPILER += emscripten

View File

@ -20,6 +20,10 @@ if(ANDROID)
set(corelib_extra_cmake_files set(corelib_extra_cmake_files
"${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}AndroidMacros.cmake") "${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}AndroidMacros.cmake")
endif() endif()
if(WASM)
set(corelib_extra_cmake_files
"${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}WasmMacros.cmake")
endif()
# special case end # special case end
##################################################################### #####################################################################

View File

@ -47,3 +47,7 @@ set(_Qt6CTestMacros "${_Qt6CoreConfigDir}/Qt6CTestMacros.cmake")
if(ANDROID_PLATFORM) if(ANDROID_PLATFORM)
include("${CMAKE_CURRENT_LIST_DIR}/@QT_CMAKE_EXPORT_NAMESPACE@AndroidMacros.cmake") include("${CMAKE_CURRENT_LIST_DIR}/@QT_CMAKE_EXPORT_NAMESPACE@AndroidMacros.cmake")
endif() endif()
if(EMSCRIPTEN)
include("${CMAKE_CURRENT_LIST_DIR}/@QT_CMAKE_EXPORT_NAMESPACE@WasmMacros.cmake")
endif()

View File

@ -559,6 +559,9 @@ function(qt6_finalize_executable target)
qt6_android_generate_deployment_settings("${target}") qt6_android_generate_deployment_settings("${target}")
qt6_android_add_apk_target("${target}") qt6_android_add_apk_target("${target}")
endif() endif()
if(EMSCRIPTEN)
qt_wasm_add_target_helpers("${target}")
endif()
endfunction() endfunction()
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS) if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)

View File

@ -0,0 +1,31 @@
function(qt6_wasm_add_target_helpers target)
# copy in Qt HTML/JS launch files for apps
get_target_property(targetType "${target}" TYPE)
if("${targetType}" STREQUAL "EXECUTABLE")
set(APPNAME ${target})
if(QT6_INSTALL_PREFIX)
set(WASM_BUILD_DIR "${QT6_INSTALL_PREFIX}")
elseif(QT_BUILD_DIR)
set(WASM_BUILD_DIR "${QT_BUILD_DIR}")
endif()
configure_file("${WASM_BUILD_DIR}/plugins/platforms/wasm_shell.html"
"${target}.html")
configure_file("${WASM_BUILD_DIR}/plugins/platforms/qtloader.js"
qtloader.js COPYONLY)
configure_file("${WASM_BUILD_DIR}/plugins/platforms/qtlogo.svg"
qtlogo.svg COPYONLY)
endif()
endfunction()
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
function(qt_wasm_add_target_helpers)
if(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
qt6_wasm_add_target_helpers(${ARGV})
endif()
endfunction()
endif()

View File

@ -389,10 +389,19 @@ ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
") ")
# opengles3 # opengles3
# special case begin
if(WASM)
set(extra_compiler_options "-s FULL_ES3=1")
endif()
# special case end
qt_config_compile_test(opengles3 qt_config_compile_test(opengles3
LABEL "OpenGL ES 3.0" LABEL "OpenGL ES 3.0"
LIBRARIES LIBRARIES
GLESv2::GLESv2 GLESv2::GLESv2
# special case begin
COMPILE_OPTIONS ${extra_compiler_options}
# special case end
CODE CODE
"#ifdef __APPLE__ "#ifdef __APPLE__
# include <OpenGLES/ES3/gl.h> # include <OpenGLES/ES3/gl.h>

View File

@ -47,7 +47,7 @@ if(HAIKU)
# add_subdirectory(haiku) # special case TODO # add_subdirectory(haiku) # special case TODO
endif() endif()
if(WASM) if(WASM)
# add_subdirectory(wasm) # special case TODO add_subdirectory(wasm)
endif() endif()
if(QT_FEATURE_integrityfb) if(QT_FEATURE_integrityfb)
# add_subdirectory(integrity) # special case TODO # add_subdirectory(integrity) # special case TODO

View File

@ -0,0 +1,78 @@
# Generated from wasm.pro.
#####################################################################
## QWasmIntegrationPlugin Plugin:
#####################################################################
qt_internal_add_plugin(QWasmIntegrationPlugin
OUTPUT_NAME qwasm
DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES wasm # special case
TYPE platforms
STATIC
SOURCES
main.cpp
qwasmclipboard.cpp qwasmclipboard.h
qwasmcompositor.cpp qwasmcompositor.h
qwasmcursor.cpp qwasmcursor.h
qwasmeventdispatcher.cpp qwasmeventdispatcher.h
qwasmeventtranslator.cpp qwasmeventtranslator.h
qwasmfontdatabase.cpp qwasmfontdatabase.h
qwasmintegration.cpp qwasmintegration.h
qwasmoffscreensurface.cpp qwasmoffscreensurface.h
qwasmopenglcontext.cpp qwasmopenglcontext.h
qwasmscreen.cpp qwasmscreen.h
qwasmservices.cpp qwasmservices.h
qwasmstring.cpp qwasmstring.h
qwasmstylepixmaps_p.h
qwasmtheme.cpp qwasmtheme.h
qwasmwindow.cpp qwasmwindow.h
DEFINES
QT_EGL_NO_X11
QT_NO_FOREACH
PUBLIC_LIBRARIES
Qt::Core
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
)
# Resources:
set_source_files_properties("${QT_SOURCE_TREE}/src/3rdparty/wasm/Vera.ttf" PROPERTIES QT_RESOURCE_ALIAS "Vera.ttf")
set_source_files_properties("${QT_SOURCE_TREE}/src/3rdparty/wasm/DejaVuSans.ttf" PROPERTIES QT_RESOURCE_ALIAS "DejaVuSans.ttf")
set_source_files_properties("${QT_SOURCE_TREE}/src/3rdparty/wasm/DejaVuSansMono.ttf" PROPERTIES QT_RESOURCE_ALIAS "DejaVuSansMono.ttf")
set(wasmfonts_resource_files
"${QT_SOURCE_TREE}/src/3rdparty/wasm/Vera.ttf"
"${QT_SOURCE_TREE}/src/3rdparty/wasm/DejaVuSans.ttf"
"${QT_SOURCE_TREE}/src/3rdparty/wasm/DejaVuSansMono.ttf"
)
qt_internal_add_resource(QWasmIntegrationPlugin "wasmfonts"
PREFIX
"/fonts"
FILES
${wasmfonts_resource_files}
)
qt_internal_extend_target(QWasmIntegrationPlugin CONDITION QT_FEATURE_opengl
SOURCES
qwasmbackingstore.cpp qwasmbackingstore.h
PUBLIC_LIBRARIES
Qt::OpenGL
Qt::OpenGLPrivate
)
#### Keys ignored in scope 4:.:.:wasm.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
# PLUGIN_EXTENDS = "-"
qt_copy_or_install(FILES
wasm_shell.html
DESTINATION "${CMAKE_INSTALL_PREFIX}/plugins/platforms/"
)
qt_copy_or_install(FILES
qtloader.js
DESTINATION "${CMAKE_INSTALL_PREFIX}/plugins/platforms/"
)
qt_copy_or_install(FILES
qtlogo.svg
DESTINATION "${CMAKE_INSTALL_PREFIX}/plugins/platforms/"
)