diff --git a/.gitmodules b/.gitmodules index 29ca8821f8eb8..356447cbf7a98 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,4 +7,4 @@ [submodule "cmake/external/emsdk"] path = cmake/external/emsdk url = https://github.com/emscripten-core/emsdk.git - branch = 3.1.59 + branch = 4.0.3 diff --git a/cmake/external/emsdk b/cmake/external/emsdk index d52c465201248..127ce42cd5f0a 160000 --- a/cmake/external/emsdk +++ b/cmake/external/emsdk @@ -1 +1 @@ -Subproject commit d52c46520124845b1e0e0525f2759299d840143f +Subproject commit 127ce42cd5f0aabe2d9b5d636041ccef7c66d165 diff --git a/cmake/external/onnxruntime_external_deps.cmake b/cmake/external/onnxruntime_external_deps.cmake index 801d2292e0f74..2feff6475ebf7 100644 --- a/cmake/external/onnxruntime_external_deps.cmake +++ b/cmake/external/onnxruntime_external_deps.cmake @@ -510,7 +510,7 @@ else() message("Setting pybind11_dep") set(pybind11_dep pybind11::pybind11) endif() - + endif() onnxruntime_fetchcontent_declare( onnx @@ -559,7 +559,7 @@ if (onnxruntime_USE_XNNPACK) find_library(xnnpack_LIBRARY NAMES XNNPACK) find_library(microkernels_prod_LIBRARY NAMES microkernels-prod) find_package(unofficial-pthreadpool CONFIG REQUIRED) - + target_include_directories(xnnpack INTERFACE "${XNNPACK_HDR}") set(XNNPACK_INCLUDE_DIR ${XNNPACK_DIR}/include) set(onnxruntime_EXTERNAL_LIBRARIES_XNNPACK ${xnnpack_LIBRARY} ${microkernels_prod_LIBRARY} unofficial::pthreadpool unofficial::pthreadpool_interface) @@ -643,10 +643,12 @@ if (onnxruntime_USE_WEBGPU) dawn URL ${DEP_URL_dawn} URL_HASH SHA1=${DEP_SHA1_dawn} - # All previous patches are merged into the upstream dawn project. We don't need to apply any patches right now. - # if we need to apply patches in the future, we can uncomment the following line. - - # PATCH_COMMAND ${Patch_EXECUTABLE} --binary --ignore-whitespace -p1 < ${PROJECT_SOURCE_DIR}/patches/dawn/dawn.patch + # # All previous patches are merged into the upstream dawn project. We don't need to apply any patches right now. + # # if we need to apply patches in the future, we can uncomment the following line. + # + # The dawn.patch contains the following changes: + # - https://dawn-review.googlesource.com/c/dawn/+/225514 + PATCH_COMMAND ${Patch_EXECUTABLE} --binary --ignore-whitespace -p1 < ${PROJECT_SOURCE_DIR}/patches/dawn/dawn.patch EXCLUDE_FROM_ALL ) endif() @@ -657,20 +659,6 @@ if (onnxruntime_USE_WEBGPU) if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") set(DAWN_EMSCRIPTEN_TOOLCHAIN "${REPO_ROOT}/cmake/external/emsdk/upstream/emscripten" CACHE STRING "" FORCE) - - # Add the missing files from the emsdk installation - # - # For a "standard" emscripten build, the folder "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/maint/" is not used. This is the - # reason why EMSDK installation does not include it. - # However, currently the WebGPU support in Emscripten is still being developed and the Dawn project is maintaining - # a fork of the Emscripten toolchain. As an extra build step, Dawn needs to generate some files using the file - # "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/maint/gen_struct_info.py" from emscripten, which is missing in the emscripten - # installed by emsdk. - # - # We keep a copy of the missing file(s) in ${PROJECT_SOURCE_DIR}/patches/emscripten/, and now we extract them to the - # emscripten toolchain folder. - execute_process(COMMAND ${CMAKE_COMMAND} -E tar x "${PROJECT_SOURCE_DIR}/patches/emscripten/patch_3.1.74.tgz" - WORKING_DIRECTORY ${DAWN_EMSCRIPTEN_TOOLCHAIN}) else() if (onnxruntime_BUILD_DAWN_MONOLITHIC_LIBRARY) set(DAWN_BUILD_MONOLITHIC_LIBRARY ON CACHE BOOL "" FORCE) diff --git a/cmake/onnxruntime_webassembly.cmake b/cmake/onnxruntime_webassembly.cmake index 6cd05d1ad024b..2c4cdebcf450a 100644 --- a/cmake/onnxruntime_webassembly.cmake +++ b/cmake/onnxruntime_webassembly.cmake @@ -472,4 +472,59 @@ jsepDownload:_pp_") endif() set_target_properties(onnxruntime_webassembly PROPERTIES OUTPUT_NAME ${target_name} SUFFIX ".mjs") + + # + # The following POST_BUILD script is a workaround for enabling: + # - using onnxruntime-web with Multi-threading enabled when import from CDN + # - using onnxruntime-web when consumed in some frameworks like Vite + # + # In the use case mentioned above, the file name of the script may be changed. So we need to replace the line: + # `new Worker(new URL("ort-wasm-*.mjs", import.meta.url),` + # with + # `new Worker(new URL(import.meta.url),` + # + # This behavior is introduced in https://github.com/emscripten-core/emscripten/pull/22165. Since it's unlikely to be + # reverted, and there is no config to disable this behavior, we have to use a post-build script to workaround it. + # + + # Generate a script to do the post-build work + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/wasm_post_build.js " + const fs = require('fs'); + const path = require('path'); + + // node wasm_post_build.js + const mjsFilePath = process.argv[2]; + let contents = fs.readFileSync(mjsFilePath).toString(); + + const regex = 'new Worker\\\\(new URL\\\\(\".+?\", ?import\\\\.meta\\\\.url\\\\),'; + const matches = [...contents.matchAll(new RegExp(regex, 'g'))]; + if (matches.length !== 1) { + throw new Error( + `Unexpected number of matches for \"${regex}\" in \"${filepath}\": ${matches.length}.`, + ); + } + + // Replace the only occurrence. + contents = contents.replace( + new RegExp(regex), + `new Worker(new URL(import.meta.url),`, + ); + + fs.writeFileSync(mjsFilePath, contents); + " + ) + + find_program(NODE_EXECUTABLE node required) + if (NOT NODE_EXECUTABLE) + message(FATAL_ERROR "Node is required to run the post-build script") + endif() + + add_custom_command( + TARGET onnxruntime_webassembly + POST_BUILD + # Backup file at $.bak + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$.bak" + COMMAND ${CMAKE_COMMAND} -E echo "Performing post-process for $" + COMMAND ${NODE_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/wasm_post_build.js" "$" + ) endif() diff --git a/cmake/patches/dawn/dawn.patch b/cmake/patches/dawn/dawn.patch new file mode 100644 index 0000000000000..e7fd935cb9cb1 --- /dev/null +++ b/cmake/patches/dawn/dawn.patch @@ -0,0 +1,23 @@ +diff --git a/src/emdawnwebgpu/CMakeLists.txt b/src/emdawnwebgpu/CMakeLists.txt +index 6e8ae37593..633af91eef 100644 +--- a/src/emdawnwebgpu/CMakeLists.txt ++++ b/src/emdawnwebgpu/CMakeLists.txt +@@ -77,9 +77,17 @@ if (${DAWN_ENABLE_EMSCRIPTEN}) + "${arg_UNPARSED_ARGUMENTS}") + endif() + ++ # since Emscripten 4.0.3, file gen_struct_info.py is moved to outside of directory maint. ++ if (EXISTS "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/gen_struct_info.py") ++ set(EM_GEN_STRUCT_INFO_SCRIPT "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/gen_struct_info.py") ++ elseif (EXISTS "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/maint/gen_struct_info.py") ++ set(EM_GEN_STRUCT_INFO_SCRIPT "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/maint/gen_struct_info.py") ++ else() ++ message(FATAL_ERROR "Dawn: Failed to locate file gen_struct_info.py from Emscripten.") ++ endif() + set(ARGS + ${Python3_EXECUTABLE} +- "${DAWN_EMSCRIPTEN_TOOLCHAIN}/tools/maint/gen_struct_info.py" ++ "${EM_GEN_STRUCT_INFO_SCRIPT}" + -q + "${EM_BUILD_GEN_DIR}/struct_info_webgpu.json" + "-I=${EM_BUILD_GEN_DIR}/include" diff --git a/cmake/patches/emscripten/patch_3.1.74.tgz b/cmake/patches/emscripten/patch_3.1.74.tgz deleted file mode 100644 index cfb52de638653..0000000000000 Binary files a/cmake/patches/emscripten/patch_3.1.74.tgz and /dev/null differ diff --git a/tools/ci_build/build.py b/tools/ci_build/build.py index 36de85ea2ebdb..c234a69a73ed8 100644 --- a/tools/ci_build/build.py +++ b/tools/ci_build/build.py @@ -488,7 +488,7 @@ def convert_arg_line_to_args(self, arg_line): # WebAssembly build parser.add_argument("--build_wasm", action="store_true", help="Build for WebAssembly") parser.add_argument("--build_wasm_static_lib", action="store_true", help="Build for WebAssembly static library") - parser.add_argument("--emsdk_version", default="3.1.59", help="Specify version of emsdk") + parser.add_argument("--emsdk_version", default="4.0.3", help="Specify version of emsdk") parser.add_argument("--enable_wasm_simd", action="store_true", help="Enable WebAssembly SIMD") parser.add_argument("--enable_wasm_threads", action="store_true", help="Enable WebAssembly multi-threads support") diff --git a/tools/ci_build/github/azure-pipelines/templates/linux-wasm-ci.yml b/tools/ci_build/github/azure-pipelines/templates/linux-wasm-ci.yml index c0bc9605212b9..44d7d2482b141 100644 --- a/tools/ci_build/github/azure-pipelines/templates/linux-wasm-ci.yml +++ b/tools/ci_build/github/azure-pipelines/templates/linux-wasm-ci.yml @@ -45,7 +45,7 @@ jobs: name: ${{ parameters.PoolName }} variables: buildArch: x64 - CommonBuildArgs: '--parallel --config ${{ parameters.BuildConfig }} --skip_submodule_sync --build_wasm --enable_wasm_simd --enable_wasm_threads --use_extensions --cmake_extra_defines onnxruntime_WEBASSEMBLY_DEFAULT_EXTENSION_FLAGS=ON ${{ parameters.ExtraBuildArgs }}' + CommonBuildArgs: '--parallel --config ${{ parameters.BuildConfig }} --skip_submodule_sync --build_wasm --enable_wasm_simd --enable_wasm_threads ${{ parameters.ExtraBuildArgs }}' runCodesignValidationInjection: false TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] ORT_CACHE_DIR: $(Agent.TempDirectory)/ort_ccache @@ -82,15 +82,15 @@ jobs: - script: | set -ex cd '$(Build.SourcesDirectory)/cmake/external/emsdk' - ./emsdk install 3.1.59 ccache-git-emscripten-64bit - ./emsdk activate 3.1.59 ccache-git-emscripten-64bit + ./emsdk install 4.0.3 ccache-git-emscripten-64bit + ./emsdk activate 4.0.3 ccache-git-emscripten-64bit displayName: 'emsdk install and activate ccache for emscripten' - ${{if eq(parameters.WithCache, false)}}: - script: | set -ex cd '$(Build.SourcesDirectory)/cmake/external/emsdk' - ./emsdk install 3.1.59 - ./emsdk activate 3.1.59 + ./emsdk install 4.0.3 + ./emsdk activate 4.0.3 displayName: 'emsdk install and activate ccache for emscripten' - template: build-linux-wasm-step.yml