diff --git a/cmake/external/onnxruntime_external_deps.cmake b/cmake/external/onnxruntime_external_deps.cmake index 0e0083af9ed54..1f31acb057b37 100644 --- a/cmake/external/onnxruntime_external_deps.cmake +++ b/cmake/external/onnxruntime_external_deps.cmake @@ -516,11 +516,8 @@ onnxruntime_fetchcontent_declare( EXCLUDE_FROM_ALL FIND_PACKAGE_ARGS NAMES ONNX onnx ) -if (NOT onnxruntime_MINIMAL_BUILD) - onnxruntime_fetchcontent_makeavailable(onnx) -else() - include(onnx_minimal) -endif() + +onnxruntime_fetchcontent_makeavailable(onnx) if(TARGET ONNX::onnx AND NOT TARGET onnx) message(STATUS "Aliasing ONNX::onnx to onnx") diff --git a/cmake/patches/onnx/onnx.patch b/cmake/patches/onnx/onnx.patch index 162d33581a5ca..c0d9794df160c 100644 --- a/cmake/patches/onnx/onnx.patch +++ b/cmake/patches/onnx/onnx.patch @@ -1,8 +1,53 @@ -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 6d7ca846..69aa622f 100644 +diff --git a/CMakeLists.txt b/CMakeLists.txt +index d15d97ed..bdacac99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt -@@ -499,6 +499,7 @@ if (MSVC) +@@ -27,6 +27,7 @@ option(ONNX_USE_LITE_PROTO "Use lite protobuf instead of full." OFF) + option(ONNX_DISABLE_EXCEPTIONS "Disable exception handling." OFF) + option(ONNX_DISABLE_STATIC_REGISTRATION "Disable static registration for onnx operator schemas." OFF) + option(ONNX_USE_UNITY_BUILD "Enable Unity (Jumbo) build for" OFF) ++option(ONNX_MINIMAL_BUILD "Build only essential ONNX components" OFF) + + if(NOT DEFINED ONNX_ML) + if(DEFINED ENV{ONNX_ML}) +@@ -457,14 +458,28 @@ relative_protobuf_generate_cpp(gen_onnx_data_proto + list(APPEND ONNX_PROTO_SRCS ${__tmp_srcs}) + list(APPEND ONNX_PROTO_HDRS ${__tmp_hdrs}) + +-file(GLOB_RECURSE __tmp_srcs "${ONNX_ROOT}/onnx/*.h" "${ONNX_ROOT}/onnx/*.cc") +-file(GLOB_RECURSE onnx_gtests_src "${ONNX_ROOT}/onnx/test/cpp/*.h" +- "${ONNX_ROOT}/onnx/test/cpp/*.cc" +- "${ONNX_ROOT}/onnx/backend/test/cpp/*.cc" +- "${ONNX_ROOT}/onnx/backend/test/cpp/*.h") +-list(REMOVE_ITEM __tmp_srcs "${ONNX_ROOT}/onnx/cpp2py_export.cc") +-list(REMOVE_ITEM __tmp_srcs ${onnx_gtests_src}) +-list(APPEND ONNX_SRCS ${__tmp_srcs}) ++if(ONNX_MINIMAL_BUILD) ++ message(STATUS "Configuring ONNX minimal build") ++ set(ONNX_SRCS ++ "${ONNX_ROOT}/onnx/common/common.h" ++ "${ONNX_ROOT}/onnx/defs/data_type_utils.h" ++ "${ONNX_ROOT}/onnx/defs/data_type_utils.cc" ++ ) ++ # Ensure ONNX_ML is treated as ON for minimal build consistency with ORT's file ++ set(ONNX_ML ON CACHE BOOL "Enable traditional ML API." FORCE) ++ # Minimal build doesn't need Python or tests ++ set(ONNX_BUILD_PYTHON OFF CACHE BOOL "Build Python binaries" FORCE) ++ set(ONNX_BUILD_TESTS OFF CACHE BOOL "Build ONNX C++ APIs Tests" FORCE) ++else() ++ file(GLOB_RECURSE __tmp_srcs "${ONNX_ROOT}/onnx/*.h" "${ONNX_ROOT}/onnx/*.cc") ++ file(GLOB_RECURSE onnx_gtests_src "${ONNX_ROOT}/onnx/test/cpp/*.h" ++ "${ONNX_ROOT}/onnx/test/cpp/*.cc" ++ "${ONNX_ROOT}/onnx/backend/test/cpp/*.cc" ++ "${ONNX_ROOT}/onnx/backend/test/cpp/*.h") ++ list(REMOVE_ITEM __tmp_srcs "${ONNX_ROOT}/onnx/cpp2py_export.cc") ++ list(REMOVE_ITEM __tmp_srcs ${onnx_gtests_src}) ++ list(APPEND ONNX_SRCS ${__tmp_srcs}) ++endif() + + add_library(onnx_proto ${ONNX_PROTO_SRCS} ${ONNX_PROTO_HDRS}) + add_dependencies(onnx_proto gen_onnx_operators_proto gen_onnx_data_proto) +@@ -496,6 +511,7 @@ if (MSVC) endif() else() # On non-Windows, hide all symbols we don't need @@ -10,7 +55,7 @@ index 6d7ca846..69aa622f 100644 set(ONNX_API_DEFINE "-DONNX_API=__attribute__\(\(__visibility__\(\"default\"\)\)\)") set_target_properties(onnx_proto PROPERTIES CXX_VISIBILITY_PRESET hidden) set_target_properties(onnx_proto PROPERTIES VISIBILITY_INLINES_HIDDEN 1) -@@ -653,20 +654,9 @@ endif() +@@ -631,20 +647,9 @@ endif() if(MSVC) target_compile_options(onnx_proto PRIVATE /MP @@ -36,15 +81,15 @@ index b847798e..a6c31904 100644 --- a/onnx/common/file_utils.h +++ b/onnx/common/file_utils.h @@ -6,7 +6,6 @@ - + #pragma once - + -#include #include #include - + @@ -17,8 +16,7 @@ namespace ONNX_NAMESPACE { - + template void LoadProtoFromPath(const std::string proto_path, T& proto) { - std::filesystem::path proto_u8_path = std::filesystem::u8path(proto_path); @@ -60,7 +105,7 @@ index 0aab3e26..398ac2d6 100644 @@ -47,10 +47,28 @@ #define ONNX_API ONNX_IMPORT #endif - + +#if defined(__GNUC__) +#pragma GCC diagnostic push + @@ -80,7 +125,7 @@ index 0aab3e26..398ac2d6 100644 #else #include "onnx/onnx.pb.h" #endif - + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif diff --git a/cmake/vcpkg-ports/onnx/binskim.patch b/cmake/vcpkg-ports/onnx/binskim.patch index 418e4419b8a41..c0d9794df160c 100644 --- a/cmake/vcpkg-ports/onnx/binskim.patch +++ b/cmake/vcpkg-ports/onnx/binskim.patch @@ -1,8 +1,61 @@ diff --git a/CMakeLists.txt b/CMakeLists.txt -index d15d97ed..fe4bd27f 100644 +index d15d97ed..bdacac99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt -@@ -631,20 +631,9 @@ endif() +@@ -27,6 +27,7 @@ option(ONNX_USE_LITE_PROTO "Use lite protobuf instead of full." OFF) + option(ONNX_DISABLE_EXCEPTIONS "Disable exception handling." OFF) + option(ONNX_DISABLE_STATIC_REGISTRATION "Disable static registration for onnx operator schemas." OFF) + option(ONNX_USE_UNITY_BUILD "Enable Unity (Jumbo) build for" OFF) ++option(ONNX_MINIMAL_BUILD "Build only essential ONNX components" OFF) + + if(NOT DEFINED ONNX_ML) + if(DEFINED ENV{ONNX_ML}) +@@ -457,14 +458,28 @@ relative_protobuf_generate_cpp(gen_onnx_data_proto + list(APPEND ONNX_PROTO_SRCS ${__tmp_srcs}) + list(APPEND ONNX_PROTO_HDRS ${__tmp_hdrs}) + +-file(GLOB_RECURSE __tmp_srcs "${ONNX_ROOT}/onnx/*.h" "${ONNX_ROOT}/onnx/*.cc") +-file(GLOB_RECURSE onnx_gtests_src "${ONNX_ROOT}/onnx/test/cpp/*.h" +- "${ONNX_ROOT}/onnx/test/cpp/*.cc" +- "${ONNX_ROOT}/onnx/backend/test/cpp/*.cc" +- "${ONNX_ROOT}/onnx/backend/test/cpp/*.h") +-list(REMOVE_ITEM __tmp_srcs "${ONNX_ROOT}/onnx/cpp2py_export.cc") +-list(REMOVE_ITEM __tmp_srcs ${onnx_gtests_src}) +-list(APPEND ONNX_SRCS ${__tmp_srcs}) ++if(ONNX_MINIMAL_BUILD) ++ message(STATUS "Configuring ONNX minimal build") ++ set(ONNX_SRCS ++ "${ONNX_ROOT}/onnx/common/common.h" ++ "${ONNX_ROOT}/onnx/defs/data_type_utils.h" ++ "${ONNX_ROOT}/onnx/defs/data_type_utils.cc" ++ ) ++ # Ensure ONNX_ML is treated as ON for minimal build consistency with ORT's file ++ set(ONNX_ML ON CACHE BOOL "Enable traditional ML API." FORCE) ++ # Minimal build doesn't need Python or tests ++ set(ONNX_BUILD_PYTHON OFF CACHE BOOL "Build Python binaries" FORCE) ++ set(ONNX_BUILD_TESTS OFF CACHE BOOL "Build ONNX C++ APIs Tests" FORCE) ++else() ++ file(GLOB_RECURSE __tmp_srcs "${ONNX_ROOT}/onnx/*.h" "${ONNX_ROOT}/onnx/*.cc") ++ file(GLOB_RECURSE onnx_gtests_src "${ONNX_ROOT}/onnx/test/cpp/*.h" ++ "${ONNX_ROOT}/onnx/test/cpp/*.cc" ++ "${ONNX_ROOT}/onnx/backend/test/cpp/*.cc" ++ "${ONNX_ROOT}/onnx/backend/test/cpp/*.h") ++ list(REMOVE_ITEM __tmp_srcs "${ONNX_ROOT}/onnx/cpp2py_export.cc") ++ list(REMOVE_ITEM __tmp_srcs ${onnx_gtests_src}) ++ list(APPEND ONNX_SRCS ${__tmp_srcs}) ++endif() + + add_library(onnx_proto ${ONNX_PROTO_SRCS} ${ONNX_PROTO_HDRS}) + add_dependencies(onnx_proto gen_onnx_operators_proto gen_onnx_data_proto) +@@ -496,6 +511,7 @@ if (MSVC) + endif() + else() + # On non-Windows, hide all symbols we don't need ++ set(EXTRA_FLAGS "-Wno-unused-parameter") + set(ONNX_API_DEFINE "-DONNX_API=__attribute__\(\(__visibility__\(\"default\"\)\)\)") + set_target_properties(onnx_proto PROPERTIES CXX_VISIBILITY_PRESET hidden) + set_target_properties(onnx_proto PROPERTIES VISIBILITY_INLINES_HIDDEN 1) +@@ -631,20 +647,9 @@ endif() if(MSVC) target_compile_options(onnx_proto PRIVATE /MP @@ -23,3 +76,58 @@ index d15d97ed..fe4bd27f 100644 ${EXTRA_FLAGS}) if(ONNX_USE_PROTOBUF_SHARED_LIBS) target_compile_options(onnx_proto +diff --git a/onnx/common/file_utils.h b/onnx/common/file_utils.h +index b847798e..a6c31904 100644 +--- a/onnx/common/file_utils.h ++++ b/onnx/common/file_utils.h +@@ -6,7 +6,6 @@ + + #pragma once + +-#include + #include + #include + +@@ -17,8 +16,7 @@ namespace ONNX_NAMESPACE { + + template + void LoadProtoFromPath(const std::string proto_path, T& proto) { +- std::filesystem::path proto_u8_path = std::filesystem::u8path(proto_path); +- std::fstream proto_stream(proto_u8_path, std::ios::in | std::ios::binary); ++ std::fstream proto_stream(proto_path, std::ios::in | std::ios::binary); + if (!proto_stream.good()) { + fail_check("Unable to open proto file: ", proto_path, ". Please check if it is a valid proto. "); + } +diff --git a/onnx/onnx_pb.h b/onnx/onnx_pb.h +index 0aab3e26..398ac2d6 100644 +--- a/onnx/onnx_pb.h ++++ b/onnx/onnx_pb.h +@@ -47,10 +47,28 @@ + #define ONNX_API ONNX_IMPORT + #endif + ++#if defined(__GNUC__) ++#pragma GCC diagnostic push ++ ++// In file included from onnx/onnx-ml.pb.h:30: ++// In file included from google/protobuf/extension_set.h:53: ++// google/protobuf/parse_context.h:328:47: error: implicit conversion loses integer precision: 'long' to 'int' [-Werror,-Wshorten-64-to-32] ++#if defined(__has_warning) ++#if __has_warning("-Wshorten-64-to-32") ++#pragma GCC diagnostic ignored "-Wshorten-64-to-32" ++#endif ++#endif // defined(__has_warning) ++ ++#endif // defined(__GNUC__) ++ + #ifdef ONNX_ML + #include "onnx/onnx-ml.pb.h" + #else + #include "onnx/onnx.pb.h" + #endif + ++#if defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ + #endif // ! ONNX_ONNX_PB_H diff --git a/tools/ci_build/build.py b/tools/ci_build/build.py index e8625e77e9a63..c69fbb677d20c 100644 --- a/tools/ci_build/build.py +++ b/tools/ci_build/build.py @@ -293,13 +293,17 @@ def generate_vcpkg_install_options(build_dir, args): folder_name_parts = [] if args.enable_address_sanitizer: folder_name_parts.append("asan") - if args.use_binskim_compliant_compile_flags and not args.android: + if args.use_binskim_compliant_compile_flags and not args.android and not args.build_wasm: folder_name_parts.append("binskim") if args.disable_rtti: folder_name_parts.append("nortti") + if args.build_wasm and not args.disable_wasm_exception_catching and not args.disable_exceptions: + folder_name_parts.append("exception_catching") if args.disable_exceptions: folder_name_parts.append("noexception") - if len(folder_name_parts) == 0: + if args.minimal_build is not None: + folder_name_parts.append("minimal") + if args.build_wasm or len(folder_name_parts) == 0: # It's hard to tell whether we must use a custom triplet or not. The official triplets work fine for most common situations. However, if a Windows build has set msvc toolset version via args.msvc_toolset then we need to, because we need to ensure all the source code are compiled by the same MSVC toolset version otherwise we will hit link errors like "error LNK2019: unresolved external symbol __std_mismatch_4 referenced in function ..." # So, to be safe we always use a custom triplet. folder_name = "default" @@ -507,7 +511,8 @@ def generate_build_tree( "-Donnxruntime_DISABLE_OPTIONAL_TYPE=" + ("ON" if disable_optional_type else "OFF"), "-Donnxruntime_CUDA_MINIMAL=" + ("ON" if args.enable_cuda_minimal_build else "OFF"), ] - + if args.minimal_build is not None: + add_default_definition(cmake_extra_defines, "ONNX_MINIMAL_BUILD", "ON") if args.rv64: add_default_definition(cmake_extra_defines, "onnxruntime_CROSS_COMPILING", "ON") if not args.riscv_toolchain_root: @@ -607,7 +612,14 @@ def generate_build_tree( add_default_definition( cmake_extra_defines, "VCPKG_CHAINLOAD_TOOLCHAIN_FILE", str(empty_toolchain_file.absolute()) ) - generate_vcpkg_triplets_for_emscripten(build_dir, emscripten_root_path) + generate_vcpkg_triplets_for_emscripten( + build_dir, + emscripten_root_path, + not args.disable_rtti, + not args.disable_wasm_exception_catching, + args.minimal_build is not None, + args.enable_address_sanitizer, + ) elif args.android: generate_android_triplets(build_dir, args.android_cpp_shared, args.android_api) elif is_windows(): diff --git a/tools/doc/builddoc.sh b/tools/doc/builddoc.sh old mode 100644 new mode 100755 diff --git a/tools/python/util/vcpkg_helpers.py b/tools/python/util/vcpkg_helpers.py index df457cdbf2b95..1fbb4a06b3c2b 100644 --- a/tools/python/util/vcpkg_helpers.py +++ b/tools/python/util/vcpkg_helpers.py @@ -9,23 +9,30 @@ # This is a way to add customizations to the official VCPKG ports. -def add_port_configs(f, has_exception: bool, is_emscripten: bool) -> None: +def add_port_configs(f, has_exception: bool, is_emscripten: bool, enable_minimal_build: bool) -> None: """ Add port-specific configurations to the triplet file. Args: f (file object): The file object to write configurations. has_exception (bool): Flag indicating if exceptions are enabled. + is_emscripten (bool): Flag indicating if the target is Emscripten. + enable_minimal_build (bool): Flag indicating if ONNX minimal build is enabled. """ f.write( - r"""if(PORT MATCHES "onnx") + r"""if(PORT MATCHES "benchmark") list(APPEND VCPKG_CMAKE_CONFIGURE_OPTIONS - "-DONNX_DISABLE_STATIC_REGISTRATION=ON" + "-DBENCHMARK_ENABLE_WERROR=OFF" ) endif() -if(PORT MATCHES "benchmark") +""" + ) + f.write( + r"""if(PORT MATCHES "date") list(APPEND VCPKG_CMAKE_CONFIGURE_OPTIONS - "-DBENCHMARK_ENABLE_WERROR=OFF" + "-DENABLE_DATE_TESTING=OFF" + "-DBUILD_TZ_LIB=OFF" + "-DUSE_SYSTEM_TZ_DB=ON" ) endif() """ @@ -39,16 +46,38 @@ def add_port_configs(f, has_exception: bool, is_emscripten: bool) -> None: endif() """ ) + + # Add ONNX specific flags based on exception and minimal build settings + f.write(r"""if(PORT MATCHES "onnx")""") # Start ONNX-specific block + f.write(r""" + list(APPEND VCPKG_CMAKE_CONFIGURE_OPTIONS + "-DONNX_DISABLE_STATIC_REGISTRATION=ON" + ) + """) if not has_exception: + # From the ORT CMake logic: onnxruntime_DISABLE_EXCEPTIONS requires onnxruntime_MINIMAL_BUILD. + # While we add the flag here based on has_exception, the calling build script + # must ensure it only uses a noexception triplet when a minimal build is intended for ORT itself. + # This triplet setting makes sure the ONNX *dependency* is built correctly if no-exception is requested. f.write( - r"""if(PORT MATCHES "onnx") + r""" list(APPEND VCPKG_CMAKE_CONFIGURE_OPTIONS "-DONNX_DISABLE_EXCEPTIONS=ON" - ) -endif() -""" + )""" ) + if enable_minimal_build: + f.write( + r""" + list(APPEND VCPKG_CMAKE_CONFIGURE_OPTIONS + "-DONNX_MINIMAL_BUILD=ON" + )""" + ) + + f.write(r""" +endif() # End ONNX-specific block +""") + def add_copyright_header(f) -> None: """ @@ -70,6 +99,7 @@ def generate_triplet_for_android( enable_rtti: bool, enable_exception: bool, enable_asan: bool, + enable_minimal_build: bool, use_cpp_shared: bool, android_api_level: int, ) -> None: @@ -82,6 +112,7 @@ def generate_triplet_for_android( enable_rtti (bool): Flag indicating if RTTI is enabled. enable_exception (bool): Flag indicating if exceptions are enabled. enable_asan (bool): Flag indicating if AddressSanitizer is enabled. + enable_minimal_build (bool): Flag indicating if ONNX minimal build is enabled. use_cpp_shared(bool): The type of C++ Runtime to use. If it is false, use "c++_static" which is the default for most CMake projects. Otherwise set the runtime to c++_shared. android_api_level(int): android_api_level """ @@ -92,6 +123,8 @@ def generate_triplet_for_android( folder_name_parts.append("nortti") if not enable_exception: folder_name_parts.append("noexception") + if enable_minimal_build: + folder_name_parts.append("minimal") folder_name = "default" if len(folder_name_parts) == 0 else "_".join(folder_name_parts) @@ -187,7 +220,7 @@ def generate_triplet_for_android( if ldflags: f.write(f'set(VCPKG_LINKER_FLAGS "{" ".join(ldflags)}")\n') f.write("list(APPEND VCPKG_CMAKE_CONFIGURE_OPTIONS -DCMAKE_CXX_STANDARD=17)\n") - add_port_configs(f, enable_exception, False) + add_port_configs(f, enable_exception, False, enable_minimal_build) # Pass enable_minimal_build def generate_android_triplets(build_dir: str, use_cpp_shared: bool, android_api_level: int) -> None: @@ -201,16 +234,20 @@ def generate_android_triplets(build_dir: str, use_cpp_shared: bool, android_api_ for enable_asan in [True, False]: for enable_rtti in [True, False]: for enable_exception in [True, False]: - for target_abi in target_abis: - generate_triplet_for_android( - build_dir, - target_abi, - enable_rtti, - enable_exception, - enable_asan, - use_cpp_shared, - android_api_level, - ) + for enable_minimal_build in [True, False]: + if not enable_exception and not enable_minimal_build: + continue + for target_abi in target_abis: + generate_triplet_for_android( + build_dir, + target_abi, + enable_rtti, + enable_exception, + enable_asan, + enable_minimal_build, + use_cpp_shared, + android_api_level, + ) def generate_triplet_for_posix_platform( @@ -220,6 +257,7 @@ def generate_triplet_for_posix_platform( enable_exception: bool, enable_binskim: bool, enable_asan: bool, + enable_minimal_build: bool, crt_linkage: str, target_abi: str, osx_deployment_target: str, @@ -234,6 +272,7 @@ def generate_triplet_for_posix_platform( enable_exception (bool): Flag indicating if exceptions are enabled. enable_binskim (bool): Flag indicating if BinSkim is enabled. enable_asan (bool): Flag indicating if AddressSanitizer is enabled. + enable_minimal_build (bool): Flag indicating if ONNX minimal build is enabled. crt_linkage (str): The CRT linkage type ("static" or "dynamic"). target_abi (str): The target ABI, which maps to the VCPKG_TARGET_ARCHITECTURE variable. Valid options include x86, x64, arm, arm64, arm64ec, s390x, ppc64le, riscv32, riscv64, loongarch32, loongarch64, mips64. osx_deployment_target (str, optional): The macOS deployment target version. The parameter sets the minimum macOS version for compiled binaries. It also changes what versions of the macOS platform SDK CMake will search for. See the CMake documentation for CMAKE_OSX_DEPLOYMENT_TARGET for more information. @@ -247,6 +286,8 @@ def generate_triplet_for_posix_platform( folder_name_parts.append("nortti") if not enable_exception: folder_name_parts.append("noexception") + if enable_minimal_build: + folder_name_parts.append("minimal") folder_name = "default" if len(folder_name_parts) == 0 else "_".join(folder_name_parts) @@ -356,77 +397,154 @@ def generate_triplet_for_posix_platform( f.write("list(APPEND VCPKG_CMAKE_CONFIGURE_OPTIONS -DCMAKE_CXX_STANDARD=20)\n") else: f.write("list(APPEND VCPKG_CMAKE_CONFIGURE_OPTIONS -DCMAKE_CXX_STANDARD=17)\n") - add_port_configs(f, enable_exception, False) + add_port_configs(f, enable_exception, False, enable_minimal_build) # Pass enable_minimal_build -def generate_vcpkg_triplets_for_emscripten(build_dir: str, emscripten_root: str) -> None: +def generate_vcpkg_triplets_for_emscripten( + build_dir: str, + emscripten_root: str, + # Parameters defining the specific build configuration + enable_rtti: bool, + enable_wasm_exception_catching: bool, # Controls -sDISABLE_EXCEPTION_CATCHING=... + enable_minimal_onnx_build: bool, # Controls ONNX port setting AND C++ exceptions (-fno-exceptions) + enable_asan: bool, +) -> None: """ - Generate triplet files for Emscripten (WASM). + Generate triplet files for Emscripten (WASM) for wasm32 and wasm64. + Places files in the 'default' subdirectory. + Configures flags based on passed parameters. + + Derives C++ exception support based on the minimal build flag: + - If enable_minimal_onnx_build=True, C++ exceptions are disabled (-fno-exceptions). + - If enable_minimal_onnx_build=False, C++ exceptions are assumed enabled (-fexceptions). + + This supports three main effective EH scenarios depending on the combination of + 'enable_minimal_onnx_build' and 'enable_wasm_exception_catching': + 1. No EH (-fno-exceptions, -sDISABLE_EXCEPTION_CATCHING=1): + Set enable_minimal_onnx_build=True, enable_wasm_exception_catching=False + 2. Full EH (-fexceptions, -sDISABLE_EXCEPTION_CATCHING=0): + Set enable_minimal_onnx_build=False, enable_wasm_exception_catching=True + 3. Throw Only EH (-fexceptions, -sDISABLE_EXCEPTION_CATCHING=1): + Set enable_minimal_onnx_build=False, enable_wasm_exception_catching=False Args: build_dir (str): The directory to save the generated triplet files. emscripten_root (str): The root path of Emscripten. + enable_rtti (bool): Flag indicating if RTTI is enabled for dependencies. + enable_wasm_exception_catching (bool): Flag indicating if the Emscripten runtime + exception catching mechanism should be enabled + (controls -sDISABLE_EXCEPTION_CATCHING=...). + enable_minimal_onnx_build (bool): Flag controlling if the ONNX dependency + should be built with DONNX_MINIMAL_BUILD=ON. + Also implicitly controls C++ exceptions for + dependencies (True => -fno-exceptions). + enable_asan (bool): Flag indicating if AddressSanitizer is enabled for dependencies. """ - for enable_rtti in [True, False]: - for enable_asan in [True, False]: - for target_abi in ["wasm32", "wasm64"]: - folder_name_parts = [] - if enable_asan: - folder_name_parts.append("asan") - folder_name = "default" if len(folder_name_parts) == 0 else "_".join(folder_name_parts) - os_name = "emscripten" - folder_name_parts = [] - if enable_asan: - folder_name_parts.append("asan") - if not enable_rtti: - folder_name_parts.append("nortti") - folder_name = "default" if len(folder_name_parts) == 0 else "_".join(folder_name_parts) - file_name = f"{target_abi}-{os_name}.cmake" - dest_path = Path(build_dir) / folder_name / file_name - os.makedirs(dest_path.parent, exist_ok=True) - with open(dest_path, "w", encoding="utf-8") as f: - add_copyright_header(f) - f.write(r""" - set(VCPKG_CRT_LINKAGE dynamic) - set(VCPKG_LIBRARY_LINKAGE static) - set(VCPKG_CMAKE_SYSTEM_NAME Emscripten) - """) - f.write(f"set(VCPKG_TARGET_ARCHITECTURE {target_abi})\n") - emscripten_root_path_cmake_path = emscripten_root.replace("\\", "/") - f.write(f'set(EMSCRIPTEN_ROOT_PATH "{emscripten_root_path_cmake_path}")\n') - vcpkg_toolchain_file = (Path(build_dir) / "emsdk_vcpkg_toolchain.cmake").absolute() - vcpkg_toolchain_file_cmake_path = str(vcpkg_toolchain_file).replace("\\", "/") - f.write(f'set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "{vcpkg_toolchain_file_cmake_path}")\n') - cflags_release = ["-DNDEBUG", "-O3", "-pthread"] - ldflags = [] - cflags = [ - "-ffunction-sections", - "-fdata-sections", - "-msimd128", - "-pthread", - "-Wno-pthreads-mem-growth", - "-sDISABLE_EXCEPTION_CATCHING=0", - ] - if enable_asan: - cflags += ["-fsanitize=address"] - ldflags += ["-fsanitize=address"] - if target_abi == "wasm64": - cflags.append("-sMEMORY64") - ldflags.append("-sMEMORY64") - if len(ldflags) >= 1: - f.write('set(VCPKG_LINKER_FLAGS "{}")\n'.format(" ".join(ldflags))) - cxxflags = cflags.copy() - if cflags: - f.write(f'set(VCPKG_C_FLAGS "{" ".join(cflags)}")\n') - if cxxflags: - f.write(f'set(VCPKG_CXX_FLAGS "{" ".join(cxxflags)}")\n') - if cflags_release: - cflags_release += cflags - f.write(f'set(VCPKG_C_FLAGS_RELEASE "{" ".join(cflags_release)}")\n') - f.write(f'set(VCPKG_CXX_FLAGS_RELEASE "{" ".join(cflags_release)}")\n') - f.write(f'set(VCPKG_C_FLAGS_RELWITHDEBINFO "{" ".join(cflags_release)}")\n') - f.write(f'set(VCPKG_CXX_FLAGS_RELWITHDEBINFO "{" ".join(cflags_release)}")\n') - add_port_configs(f, True, True) + # Always place generated files in the 'default' folder for Emscripten + folder_name = "default" + + # Derive C++ exception enablement from the minimal build flag + cpp_exceptions_enabled = not enable_minimal_onnx_build + + for target_abi in ["wasm32", "wasm64"]: + os_name = "emscripten" + file_name = f"{target_abi}-{os_name}.cmake" + dest_path = Path(build_dir) / folder_name / file_name + os.makedirs(dest_path.parent, exist_ok=True) + + with open(dest_path, "w", encoding="utf-8") as f: + add_copyright_header(f) + f.write(r""" +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) +set(VCPKG_CMAKE_SYSTEM_NAME Emscripten) +""") + f.write(f"set(VCPKG_TARGET_ARCHITECTURE {target_abi})\n") + emscripten_root_path_cmake_path = emscripten_root.replace("\\", "/") + f.write(f'set(EMSCRIPTEN_ROOT_PATH "{emscripten_root_path_cmake_path}")\n') + + # Define the path to the intermediate toolchain file used by vcpkg for wasm + vcpkg_toolchain_file = (Path(build_dir) / "emsdk_vcpkg_toolchain.cmake").absolute() + vcpkg_toolchain_file_cmake_path = str(vcpkg_toolchain_file).replace("\\", "/") + f.write(f'set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "{vcpkg_toolchain_file_cmake_path}")\n') + + # --- Configure Flags based on Parameters --- + cflags_release = ["-DNDEBUG", "-O3", "-flto"] + ldflags = [] # Initialize linker flags list + # Base flags applicable to both C and C++ + base_flags = [ + "-ffunction-sections", + "-fdata-sections", + "-msimd128", + "-pthread", + "-Wno-pthreads-mem-growth", + ] + + # ASan (apply to Base, Linker) + if enable_asan: + asan_flag = "-fsanitize=address" + base_flags.append(asan_flag) + ldflags.append(asan_flag) # Add to linker flags + + # Wasm Exception Catching Runtime (-s flag, apply to Base and Linker flags) + exception_catching_flag = "" + if enable_wasm_exception_catching: + exception_catching_flag = "-sDISABLE_EXCEPTION_CATCHING=0" + else: + exception_catching_flag = "-sDISABLE_EXCEPTION_CATCHING=1" + + base_flags.append(exception_catching_flag) # Add to base C/C++ flags + ldflags.append(exception_catching_flag) # Add to linker flags + + # Wasm64 Memory (apply to Base, Linker) + if target_abi == "wasm64": + memory_flag = "-sMEMORY64" + base_flags.append(memory_flag) + ldflags.append(memory_flag) # Add to linker flags + + # --- C Flags --- + # VCPKG_C_FLAGS applies only base flags + f.write(f'set(VCPKG_C_FLAGS "{" ".join(base_flags)}")\n') + + # --- CXX Flags --- + # Start with base flags + cxxflags = list(base_flags) # Create a copy + + # C++ RTTI Compiler Flag + if not enable_rtti: + cxxflags.append("-fno-rtti") + + # C++ Exceptions Compiler Flag (Derived from enable_minimal_onnx_build) + if not cpp_exceptions_enabled: # i.e., if enable_minimal_onnx_build is True + cxxflags.append("-fno-exceptions") + # If cpp_exceptions_enabled=True, we assume -fexceptions is the default + # or handled by the Emscripten toolchain/CMake settings elsewhere. + + f.write(f'set(VCPKG_CXX_FLAGS "{" ".join(cxxflags)}")\n') + + # --- Linker Flags --- + # Apply Linker flags (now includes exception and memory flags explicitly) + if len(ldflags) >= 1: + f.write('set(VCPKG_LINKER_FLAGS "{}")\n'.format(" ".join(ldflags))) + + # --- Release / RelWithDebInfo Flags --- + # Combine base flags with release-specific flags + c_combined_release_flags = cflags_release + base_flags + cxx_combined_release_flags = cflags_release + cxxflags # Use the derived cxxflags + + f.write(f'set(VCPKG_C_FLAGS_RELEASE "{" ".join(c_combined_release_flags)}")\n') + f.write(f'set(VCPKG_CXX_FLAGS_RELEASE "{" ".join(cxx_combined_release_flags)}")\n') + + f.write("set(VCPKG_LINKER_FLAGS_RELEASE -flto)\n") + + # --- Add Port Specific Configs --- + # Pass the derived C++ exception status and the original minimal build flag + add_port_configs( + f, + has_exception=cpp_exceptions_enabled, # Derived value + is_emscripten=True, + enable_minimal_build=enable_minimal_onnx_build, + ) # Original parameter def generate_windows_triplets(build_dir: str, toolset_version: str) -> None: @@ -448,64 +566,78 @@ def generate_windows_triplets(build_dir: str, toolset_version: str) -> None: for enable_exception in [True, False]: for enable_binskim in [True, False]: for enable_asan in [True, False]: - for crt_linkage in crt_linkages: - # Address Sanitizer libs do not have a Qspectre version. So they two cannot be both enabled. - if enable_asan and enable_binskim: - continue - for target_abi in target_abis: - folder_name_parts = [] - if enable_asan: - folder_name_parts.append("asan") - if enable_binskim: - folder_name_parts.append("binskim") - if not enable_rtti: - folder_name_parts.append("nortti") - if not enable_exception: - folder_name_parts.append("noexception") - folder_name = "default" if len(folder_name_parts) == 0 else "_".join(folder_name_parts) - file_name_parts = [target_abi, "windows", "static"] - if crt_linkage == "dynamic": - file_name_parts.append("md") - file_name = "-".join(file_name_parts) + ".cmake" - dest_path = Path(build_dir) / folder_name / file_name - os.makedirs(dest_path.parent, exist_ok=True) - with open(dest_path, "w", encoding="utf-8") as f: - add_copyright_header(f) - f.write(f"set(VCPKG_TARGET_ARCHITECTURE {target_abi})\n") - f.write(f"set(VCPKG_CRT_LINKAGE {crt_linkage})\n") - f.write("set(VCPKG_LIBRARY_LINKAGE static)\n") - if toolset_version: - f.write(f"set(VCPKG_PLATFORM_TOOLSET_VERSION {toolset_version})\n") - cflags = ["/MP", "/DWIN32", "/D_WINDOWS"] + for enable_minimal_build in [True, False]: + for crt_linkage in crt_linkages: + # Address Sanitizer libs do not have a Qspectre version. So they two cannot be both enabled. + if enable_asan and enable_binskim: + continue + # ORT Constraint: If exceptions are disabled, minimal build must be enabled + if not enable_exception and not enable_minimal_build: + continue + + for target_abi in target_abis: + folder_name_parts = [] + if enable_asan: + folder_name_parts.append("asan") if enable_binskim: - cflags += [ - "/DWINAPI_FAMILY=100", - "/DWINVER=0x0A00", - "/D_WIN32_WINNT=0x0A00", - "/DNTDDI_VERSION=0x0A000000", - ] - ldflags = [] - if enable_binskim: - cflags += ["/guard:cf", "/Qspectre", "/W3"] - ldflags = ["/profile", "/DYNAMICBASE"] - elif enable_asan: - cflags.append("/fsanitize=address") - cxxflags = cflags.copy() - cxxflags.append("/Zc:__cplusplus") - if enable_exception: - cxxflags.append("/EHsc") + folder_name_parts.append("binskim") if not enable_rtti: - cxxflags += ["/GR-", "/we4541"] - if cflags: - f.write(f'set(VCPKG_C_FLAGS "{" ".join(cflags)}")\n') - if cxxflags: - f.write(f'set(VCPKG_CXX_FLAGS "{" ".join(cxxflags)}")\n') - f.write( - "list(APPEND VCPKG_CMAKE_CONFIGURE_OPTIONS --compile-no-warning-as-error -DCMAKE_CXX_STANDARD=17)\n" - ) - if ldflags: - f.write(f'set(VCPKG_LINKER_FLAGS "{" ".join(ldflags)}")\n') - add_port_configs(f, enable_exception, False) + folder_name_parts.append("nortti") + if not enable_exception: + folder_name_parts.append("noexception") + if enable_minimal_build: + folder_name_parts.append("minimal") + + folder_name = "default" if len(folder_name_parts) == 0 else "_".join(folder_name_parts) + file_name_parts = [target_abi, "windows", "static"] + if crt_linkage == "dynamic": + file_name_parts.append("md") + file_name = "-".join(file_name_parts) + ".cmake" + dest_path = Path(build_dir) / folder_name / file_name + os.makedirs(dest_path.parent, exist_ok=True) + with open(dest_path, "w", encoding="utf-8") as f: + add_copyright_header(f) + f.write(f"set(VCPKG_TARGET_ARCHITECTURE {target_abi})\n") + f.write(f"set(VCPKG_CRT_LINKAGE {crt_linkage})\n") + f.write("set(VCPKG_LIBRARY_LINKAGE static)\n") + if toolset_version: + f.write(f"set(VCPKG_PLATFORM_TOOLSET_VERSION {toolset_version})\n") + cflags = ["/MP", "/DWIN32", "/D_WINDOWS"] + if enable_binskim: + cflags += [ + "/DWINAPI_FAMILY=100", + "/DWINVER=0x0A00", + "/D_WIN32_WINNT=0x0A00", + "/DNTDDI_VERSION=0x0A000000", + ] + ldflags = [] + if enable_binskim: + cflags += ["/guard:cf", "/Qspectre", "/W3"] + ldflags = ["/profile", "/DYNAMICBASE"] + elif enable_asan: + cflags.append("/fsanitize=address") + cxxflags = cflags.copy() + cxxflags.append("/Zc:__cplusplus") + if enable_exception: + cxxflags.append("/EHsc") + # MSVC doesn't have a specific flag to disable exceptions like /EHs-c- + # but relies on _HAS_EXCEPTIONS=0 and potentially other flags managed by ORT's main CMake. + # Vcpkg doesn't directly control this via a simple triplet flag AFAIK. + # ORT's CMake handles this via CMAKE_CXX_FLAGS adjustment. + if not enable_rtti: + cxxflags += ["/GR-", "/we4541"] + if cflags: + f.write(f'set(VCPKG_C_FLAGS "{" ".join(cflags)}")\n') + if cxxflags: + f.write(f'set(VCPKG_CXX_FLAGS "{" ".join(cxxflags)}")\n') + f.write( + "list(APPEND VCPKG_CMAKE_CONFIGURE_OPTIONS --compile-no-warning-as-error -DCMAKE_CXX_STANDARD=17)\n" + ) + if ldflags: + f.write(f'set(VCPKG_LINKER_FLAGS "{" ".join(ldflags)}")\n') + add_port_configs( + f, enable_exception, False, enable_minimal_build + ) # Pass enable_minimal_build def generate_linux_triplets(build_dir: str) -> None: @@ -520,20 +652,24 @@ def generate_linux_triplets(build_dir: str) -> None: for enable_exception in [True, False]: for enable_binskim in [True, False]: for enable_asan in [True, False]: - if enable_asan and enable_binskim: - continue - for target_abi in target_abis: - generate_triplet_for_posix_platform( - build_dir, - "linux", - enable_rtti, - enable_exception, - enable_binskim, - enable_asan, - "dynamic", - target_abi, - None, - ) + for enable_minimal_build in [True, False]: + if enable_asan and enable_binskim: + continue + if not enable_exception and not enable_minimal_build: + continue + for target_abi in target_abis: + generate_triplet_for_posix_platform( + build_dir, + "linux", + enable_rtti, + enable_exception, + enable_binskim, + enable_asan, + enable_minimal_build, + "dynamic", + target_abi, + None, + ) def generate_macos_triplets(build_dir: str, osx_deployment_target: str) -> None: @@ -549,17 +685,22 @@ def generate_macos_triplets(build_dir: str, osx_deployment_target: str) -> None: for enable_exception in [True, False]: for enable_binskim in [True, False]: for enable_asan in [True, False]: - if enable_asan and enable_binskim: - continue - for target_abi in target_abis: - generate_triplet_for_posix_platform( - build_dir, - "osx", - enable_rtti, - enable_exception, - enable_binskim, - enable_asan, - "dynamic", - target_abi, - osx_deployment_target, - ) + for enable_minimal_build in [True, False]: + if enable_asan and enable_binskim: + continue + # ORT Constraint: If exceptions are disabled, minimal build must be enabled + if not enable_exception and not enable_minimal_build: + continue + for target_abi in target_abis: + generate_triplet_for_posix_platform( + build_dir, + "osx", + enable_rtti, + enable_exception, + enable_binskim, + enable_asan, + enable_minimal_build, + "dynamic", + target_abi, + osx_deployment_target, + )