From 8167cb1bd90a79013ab5006ebc71d6be632a5d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Fri, 14 Aug 2026 19:39:51 +0200 Subject: [PATCH 1/3] Android: allow building Vulkan/XNNPACK backends as separate shared libraries The Android AAR links every enabled backend into libexecutorch_jni.so, so an app pays for all of them even when it uses one. Vulkan and XNNPACK are the largest contributors, and an app that ships only the CPU path still carries the GPU backend. Add EXECUTORCH_BUILD_VULKAN_BACKEND_SHARED and EXECUTORCH_BUILD_XNNPACK_BACKEND_SHARED, both defaulting to OFF so existing builds are unchanged. When set, the backend is emitted as its own .so that whole-archives the corresponding static archive, and the JNI library no longer links it. Consumers then load only the backends they need. Notes: * jni_noop.cpp is an empty translation unit. A SHARED target whose only content is a whole-archived static library still needs one source file for CMake to invoke the linker. * custom_ops links xnnpack_backend directly, which would pull the backend back into the JNI library and defeat the split, so that link is dropped when the shared XNNPACK build is selected. * build_android_library.sh forwards both variables so they can be driven from the environment. --- extension/android/CMakeLists.txt | 59 ++++++++++++++++++++++--- extension/android/jni/jni_noop.cpp | 3 ++ extension/llm/custom_ops/CMakeLists.txt | 6 ++- scripts/build_android_library.sh | 17 ++++++- 4 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 extension/android/jni/jni_noop.cpp diff --git a/extension/android/CMakeLists.txt b/extension/android/CMakeLists.txt index c94b95286d0..3da6c8f3a64 100644 --- a/extension/android/CMakeLists.txt +++ b/extension/android/CMakeLists.txt @@ -116,10 +116,7 @@ if(TARGET qnn_executorch_backend) endif() if(TARGET xnnpack_backend) - executorch_target_link_options_shared_lib(xnnpack_backend) - list( - APPEND - link_libraries + set(_xnnpack_so_link_libs xnnpack_backend XNNPACK pthreadpool @@ -127,13 +124,61 @@ if(TARGET xnnpack_backend) xnnpack-microkernels-prod ) if(TARGET kleidiai) - list(APPEND link_libraries kleidiai) + list(APPEND _xnnpack_so_link_libs kleidiai) + endif() + + if(EXECUTORCH_BUILD_XNNPACK_BACKEND_SHARED) + # Same rationale as EXECUTORCH_BUILD_VULKAN_BACKEND_SHARED below: ship + # xnnpack_backend as its own libxnnpack_executorch_backend.so so the + # consumer can opt out at install time. Link only the backend itself + # (whole-archived so the register_backend static initializer fires) and + # the XNNPACK third-party libs + executorch_core. Kernel registration + # archives stay in libexecutorch_jni.so so loading both shared libraries + # together does not trigger Error::RegistrationAlreadyRegistered (0x16). + add_library(xnnpack_executorch_backend SHARED + ${EXECUTORCH_ROOT}/extension/android/jni/jni_noop.cpp + ) + executorch_target_link_options_shared_lib(xnnpack_backend) + target_link_options(xnnpack_executorch_backend PRIVATE -fopenmp -static-openmp) + target_link_options_gc_sections(xnnpack_executorch_backend) + target_link_libraries(xnnpack_executorch_backend + PRIVATE ${_xnnpack_so_link_libs} executorch_core log + ) + set_target_properties( + xnnpack_executorch_backend PROPERTIES LINK_FLAGS "-Wl,-rpath='$ORIGIN'" + ) + # executorch_jni still needs cpuinfo headers / lib for thread count detection. + list(APPEND link_libraries cpuinfo) + else() + executorch_target_link_options_shared_lib(xnnpack_backend) + list(APPEND link_libraries ${_xnnpack_so_link_libs}) endif() endif() if(TARGET vulkan_backend) - executorch_target_link_options_shared_lib(vulkan_backend) - list(APPEND link_libraries vulkan_backend) + if(EXECUTORCH_BUILD_VULKAN_BACKEND_SHARED) + # Build vulkan_backend as a standalone shared library that React Native + # Executorch can ship as an opt-in artifact (libvulkan_executorch_backend.so). + # The .so links only vulkan_backend (with --whole-archive so its + # register_backend static initializer fires) plus executorch_core/vulkan_schema. + # Kernel registration libs (optimized_native_cpu_ops_lib, custom_ops, etc.) + # stay in libexecutorch_jni.so to avoid duplicate Kernel registration when + # both .so are loaded together (Error::RegistrationAlreadyRegistered, 0x16). + add_library(vulkan_executorch_backend SHARED + ${EXECUTORCH_ROOT}/extension/android/jni/jni_noop.cpp + ) + executorch_target_link_options_shared_lib(vulkan_backend) + target_link_options_gc_sections(vulkan_executorch_backend) + target_link_libraries(vulkan_executorch_backend + PRIVATE vulkan_backend vulkan_schema executorch_core log + ) + set_target_properties( + vulkan_executorch_backend PROPERTIES LINK_FLAGS "-Wl,-rpath='$ORIGIN'" + ) + else() + executorch_target_link_options_shared_lib(vulkan_backend) + list(APPEND link_libraries vulkan_backend) + endif() endif() if(EXECUTORCH_BUILD_KERNELS_LLM) diff --git a/extension/android/jni/jni_noop.cpp b/extension/android/jni/jni_noop.cpp new file mode 100644 index 00000000000..4084d021d89 --- /dev/null +++ b/extension/android/jni/jni_noop.cpp @@ -0,0 +1,3 @@ +// Empty translation unit so SHARED libraries that only need to whole-archive +// other static archives (e.g. libvulkan_executorch_backend.so) have at least +// one source file for CMake to invoke the linker on. diff --git a/extension/llm/custom_ops/CMakeLists.txt b/extension/llm/custom_ops/CMakeLists.txt index 8a43a5ddf5c..4d3050dc919 100644 --- a/extension/llm/custom_ops/CMakeLists.txt +++ b/extension/llm/custom_ops/CMakeLists.txt @@ -67,7 +67,11 @@ endif() list(TRANSFORM _custom_ops__srcs PREPEND "${EXECUTORCH_ROOT}/") -if(NOT EXECUTORCH_BUILD_XNNPACK) +if(NOT EXECUTORCH_BUILD_XNNPACK OR EXECUTORCH_BUILD_XNNPACK_BACKEND_SHARED) + # custom_ops doesn't actually call into xnnpack_backend (no XNNPACK refs in + # its sources). The transitive PUBLIC link is what was previously dragging + # XNNCompiler/XNNExecutor into libexecutorch_jni.so via the WHOLE_ARCHIVE on + # custom_ops, which defeats EXECUTORCH_BUILD_XNNPACK_BACKEND_SHARED. Drop it. list(APPEND custom_ops_libs extension_threadpool) else() list(APPEND custom_ops_libs extension_threadpool xnnpack_backend) diff --git a/scripts/build_android_library.sh b/scripts/build_android_library.sh index 5363c64b87c..02e7e3b8403 100755 --- a/scripts/build_android_library.sh +++ b/scripts/build_android_library.sh @@ -33,6 +33,8 @@ build_android_native_library() { fi EXECUTORCH_BUILD_VULKAN="${EXECUTORCH_BUILD_VULKAN:-OFF}" + EXECUTORCH_BUILD_VULKAN_BACKEND_SHARED="${EXECUTORCH_BUILD_VULKAN_BACKEND_SHARED:-OFF}" + EXECUTORCH_BUILD_XNNPACK_BACKEND_SHARED="${EXECUTORCH_BUILD_XNNPACK_BACKEND_SHARED:-OFF}" XNNPACK_ENABLE_ARM_SME2="${XNNPACK_ENABLE_ARM_SME2:-ON}" cmake . -DCMAKE_INSTALL_PREFIX="${CMAKE_OUT}" \ @@ -52,6 +54,8 @@ build_android_native_library() { -DEXECUTORCH_BUILD_QNN="${EXECUTORCH_BUILD_QNN}" \ -DQNN_SDK_ROOT="${QNN_SDK_ROOT}" \ -DEXECUTORCH_BUILD_VULKAN="${EXECUTORCH_BUILD_VULKAN}" \ + -DEXECUTORCH_BUILD_VULKAN_BACKEND_SHARED="${EXECUTORCH_BUILD_VULKAN_BACKEND_SHARED}" \ + -DEXECUTORCH_BUILD_XNNPACK_BACKEND_SHARED="${EXECUTORCH_BUILD_XNNPACK_BACKEND_SHARED}" \ -DXNNPACK_ENABLE_ARM_SME2="${XNNPACK_ENABLE_ARM_SME2}" \ -DFLATCC_ALLOW_WERROR=OFF \ -DSUPPORT_REGEX_LOOKAHEAD=ON \ @@ -68,7 +72,18 @@ build_android_native_library() { # Copy artifacts to ABI specific directory local SO_STAGE_DIR="cmake-out-android-so/${ANDROID_ABI}" mkdir -p ${SO_STAGE_DIR} - cp "${CMAKE_OUT}"/extension/android/*.so "${SO_STAGE_DIR}/libexecutorch.so" + cp "${CMAKE_OUT}"/extension/android/libexecutorch_jni.so "${SO_STAGE_DIR}/libexecutorch.so" + + # Copy standalone Vulkan backend shared library if built. Used by React + # Native Executorch as an opt-in artifact when the app enables Vulkan. + if [ -f "${CMAKE_OUT}"/extension/android/libvulkan_executorch_backend.so ]; then + cp "${CMAKE_OUT}"/extension/android/libvulkan_executorch_backend.so "${SO_STAGE_DIR}/" + fi + + # Same for XNNPACK as a standalone shared library. + if [ -f "${CMAKE_OUT}"/extension/android/libxnnpack_executorch_backend.so ]; then + cp "${CMAKE_OUT}"/extension/android/libxnnpack_executorch_backend.so "${SO_STAGE_DIR}/" + fi # Copy QNN related so library if [ -n "$QNN_SDK_ROOT" ] && [ "$ANDROID_ABI" == "arm64-v8a" ]; then From 24d05ae93b43dd15824a37deff7ff25841180f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=C5=82uszniak?= Date: Tue, 18 Aug 2026 22:37:55 +0200 Subject: [PATCH 2/3] lint: apply cmake-format to extension/android/CMakeLists.txt --- extension/android/CMakeLists.txt | 52 +++++++++++++++++--------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/extension/android/CMakeLists.txt b/extension/android/CMakeLists.txt index 3da6c8f3a64..9eb0cca640f 100644 --- a/extension/android/CMakeLists.txt +++ b/extension/android/CMakeLists.txt @@ -116,12 +116,8 @@ if(TARGET qnn_executorch_backend) endif() if(TARGET xnnpack_backend) - set(_xnnpack_so_link_libs - xnnpack_backend - XNNPACK - pthreadpool - cpuinfo - xnnpack-microkernels-prod + set(_xnnpack_so_link_libs xnnpack_backend XNNPACK pthreadpool cpuinfo + xnnpack-microkernels-prod ) if(TARGET kleidiai) list(APPEND _xnnpack_so_link_libs kleidiai) @@ -131,23 +127,28 @@ if(TARGET xnnpack_backend) # Same rationale as EXECUTORCH_BUILD_VULKAN_BACKEND_SHARED below: ship # xnnpack_backend as its own libxnnpack_executorch_backend.so so the # consumer can opt out at install time. Link only the backend itself - # (whole-archived so the register_backend static initializer fires) and - # the XNNPACK third-party libs + executorch_core. Kernel registration - # archives stay in libexecutorch_jni.so so loading both shared libraries - # together does not trigger Error::RegistrationAlreadyRegistered (0x16). - add_library(xnnpack_executorch_backend SHARED + # (whole-archived so the register_backend static initializer fires) and the + # XNNPACK third-party libs + executorch_core. Kernel registration archives + # stay in libexecutorch_jni.so so loading both shared libraries together + # does not trigger Error::RegistrationAlreadyRegistered (0x16). + add_library( + xnnpack_executorch_backend SHARED ${EXECUTORCH_ROOT}/extension/android/jni/jni_noop.cpp ) executorch_target_link_options_shared_lib(xnnpack_backend) - target_link_options(xnnpack_executorch_backend PRIVATE -fopenmp -static-openmp) + target_link_options( + xnnpack_executorch_backend PRIVATE -fopenmp -static-openmp + ) target_link_options_gc_sections(xnnpack_executorch_backend) - target_link_libraries(xnnpack_executorch_backend - PRIVATE ${_xnnpack_so_link_libs} executorch_core log + target_link_libraries( + xnnpack_executorch_backend PRIVATE ${_xnnpack_so_link_libs} + executorch_core log ) set_target_properties( xnnpack_executorch_backend PROPERTIES LINK_FLAGS "-Wl,-rpath='$ORIGIN'" ) - # executorch_jni still needs cpuinfo headers / lib for thread count detection. + # executorch_jni still needs cpuinfo headers / lib for thread count + # detection. list(APPEND link_libraries cpuinfo) else() executorch_target_link_options_shared_lib(xnnpack_backend) @@ -158,19 +159,22 @@ endif() if(TARGET vulkan_backend) if(EXECUTORCH_BUILD_VULKAN_BACKEND_SHARED) # Build vulkan_backend as a standalone shared library that React Native - # Executorch can ship as an opt-in artifact (libvulkan_executorch_backend.so). - # The .so links only vulkan_backend (with --whole-archive so its - # register_backend static initializer fires) plus executorch_core/vulkan_schema. - # Kernel registration libs (optimized_native_cpu_ops_lib, custom_ops, etc.) - # stay in libexecutorch_jni.so to avoid duplicate Kernel registration when - # both .so are loaded together (Error::RegistrationAlreadyRegistered, 0x16). - add_library(vulkan_executorch_backend SHARED + # Executorch can ship as an opt-in artifact + # (libvulkan_executorch_backend.so). The .so links only vulkan_backend (with + # --whole-archive so its register_backend static initializer fires) plus + # executorch_core/vulkan_schema. Kernel registration libs + # (optimized_native_cpu_ops_lib, custom_ops, etc.) stay in + # libexecutorch_jni.so to avoid duplicate Kernel registration when both .so + # are loaded together (Error::RegistrationAlreadyRegistered, 0x16). + add_library( + vulkan_executorch_backend SHARED ${EXECUTORCH_ROOT}/extension/android/jni/jni_noop.cpp ) executorch_target_link_options_shared_lib(vulkan_backend) target_link_options_gc_sections(vulkan_executorch_backend) - target_link_libraries(vulkan_executorch_backend - PRIVATE vulkan_backend vulkan_schema executorch_core log + target_link_libraries( + vulkan_executorch_backend PRIVATE vulkan_backend vulkan_schema + executorch_core log ) set_target_properties( vulkan_executorch_backend PROPERTIES LINK_FLAGS "-Wl,-rpath='$ORIGIN'" From 69a5f51318780855df4dd4c0e180d6b59ac33158 Mon Sep 17 00:00:00 2001 From: Mateusz Sluszniak Date: Tue, 1 Sep 2026 20:27:46 +0200 Subject: [PATCH 3/3] Export the backend registry when a backend is built as its own .so A split backend links executorch_core statically, so it holds a second copy of the registry and only reaches the runtime's copy by binding its register_backend PLT slot to the first definition in the global lookup scope. version_script.txt makes that definition local in libexecutorch_jni.so, so on the AAR path the backend would register into its own table and the runtime would report DelegateNotFound. Use a version script that exports the registry entry points (and pthreadpool, so a split XNNPACK shares the configured pool) whenever a backend is split out, and write the load-order contract down next to the option. Also drop the dead -fopenmp/-static-openmp flags and the $ORIGIN rpath (the .so has no non-system DT_NEEDED), register both options in the preset system, give jni_noop.cpp the license header, and trim the duplicated rationale comments. --- extension/android/CMakeLists.txt | 71 ++++++++++++------- extension/android/jni/jni_noop.cpp | 8 +++ .../jni/version_script_shared_backends.txt | 23 ++++++ tools/cmake/preset/default.cmake | 21 ++++++ 4 files changed, 98 insertions(+), 25 deletions(-) create mode 100644 extension/android/jni/version_script_shared_backends.txt diff --git a/extension/android/CMakeLists.txt b/extension/android/CMakeLists.txt index 9eb0cca640f..f1073fe7a0c 100644 --- a/extension/android/CMakeLists.txt +++ b/extension/android/CMakeLists.txt @@ -115,6 +115,31 @@ if(TARGET qnn_executorch_backend) list(APPEND link_libraries qnn_executorch_backend) endif() +# EXECUTORCH_BUILD_XNNPACK_BACKEND_SHARED / +# EXECUTORCH_BUILD_VULKAN_BACKEND_SHARED emit a backend as its own .so so a +# consumer can drop the ones it does not use. A split backend still links +# executorch_core statically, so it carries a second copy of the backend +# registry (registered_backends[] in runtime/backend/interface.cpp). +# Registration reaches the runtime's copy only through PLT interposition: the +# register_backend call in the backend .so is a JUMP_SLOT relocation, so the +# dynamic linker binds it to the first definition in the global lookup scope. +# Two things have to hold for that to be this library's copy: +# +# * libexecutorch_jni.so has to export register_backend. The default version +# script hides everything but JNI_OnLoad/Java_*, so jni/version_script.txt is +# swapped for jni/version_script_shared_backends.txt below whenever a backend +# is split out. +# * The consumer has to load libexecutorch_jni.so ahead of the backend .so in +# the same lookup scope. Naming both in the link line of the library that uses +# them, runtime first, does that: the runtime lands earlier in DT_NEEDED and +# wins the lookup. dlopen()ing a backend .so on its own does not, and the +# backend then registers into its own table while the runtime reports +# DelegateNotFound. +# +# The same interposition is what keeps a split XNNPACK on one thread pool: the +# pthreadpool symbols are exported from here too, so the backend .so binds to +# the pool extension_threadpool configures instead of a second, unconfigured +# copy of its own. if(TARGET xnnpack_backend) set(_xnnpack_so_link_libs xnnpack_backend XNNPACK pthreadpool cpuinfo xnnpack-microkernels-prod @@ -124,29 +149,21 @@ if(TARGET xnnpack_backend) endif() if(EXECUTORCH_BUILD_XNNPACK_BACKEND_SHARED) - # Same rationale as EXECUTORCH_BUILD_VULKAN_BACKEND_SHARED below: ship - # xnnpack_backend as its own libxnnpack_executorch_backend.so so the - # consumer can opt out at install time. Link only the backend itself - # (whole-archived so the register_backend static initializer fires) and the - # XNNPACK third-party libs + executorch_core. Kernel registration archives - # stay in libexecutorch_jni.so so loading both shared libraries together - # does not trigger Error::RegistrationAlreadyRegistered (0x16). + # Whole-archive the backend so its register_backend static initializer + # fires, and take only the XNNPACK third-party libs with it. The kernel + # registration archives stay in libexecutorch_jni.so, so loading both + # libraries together does not register a kernel twice + # (Error::RegistrationAlreadyRegistered, 0x16). add_library( xnnpack_executorch_backend SHARED ${EXECUTORCH_ROOT}/extension/android/jni/jni_noop.cpp ) executorch_target_link_options_shared_lib(xnnpack_backend) - target_link_options( - xnnpack_executorch_backend PRIVATE -fopenmp -static-openmp - ) target_link_options_gc_sections(xnnpack_executorch_backend) target_link_libraries( xnnpack_executorch_backend PRIVATE ${_xnnpack_so_link_libs} executorch_core log ) - set_target_properties( - xnnpack_executorch_backend PROPERTIES LINK_FLAGS "-Wl,-rpath='$ORIGIN'" - ) # executorch_jni still needs cpuinfo headers / lib for thread count # detection. list(APPEND link_libraries cpuinfo) @@ -158,14 +175,9 @@ endif() if(TARGET vulkan_backend) if(EXECUTORCH_BUILD_VULKAN_BACKEND_SHARED) - # Build vulkan_backend as a standalone shared library that React Native - # Executorch can ship as an opt-in artifact - # (libvulkan_executorch_backend.so). The .so links only vulkan_backend (with - # --whole-archive so its register_backend static initializer fires) plus - # executorch_core/vulkan_schema. Kernel registration libs - # (optimized_native_cpu_ops_lib, custom_ops, etc.) stay in - # libexecutorch_jni.so to avoid duplicate Kernel registration when both .so - # are loaded together (Error::RegistrationAlreadyRegistered, 0x16). + # Same shape as the XNNPACK split above: whole-archive vulkan_backend and + # take only vulkan_schema with it, leaving the kernel registration archives + # in libexecutorch_jni.so. add_library( vulkan_executorch_backend SHARED ${EXECUTORCH_ROOT}/extension/android/jni/jni_noop.cpp @@ -176,9 +188,6 @@ if(TARGET vulkan_backend) vulkan_executorch_backend PRIVATE vulkan_backend vulkan_schema executorch_core log ) - set_target_properties( - vulkan_executorch_backend PROPERTIES LINK_FLAGS "-Wl,-rpath='$ORIGIN'" - ) else() executorch_target_link_options_shared_lib(vulkan_backend) list(APPEND link_libraries vulkan_backend) @@ -291,9 +300,21 @@ target_include_directories( target_compile_options(executorch_jni PUBLIC ${_common_compile_options}) +if(EXECUTORCH_BUILD_XNNPACK_BACKEND_SHARED + OR EXECUTORCH_BUILD_VULKAN_BACKEND_SHARED +) + set(_executorch_jni_version_script + "${CMAKE_CURRENT_SOURCE_DIR}/jni/version_script_shared_backends.txt" + ) +else() + set(_executorch_jni_version_script + "${CMAKE_CURRENT_SOURCE_DIR}/jni/version_script.txt" + ) +endif() + target_link_options( executorch_jni PRIVATE - "LINKER:--version-script,${CMAKE_CURRENT_SOURCE_DIR}/jni/version_script.txt" + "LINKER:--version-script,${_executorch_jni_version_script}" ) target_link_options_gc_sections(executorch_jni) diff --git a/extension/android/jni/jni_noop.cpp b/extension/android/jni/jni_noop.cpp index 4084d021d89..b5b7cf76388 100644 --- a/extension/android/jni/jni_noop.cpp +++ b/extension/android/jni/jni_noop.cpp @@ -1,3 +1,11 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + // Empty translation unit so SHARED libraries that only need to whole-archive // other static archives (e.g. libvulkan_executorch_backend.so) have at least // one source file for CMake to invoke the linker on. diff --git a/extension/android/jni/version_script_shared_backends.txt b/extension/android/jni/version_script_shared_backends.txt new file mode 100644 index 00000000000..7deb0ca8006 --- /dev/null +++ b/extension/android/jni/version_script_shared_backends.txt @@ -0,0 +1,23 @@ +{ + global: + JNI_OnLoad; + Java_*; + # A backend built as its own .so (EXECUTORCH_BUILD_XNNPACK_BACKEND_SHARED / + # EXECUTORCH_BUILD_VULKAN_BACKEND_SHARED) carries its own statically linked + # copy of executorch_core, and therefore its own backend registry. Its call + # to register_backend goes through the PLT, so exporting the registry entry + # points here lets the dynamic linker bind that call to this library's + # registry - the one the runtime actually reads from. + extern "C++" { + executorch::runtime*::register_backend*; + executorch::runtime*::get_backend_class*; + executorch::runtime*::get_backend_name*; + executorch::runtime*::get_num_registered_backends*; + }; + # Same reason, for the thread pool the split XNNPACK backend runs on: bind + # its pthreadpool calls to the pool extension_threadpool configures here + # rather than to a second, unconfigured copy inside the backend .so. + pthreadpool_*; + local: + *; +}; diff --git a/tools/cmake/preset/default.cmake b/tools/cmake/preset/default.cmake index ae5437ea443..979c9d0c953 100644 --- a/tools/cmake/preset/default.cmake +++ b/tools/cmake/preset/default.cmake @@ -171,6 +171,18 @@ define_overridable_option( define_overridable_option( EXECUTORCH_BUILD_VULKAN "Build the Vulkan backend" BOOL OFF ) +define_overridable_option( + EXECUTORCH_BUILD_XNNPACK_BACKEND_SHARED + "Build the XNNPACK backend as its own shared library instead of linking it into the Android JNI library" + BOOL + OFF +) +define_overridable_option( + EXECUTORCH_BUILD_VULKAN_BACKEND_SHARED + "Build the Vulkan backend as its own shared library instead of linking it into the Android JNI library" + BOOL + OFF +) define_overridable_option( EXECUTORCH_BUILD_WEBGPU "Build the WebGPU backend" BOOL OFF ) @@ -357,6 +369,15 @@ check_required_options_on( IF_ON EXECUTORCH_BUILD_QNN REQUIRES EXECUTORCH_BUILD_EXTENSION_TENSOR ) +check_required_options_on( + IF_ON EXECUTORCH_BUILD_XNNPACK_BACKEND_SHARED REQUIRES + EXECUTORCH_BUILD_XNNPACK +) + +check_required_options_on( + IF_ON EXECUTORCH_BUILD_VULKAN_BACKEND_SHARED REQUIRES EXECUTORCH_BUILD_VULKAN +) + check_required_options_on( IF_ON EXECUTORCH_ENABLE_BUNDLE_IO REQUIRES EXECUTORCH_BUILD_DEVTOOLS )