From 476ee7ee91db1dabaea0b74f775419cf8d0f814a Mon Sep 17 00:00:00 2001 From: Yulong Wang <7679871+fs-eire@users.noreply.github.com> Date: Wed, 24 Jan 2024 22:22:42 -0800 Subject: [PATCH] w --- cmake/CMakeLists.txt | 1 + cmake/adjust_global_compile_flags.cmake | 6 +++ .../external/onnxruntime_external_deps.cmake | 6 +++ cmake/onnxruntime_unittests.cmake | 15 ++----- cmake/onnxruntime_webassembly.cmake | 13 ++++-- cmake/patches/googletest/googletest.patch | 17 +++++++ js/build_jsep.bat | 2 + tools/ci_build/build.py | 44 ++++++++++++++----- .../templates/linux-wasm-ci.yml | 11 +++-- .../azure-pipelines/templates/web-ci.yml | 4 +- 10 files changed, 89 insertions(+), 30 deletions(-) create mode 100644 cmake/patches/googletest/googletest.patch diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 0eb224623f678..f0df5be2518cb 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -191,6 +191,7 @@ option(onnxruntime_USE_MPI "Build with MPI support" OFF) # WebAssembly options option(onnxruntime_BUILD_WEBASSEMBLY_STATIC_LIB "Enable this option to create WebAssembly static library" OFF) option(onnxruntime_ENABLE_WEBASSEMBLY_THREADS "Enable this option to create WebAssembly byte codes with multi-threads support" OFF) +option(onnxruntime_ENABLE_WEBASSEMBLY_NATIVE_EXCEPTION_HANDLING "Enable this option to turn on native exception handling" OFF) option(onnxruntime_ENABLE_WEBASSEMBLY_EXCEPTION_CATCHING "Enable this option to turn on exception catching" OFF) option(onnxruntime_ENABLE_WEBASSEMBLY_API_EXCEPTION_CATCHING "Enable this option to turn on api exception catching" OFF) option(onnxruntime_ENABLE_WEBASSEMBLY_EXCEPTION_THROWING "Enable this option to turn on exception throwing even if the build disabled exceptions support" OFF) diff --git a/cmake/adjust_global_compile_flags.cmake b/cmake/adjust_global_compile_flags.cmake index 2c7bf9f1c2f5c..468416ac37f36 100644 --- a/cmake/adjust_global_compile_flags.cmake +++ b/cmake/adjust_global_compile_flags.cmake @@ -42,6 +42,12 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") string(APPEND CMAKE_CXX_FLAGS " -msimd128") endif() + if (onnxruntime_ENABLE_WEBASSEMBLY_NATIVE_EXCEPTION_HANDLING AND NOT onnxruntime_DISABLE_EXCEPTIONS) + # use webassembly exception handling + string(APPEND CMAKE_C_FLAGS " -fwasm-exceptions") + string(APPEND CMAKE_CXX_FLAGS " -fwasm-exceptions") + endif() + if (onnxruntime_ENABLE_WEBASSEMBLY_EXCEPTION_CATCHING) string(APPEND CMAKE_C_FLAGS " -s DISABLE_EXCEPTION_CATCHING=0") string(APPEND CMAKE_CXX_FLAGS " -s DISABLE_EXCEPTION_CATCHING=0") diff --git a/cmake/external/onnxruntime_external_deps.cmake b/cmake/external/onnxruntime_external_deps.cmake index 403b4b2c4107a..dfeedf24e7de8 100644 --- a/cmake/external/onnxruntime_external_deps.cmake +++ b/cmake/external/onnxruntime_external_deps.cmake @@ -44,10 +44,16 @@ if (onnxruntime_BUILD_UNIT_TESTS) set(GTEST_HAS_ABSL ON CACHE BOOL "" FORCE) endif() # gtest and gmock + if(onnxruntime_ENABLE_WEBASSEMBLY_NATIVE_EXCEPTION_HANDLING AND Patch_FOUND) + set(ONNXRUNTIME_GTEST_PATCH_COMMAND ${Patch_EXECUTABLE} --binary --ignore-whitespace -p1 < ${PROJECT_SOURCE_DIR}/patches/googletest/googletest.patch) + else() + set(ONNXRUNTIME_GTEST_PATCH_COMMAND "") + endif() FetchContent_Declare( googletest URL ${DEP_URL_googletest} URL_HASH SHA1=${DEP_SHA1_googletest} + PATCH_COMMAND ${ONNXRUNTIME_GTEST_PATCH_COMMAND} FIND_PACKAGE_ARGS 1.14.0...<2.0.0 NAMES GTest ) endif() diff --git a/cmake/onnxruntime_unittests.cmake b/cmake/onnxruntime_unittests.cmake index 0987d6d164dbd..f49f6d1f1e370 100644 --- a/cmake/onnxruntime_unittests.cmake +++ b/cmake/onnxruntime_unittests.cmake @@ -201,18 +201,8 @@ function(AddTest) list(APPEND TEST_NODE_FLAGS "--experimental-wasm-simd") endif() - # prefer Node from emsdk so the version is more deterministic - if (DEFINED ENV{EMSDK_NODE}) - set(NODE_EXECUTABLE $ENV{EMSDK_NODE}) - else() - # warning as we don't know what node version is being used and whether things like the TEST_NODE_FLAGS - # will be valid. e.g. "--experimental-wasm-simd" is not valid with node v20 or later. - message(WARNING "EMSDK_NODE environment variable was not set. Falling back to system `node`.") - set(NODE_EXECUTABLE node) - endif() - add_test(NAME ${_UT_TARGET} - COMMAND ${NODE_EXECUTABLE} ${TEST_NODE_FLAGS} ${_UT_TARGET}.js ${TEST_ARGS} + COMMAND node ${TEST_NODE_FLAGS} ${_UT_TARGET}.js ${TEST_ARGS} WORKING_DIRECTORY $ ) endif() @@ -907,6 +897,9 @@ endif() if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") set_target_properties(onnxruntime_test_all PROPERTIES LINK_DEPENDS ${TEST_SRC_DIR}/wasm/onnxruntime_test_all_adapter.js) set_target_properties(onnxruntime_test_all PROPERTIES LINK_FLAGS "-s STACK_SIZE=5242880 -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4294967296 -s INCOMING_MODULE_JS_API=[preRun,locateFile,arguments,onExit,wasmMemory,buffer,instantiateWasm] --pre-js \"${TEST_SRC_DIR}/wasm/onnxruntime_test_all_adapter.js\" -s \"EXPORTED_RUNTIME_METHODS=['FS']\" --preload-file ${CMAKE_CURRENT_BINARY_DIR}/testdata@/testdata -s EXIT_RUNTIME=1 -s DEMANGLE_SUPPORT=1") + if (onnxruntime_ENABLE_WEBASSEMBLY_NATIVE_EXCEPTION_HANDLING AND NOT onnxruntime_DISABLE_EXCEPTIONS) + set_property(TARGET onnxruntime_test_all APPEND_STRING PROPERTY LINK_FLAGS " -fwasm-exceptions") + endif() if (onnxruntime_ENABLE_WEBASSEMBLY_THREADS) set_property(TARGET onnxruntime_test_all APPEND_STRING PROPERTY LINK_FLAGS " -s DEFAULT_PTHREAD_STACK_SIZE=131072 -s PROXY_TO_PTHREAD=1") endif() diff --git a/cmake/onnxruntime_webassembly.cmake b/cmake/onnxruntime_webassembly.cmake index 546d50c1ca2d3..f33309243421c 100644 --- a/cmake/onnxruntime_webassembly.cmake +++ b/cmake/onnxruntime_webassembly.cmake @@ -162,6 +162,11 @@ else() ${onnxruntime_webassembly_src} ) + + if (onnxruntime_ENABLE_WEBASSEMBLY_NATIVE_EXCEPTION_HANDLING AND NOT onnxruntime_DISABLE_EXCEPTIONS) + target_link_options(onnxruntime_webassembly PRIVATE "-fwasm-exceptions") + endif() + if (onnxruntime_ENABLE_WEBASSEMBLY_API_EXCEPTION_CATCHING) # we catch exceptions at the api level file(GLOB_RECURSE onnxruntime_webassembly_src_exc CONFIGURE_DEPENDS @@ -171,6 +176,7 @@ else() set (WASM_API_EXCEPTION_CATCHING "-s DISABLE_EXCEPTION_CATCHING=0") message(STATUS "onnxruntime_ENABLE_WEBASSEMBLY_EXCEPTION_CATCHING_ON_API set") set_source_files_properties(${onnxruntime_webassembly_src_exc} PROPERTIES COMPILE_FLAGS ${WASM_API_EXCEPTION_CATCHING}) + target_link_options(onnxruntime_webassembly PRIVATE "SHELL:${WASM_API_EXCEPTION_CATCHING}") endif() target_link_libraries(onnxruntime_webassembly PRIVATE @@ -226,7 +232,6 @@ else() "SHELL:-s VERBOSE=0" "SHELL:-s FILESYSTEM=0" "SHELL:-s INCOMING_MODULE_JS_API=[preRun,locateFile,arguments,onExit,wasmMemory,buffer,instantiateWasm,mainScriptUrlOrBlob]" - ${WASM_API_EXCEPTION_CATCHING} --no-entry ) @@ -274,8 +279,10 @@ else() endif() endif() - # Set link flag to enable exceptions support, this will override default disabling exception throwing behavior when disable exceptions. - target_link_options(onnxruntime_webassembly PRIVATE "SHELL:-s DISABLE_EXCEPTION_THROWING=0") + if (NOT onnxruntime_ENABLE_WEBASSEMBLY_NATIVE_EXCEPTION_HANDLING) + # Set link flag to enable exceptions support, this will override default disabling exception throwing behavior when disable exceptions. + target_link_options(onnxruntime_webassembly PRIVATE "SHELL:-s DISABLE_EXCEPTION_THROWING=0") + endif() if (onnxruntime_ENABLE_WEBASSEMBLY_PROFILING) target_link_options(onnxruntime_webassembly PRIVATE --profiling --profiling-funcs) diff --git a/cmake/patches/googletest/googletest.patch b/cmake/patches/googletest/googletest.patch new file mode 100644 index 0000000000000..ec9fc8af88d6c --- /dev/null +++ b/cmake/patches/googletest/googletest.patch @@ -0,0 +1,17 @@ +diff --git a/googletest/cmake/internal_utils.cmake b/googletest/cmake/internal_utils.cmake +index 580ac1cb..c2490d9f 100644 +--- a/googletest/cmake/internal_utils.cmake ++++ b/googletest/cmake/internal_utils.cmake +@@ -92,7 +92,11 @@ macro(config_compiler_and_linker) + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR + CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") + set(cxx_base_flags "-Wall -Wshadow -Wconversion -Wundef") +- set(cxx_exception_flags "-fexceptions") ++ if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") ++ set(cxx_exception_flags "-fwasm-exceptions") ++ else() ++ set(cxx_exception_flags "-fexceptions") ++ endif() + set(cxx_no_exception_flags "-fno-exceptions") + set(cxx_strict_flags "-W -Wpointer-arith -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch -Wunused-parameter -Wcast-align -Winline -Wredundant-decls") + set(cxx_no_rtti_flags "-fno-rtti") diff --git a/js/build_jsep.bat b/js/build_jsep.bat index acd40ff920774..5dbac70343214 100644 --- a/js/build_jsep.bat +++ b/js/build_jsep.bat @@ -10,6 +10,8 @@ rem config Build configuration, "d" or "r" rem threaded Build with threading support, "st" or "mt" rem clean Perform a clean build, "clean" or empty +rem build --build_wasm --enable_wasm_simd --config Release --use_extensions --cmake_extra_defines onnxruntime_WEBASSEMBLY_DEFAULT_EXTENSION_FLAGS=ON + setlocal enabledelayedexpansion set ROOT=%~dp0..\ diff --git a/tools/ci_build/build.py b/tools/ci_build/build.py index 186bb699ad209..0bc1f48249790 100644 --- a/tools/ci_build/build.py +++ b/tools/ci_build/build.py @@ -470,6 +470,14 @@ def convert_arg_line_to_args(self, arg_line): help="Enable exception throwing in WebAssembly, this will override default disabling exception throwing " "behavior when disable exceptions.", ) + parser.add_argument( + "--enable_wasm_native_eh", + action="store_true", + help="Enable native exception handling in WebAssembly, this will use compiler flag \"-fwasm-exceptions\" " + "instead of \"-fexceptions\". See " + "https://emscripten.org/docs/porting/exceptions.html#webassembly-exception-handling-based-support for more" + "information.", + ) parser.add_argument("--wasm_run_tests_in_browser", action="store_true", help="Run WebAssembly tests in browser") parser.add_argument( @@ -767,12 +775,29 @@ def convert_arg_line_to_args(self, arg_line): if args.android_ndk_path: args.android_ndk_path = os.path.normpath(args.android_ndk_path) - if args.enable_wasm_api_exception_catching: - # if we catch on api level, we don't want to catch all - args.disable_wasm_exception_catching = True - if not args.disable_wasm_exception_catching or args.enable_wasm_api_exception_catching: - # doesn't make sense to catch if no one throws - args.enable_wasm_exception_throwing_override = True + if args.enable_wasm_native_eh: + if args.enable_wasm_exception_throwing_override: + raise BuildError( + "Cannot specify both 'enable_wasm_native_eh' and 'enable_wasm_exception_throwing_override'. " + "The Emscripten(JS) exception handling is not compatible with the native exception handling." + ) + if args.disable_wasm_exception_catching: + raise BuildError( + "Cannot specify both 'enable_wasm_native_eh' and 'disable_wasm_exception_catching'. " + "The Emscripten(JS) exception handling is not compatible with the native exception handling." + ) + if args.enable_wasm_api_exception_catching: + raise BuildError( + "Cannot specify both 'enable_wasm_native_eh' and 'enable_wasm_api_exception_catching'. " + "The Emscripten(JS) exception handling is not compatible with the native exception handling." + ) + else: + if args.enable_wasm_api_exception_catching: + # if we catch on api level, we don't want to catch all + args.disable_wasm_exception_catching = True + if not args.disable_wasm_exception_catching or args.enable_wasm_api_exception_catching: + # doesn't make sense to catch if no one throws + args.enable_wasm_exception_throwing_override = True if args.cmake_generator is None and is_windows(): args.cmake_generator = "Ninja" if args.build_wasm else "Visual Studio 17 2022" @@ -1071,6 +1096,8 @@ def generate_build_tree( "-Donnxruntime_ENABLE_CUDA_LINE_NUMBER_INFO=" + ("ON" if args.enable_cuda_line_info else "OFF"), "-Donnxruntime_USE_CUDA_NHWC_OPS=" + ("ON" if args.enable_cuda_nhwc_ops else "OFF"), "-Donnxruntime_BUILD_WEBASSEMBLY_STATIC_LIB=" + ("ON" if args.build_wasm_static_lib else "OFF"), + "-Donnxruntime_ENABLE_WEBASSEMBLY_NATIVE_EXCEPTION_HANDLING=" + + ("ON" if args.enable_wasm_native_eh else "OFF"), "-Donnxruntime_ENABLE_WEBASSEMBLY_EXCEPTION_CATCHING=" + ("OFF" if args.disable_wasm_exception_catching else "ON"), "-Donnxruntime_ENABLE_WEBASSEMBLY_API_EXCEPTION_CATCHING=" @@ -2549,11 +2576,6 @@ def main(): args.build_wasm = True if args.build_wasm: - if not args.disable_wasm_exception_catching and args.disable_exceptions: - # When '--disable_exceptions' is set, we set '--disable_wasm_exception_catching' as well - args.disable_wasm_exception_catching = True - if args.test and args.disable_wasm_exception_catching and not args.minimal_build: - raise BuildError("WebAssembly tests need exception catching enabled to run if it's not minimal build") if args.test and args.enable_wasm_debug_info: # With flag --enable_wasm_debug_info, onnxruntime_test_all.wasm will be very huge (>1GB). This will fail # Node.js when trying to load the .wasm file. 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 360e3d5ef879b..8456ee42d2190 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,9 @@ jobs: name: ${{ parameters.PoolName }} variables: buildArch: x64 - CommonBuildArgs: '--parallel --config ${{ parameters.BuildConfig }} --skip_submodule_sync --build_wasm ${{ parameters.ExtraBuildArgs }}' + CommonBuildArgs: '--parallel --config ${{ parameters.BuildConfig }} --skip_submodule_sync --build_wasm --use_extensions --cmake_extra_defines onnxruntime_WEBASSEMBLY_DEFAULT_EXTENSION_FLAGS=ON ${{ parameters.ExtraBuildArgs }}' + NonJsepBuildArgs: '--use_webnn --target onnxruntime_webassembly --skip_tests' + JsepBuildArgs: '--use_jsep --use_webnn --target onnxruntime_webassembly --skip_tests' runCodesignValidationInjection: false TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] ORT_CACHE_DIR: $(Agent.TempDirectory)/ort_ccache @@ -80,6 +82,9 @@ jobs: versionSpec: '3.8' addToPath: true architecture: $(buildArch) + - task: NodeTool@0 + inputs: + versionSpec: '18.x' - template: download-deps.yml - task: PythonScript@0 @@ -174,7 +179,7 @@ jobs: ${{ else }}: AdditionalKey: wasm_simd_jsep | ${{ parameters.BuildConfig }} CacheDir: $(ORT_CACHE_DIR)/wasm_simd_jsep - Arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)/wasm_simd_jsep --enable_wasm_simd --use_jsep --use_webnn --target onnxruntime_webassembly --skip_tests' + Arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)/wasm_simd_jsep --enable_wasm_simd $(JsepBuildArgs)' DisplayName: 'Build (simd + JSEP)' WithCache: ${{ parameters.WithCache }} - template: build-linux-wasm-step.yml @@ -185,7 +190,7 @@ jobs: ${{ else }}: AdditionalKey: wasm_simd_threads_jsep | ${{ parameters.BuildConfig }} CacheDir: $(ORT_CACHE_DIR)/wasm_simd_threads_jsep - Arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)/wasm_simd_threads_jsep --enable_wasm_simd --enable_wasm_threads --use_jsep --use_webnn --target onnxruntime_webassembly --skip_tests' + Arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)/wasm_simd_threads_jsep --enable_wasm_simd --enable_wasm_threads $(JsepBuildArgs)' DisplayName: 'Build (simd + threads + JSEP)' WithCache: ${{ parameters.WithCache }} diff --git a/tools/ci_build/github/azure-pipelines/templates/web-ci.yml b/tools/ci_build/github/azure-pipelines/templates/web-ci.yml index 9982b36509b68..e76e2a6eec3b6 100644 --- a/tools/ci_build/github/azure-pipelines/templates/web-ci.yml +++ b/tools/ci_build/github/azure-pipelines/templates/web-ci.yml @@ -95,7 +95,7 @@ stages: parameters: CommitOverride: true BuildConfig: 'Debug' - ExtraBuildArgs: '--use_extensions --cmake_extra_defines onnxruntime_WEBASSEMBLY_DEFAULT_EXTENSION_FLAGS=ON ${{ parameters.ExtraBuildArgs }}' + ExtraBuildArgs: '${{ parameters.ExtraBuildArgs }}' PoolName: ${{ parameters.PoolName }} BuildJsep: ${{ parameters.BuildJsep }} WithCache: ${{ parameters.WithCache }} @@ -125,7 +125,7 @@ stages: parameters: CommitOverride: true BuildConfig: 'Release' - ExtraBuildArgs: '--target onnxruntime_webassembly --skip_tests --enable_wasm_api_exception_catching --disable_rtti --use_extensions --cmake_extra_defines onnxruntime_WEBASSEMBLY_DEFAULT_EXTENSION_FLAGS=ON ${{ parameters.ExtraBuildArgs }}' + ExtraBuildArgs: '--disable_rtti ${{ parameters.ExtraBuildArgs }}' PoolName: ${{ parameters.PoolName }} BuildJsep: ${{ parameters.BuildJsep }} WithCache: ${{ parameters.WithCache }}