Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
f932b9c
Update
shoumikhin Jul 31, 2026
a231092
Update
shoumikhin Jul 31, 2026
4b44a20
Update
shoumikhin Aug 1, 2026
0fcd4f5
Update
shoumikhin Aug 1, 2026
42b1290
Update
shoumikhin Aug 1, 2026
576b09e
Update
shoumikhin Aug 1, 2026
b350ed6
Update
shoumikhin Aug 1, 2026
20af43e
Update
shoumikhin Aug 1, 2026
de44074
Update
shoumikhin Aug 1, 2026
64027b7
Update
shoumikhin Aug 1, 2026
9adcc7d
Update
shoumikhin Aug 1, 2026
c67a562
Update
shoumikhin Aug 1, 2026
3d0877f
Update
shoumikhin Aug 1, 2026
a038dbc
Update
shoumikhin Aug 1, 2026
9758ccc
Update
shoumikhin Aug 1, 2026
5869a91
Update
shoumikhin Aug 1, 2026
e063167
Update
shoumikhin Aug 1, 2026
e7001ac
Update
shoumikhin Aug 2, 2026
a2096e2
Update
shoumikhin Aug 2, 2026
9ed601f
Update
shoumikhin Aug 2, 2026
60b801f
Update
shoumikhin Aug 2, 2026
bebbbd9
Update
shoumikhin Aug 2, 2026
dd3af02
Update
shoumikhin Aug 2, 2026
050327c
Update
shoumikhin Aug 2, 2026
5cb77bc
Update
shoumikhin Aug 2, 2026
af284f6
Update
shoumikhin Aug 2, 2026
96334c6
Update
shoumikhin Aug 2, 2026
9addd69
Update
shoumikhin Aug 2, 2026
fbcf931
Update
shoumikhin Aug 2, 2026
1de5047
Update
shoumikhin Aug 2, 2026
85be3cf
Update
shoumikhin Aug 2, 2026
12da9b3
Update
shoumikhin Aug 2, 2026
f972cce
Update
shoumikhin Aug 2, 2026
3832931
Update
shoumikhin Aug 2, 2026
515e34f
Update
shoumikhin Aug 2, 2026
836af39
Update
shoumikhin Aug 3, 2026
e1ee4af
Update
shoumikhin Aug 3, 2026
ba0c8f1
Update
shoumikhin Aug 3, 2026
a7457b5
Update
shoumikhin Aug 3, 2026
efb9bc1
Update
shoumikhin Aug 3, 2026
9d3f6c4
Update
shoumikhin Aug 3, 2026
9e781b3
Update
shoumikhin Aug 3, 2026
25b7c74
Update
shoumikhin Aug 3, 2026
06762fe
Update
shoumikhin Aug 3, 2026
f080144
Update
shoumikhin Aug 3, 2026
85c41d1
Update
shoumikhin Aug 3, 2026
4fc97dd
Update
shoumikhin Aug 3, 2026
d6114ed
Update
shoumikhin Aug 3, 2026
344b53f
Update
shoumikhin Aug 3, 2026
9c41cf2
Update
shoumikhin Aug 3, 2026
c0302fa
Update
shoumikhin Aug 3, 2026
6818a88
Update
shoumikhin Aug 3, 2026
66cf96c
Update
shoumikhin Aug 3, 2026
cac8c9b
Update
shoumikhin Aug 3, 2026
f5819c2
Update
shoumikhin Aug 3, 2026
16ef221
Update
shoumikhin Aug 3, 2026
1347b9d
Update
shoumikhin Aug 3, 2026
6fc6c9c
Update
shoumikhin Aug 3, 2026
7d3b20f
Update
shoumikhin Aug 4, 2026
190a917
Update
shoumikhin Aug 4, 2026
f0d98f4
Update
shoumikhin Aug 4, 2026
8d5f30f
Update
shoumikhin Aug 4, 2026
e1600c8
Update
shoumikhin Aug 4, 2026
9b80da1
Update
shoumikhin Aug 4, 2026
78518c9
Update
shoumikhin Aug 4, 2026
de92937
Update
shoumikhin Aug 4, 2026
b54b04b
Update
shoumikhin Aug 4, 2026
289cf00
Update
shoumikhin Aug 4, 2026
d7ecfa9
Update
shoumikhin Aug 4, 2026
6eb7c6d
Update
shoumikhin Aug 4, 2026
662bef7
Update
shoumikhin Aug 4, 2026
18f9448
Update
shoumikhin Aug 5, 2026
bba6d85
Update
shoumikhin Aug 5, 2026
c489bc4
Update
shoumikhin Aug 5, 2026
8c892d8
Update
shoumikhin Aug 5, 2026
cd98316
Update
shoumikhin Aug 5, 2026
74bcef4
Update
shoumikhin Aug 5, 2026
9fb9a46
Update
shoumikhin Aug 5, 2026
f1e842a
Update
shoumikhin Aug 5, 2026
e9198fe
Update
shoumikhin Aug 5, 2026
00509a8
Update
shoumikhin Aug 5, 2026
4e029cd
Update
shoumikhin Aug 5, 2026
873a60a
Update
shoumikhin Aug 5, 2026
1152545
Update
shoumikhin Aug 5, 2026
e92e3d1
Update
shoumikhin Aug 5, 2026
bf30292
Update
shoumikhin Aug 5, 2026
c8bd5fd
Update
shoumikhin Aug 5, 2026
20e3424
Update
shoumikhin Aug 5, 2026
19ea4cf
Update
shoumikhin Aug 5, 2026
aa1a2d8
Update
shoumikhin Aug 5, 2026
476163d
Update
shoumikhin Aug 5, 2026
637d5d3
Update
shoumikhin Aug 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .ci/scripts/wheel/test_cpp_sdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@
"executorch::runtime::get_registered_kernels",
)

# A representative symbol from the XNNPACK delegate. A second definer means the
# process carries two copies of the delegate.
_XNNPACK_SYMBOLS = (
"executorch::backends::xnnpack::XnnpackBackendOptions::workspace_manager",
)

# `nm -DC` prints "<hexaddr> <kind> <name>" for a definition and
# " U <name>" for an undefined reference.
_DEFINED = re.compile(r"^[0-9a-fA-F]+\s+(?P<kind>[A-Za-z])\s+(?P<name>.+)$")
Expand Down Expand Up @@ -194,6 +200,11 @@ def test_single_kernel_registration() -> None:
_assert_single_definer(_KERNEL_REGISTRY_SYMBOLS, "operator registry")


def test_single_xnnpack_delegate() -> None:
"""Exactly one shipped library may define the XNNPACK delegate."""
_assert_single_definer(_XNNPACK_SYMBOLS, "XNNPACK delegate")


def test_cpp_consumer(work_dir: Path) -> None:
"""A standalone C++ app builds and runs against the installed wheel."""
assert shutil.which("cmake") is not None, "cmake is required to build a consumer"
Expand Down Expand Up @@ -784,7 +795,7 @@ def test_no_absolute_runtime_paths() -> None:

# Link every component this wheel offers, and report which ones those are so the test
# can check the result. Guarded individually because the set depends on the wheel.
foreach(_component threadpool kernels_optimized kernels_quantized etdump)
foreach(_component threadpool kernels_optimized kernels_quantized etdump backend_xnnpack)
if(TARGET executorch::${_component})
target_link_libraries(component_consumer PRIVATE executorch::${_component})
# Report the library file, not just the target name: the two differ, and the test
Expand Down Expand Up @@ -953,6 +964,7 @@ def run_tests(work_dir: Path) -> None:
test_no_absolute_runtime_paths()
test_single_threadpool()
test_single_kernel_registration()
test_single_xnnpack_delegate()
test_cpp_consumer(work_dir)
test_documented_example_compiles(work_dir)
test_component_targets_link(work_dir)
31 changes: 20 additions & 11 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1242,9 +1242,15 @@ if(EXECUTORCH_BUILD_PYBIND)
endif()

if(EXECUTORCH_BUILD_XNNPACK)
# need to explicitly specify XNNPACK and xnnpack-microkernels-prod here
# otherwise uses XNNPACK and microkernel-prod symbols from libtorch_cpu
list(APPEND _dep_libs xnnpack_backend XNNPACK xnnpack-microkernels-prod)
if(EXECUTORCH_BUILD_SHARED)
# The delegate bundles XNNPACK and its microkernels, so naming them again
# here would ship a second copy.
list(APPEND _dep_libs xnnpack_backend)
Comment thread
shoumikhin marked this conversation as resolved.
else()
# need to explicitly specify XNNPACK and xnnpack-microkernels-prod here
# otherwise uses XNNPACK and microkernel-prod symbols from libtorch_cpu
list(APPEND _dep_libs xnnpack_backend XNNPACK xnnpack-microkernels-prod)
endif()
endif()

if(EXECUTORCH_BUILD_VULKAN)
Expand Down Expand Up @@ -1299,14 +1305,17 @@ if(EXECUTORCH_BUILD_PYBIND)
target_compile_options(portable_lib PUBLIC ${_pybind_compile_options})
target_link_libraries(portable_lib PRIVATE ${_dep_libs})
executorch_target_link_shared_runtime(portable_lib)
# The operators register themselves from a static initializer, so nothing here
# references a symbol from the kernels library and some linkers drop it, which
# surfaces at runtime as a missing kernel rather than a link error.
if(TARGET optimized_native_cpu_ops_lib)
executorch_target_retain_shared_library(
portable_lib optimized_native_cpu_ops_lib
)
endif()
# These libraries register their operators or their backend from a static
# initializer, so nothing here references a symbol from them and some linkers
# drop them from DT_NEEDED. That surfaces at runtime as a missing kernel or an
# unregistered backend rather than as a link error.
foreach(_retained_component optimized_native_cpu_ops_lib xnnpack_backend)
if(TARGET ${_retained_component})
executorch_target_retain_shared_library(
portable_lib ${_retained_component}
)
endif()
endforeach()

# Set RPATH to find PyTorch and backend libraries relative to the installation
# location. This goes from executorch/extension/pybindings up to
Expand Down
44 changes: 41 additions & 3 deletions backends/xnnpack/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,54 @@ target_include_directories(
$<BUILD_INTERFACE:${EXECUTORCH_ROOT}/third-party/flatbuffers/include>
)

set(xnnpack_third_party pthreadpool extension_threadpool cpuinfo)
if(EXECUTORCH_BUILD_SHARED)
# extension_threadpool is a shared library here and already provides
# pthreadpool and cpuinfo. Naming the static archives as well would give this
# delegate its own second copy of both, so a process would end up with two
# thread pools rather than the one the shared library exists to provide.
set(xnnpack_third_party extension_threadpool)
else()
set(xnnpack_third_party pthreadpool extension_threadpool cpuinfo)
endif()

include(cmake/Dependencies.cmake)

list(TRANSFORM _xnnpack_backend__srcs PREPEND "${EXECUTORCH_ROOT}/")
add_library(xnnpack_backend ${_xnnpack_backend__srcs})
# Build the delegate as a shared library for the wheel so a process has one copy
# of it, and keep it static everywhere else so no other build changes.
if(EXECUTORCH_BUILD_SHARED)
set(_xnnpack_backend_library_type SHARED)
else()
set(_xnnpack_backend_library_type STATIC)
endif()
add_library(
xnnpack_backend ${_xnnpack_backend_library_type} ${_xnnpack_backend__srcs}
)
target_link_libraries(
xnnpack_backend PUBLIC ${xnnpack_third_party} executorch_core xnnpack_schema
xnnpack_backend PUBLIC ${xnnpack_third_party} xnnpack_schema
extension_threadpool
)
if(EXECUTORCH_BUILD_SHARED)
Comment thread
shoumikhin marked this conversation as resolved.
set_target_properties(
xnnpack_backend
PROPERTIES OUTPUT_NAME executorch_backend_xnnpack
VERSION "${PROJECT_VERSION}"
SOVERSION "${PROJECT_VERSION_MAJOR}"
)
# XNNPACK and its microkernels are forced static, so bundle them inside this
# library instead of making every consumer supply them.
executorch_target_whole_archive(xnnpack_backend XNNPACK)
executorch_target_whole_archive(xnnpack_backend xnnpack-microkernels-prod)
target_link_libraries(xnnpack_backend PUBLIC executorch_shared)
if(NOT APPLE)
# Ships beside the runtime in the wheel's lib/ directory.
set_target_properties(
xnnpack_backend PROPERTIES BUILD_RPATH "$ORIGIN" INSTALL_RPATH "$ORIGIN"
)
endif()
else()
target_link_libraries(xnnpack_backend PUBLIC executorch_core)
endif()
target_include_directories(
xnnpack_backend PUBLIC ${_common_include_directories}
)
Expand Down
1 change: 0 additions & 1 deletion docs/source/using-executorch-cpp.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ each one is defined only when the installed wheel actually ships it:
| --- | --- |
| `executorch::runtime` | The core runtime. Always present. |
| `executorch::threadpool` | The shared thread pool the kernels and backends use. |
| `executorch::kernels_optimized` | CPU operator kernels, for any operator not taken by a backend. |

Each target already carries what it needs: the runtime dependency, the include
directories, the runtime search paths, and the linker options that keep a
Expand Down
27 changes: 22 additions & 5 deletions extension/training/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,17 @@ if(EXECUTORCH_BUILD_PYBIND)
endif()

if(EXECUTORCH_BUILD_XNNPACK)
# need to explicitly specify XNNPACK and xnnpack-microkernels-prod here
# otherwise uses XNNPACK and microkernel-prod symbols from libtorch_cpu
list(APPEND _pybind_training_dep_libs xnnpack_backend XNNPACK
xnnpack-microkernels-prod
)
if(EXECUTORCH_BUILD_SHARED)
# The delegate bundles XNNPACK and its microkernels, so naming them again
# here would ask for a second copy of what that library already provides.
list(APPEND _pybind_training_dep_libs xnnpack_backend)
else()
# need to explicitly specify XNNPACK and xnnpack-microkernels-prod here
# otherwise uses XNNPACK and microkernel-prod symbols from libtorch_cpu
list(APPEND _pybind_training_dep_libs xnnpack_backend XNNPACK
xnnpack-microkernels-prod
)
endif()
endif()

pybind11_add_module(
Expand All @@ -89,6 +95,17 @@ if(EXECUTORCH_BUILD_PYBIND)
-fexceptions>
)
target_link_libraries(_training_lib PRIVATE ${_pybind_training_dep_libs})

if(EXECUTORCH_BUILD_SHARED
AND EXECUTORCH_BUILD_XNNPACK
AND TARGET xnnpack_backend
)
# The delegate registers itself from a static initializer, so nothing in
# this extension references a symbol from it and a normal link can drop it.
# Keeping it named on the link line is what makes an XNNPACK-delegated
# program usable from here.
executorch_target_retain_shared_library(_training_lib xnnpack_backend)
endif()
executorch_target_link_shared_runtime(_training_lib)

if(EXECUTORCH_BUILD_SHARED
Expand Down
17 changes: 17 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -1374,6 +1374,23 @@ def run(self): # noqa C901
"EXECUTORCH_BUILD_KERNELS_QUANTIZED",
],
),
# Install the XNNPACK delegate beside them, so a process has one
# copy of it instead of one per component that uses it.
BuiltFile(
src_dir="%CMAKE_CACHE_DIR%/backends/xnnpack/",
src_name=(
"libexecutorch_backend_xnnpack.so."
f"{get_runtime_soname_major()}.*"
),
dst=(
"executorch/lib/libexecutorch_backend_xnnpack.so."
f"{get_runtime_soname_major()}"
),
dependent_cmake_flags=[
"EXECUTORCH_BUILD_SHARED",
"EXECUTORCH_BUILD_XNNPACK",
],
),
# Install the prebuilt pybindings extension wrapper for the runtime,
# portable kernels, and a selection of backends. This lets users
# load and execute .pte files from python.
Expand Down
5 changes: 2 additions & 3 deletions tools/cmake/executorch-wheel-config.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@
# dependency and, for a registration-only library, the link options that keep it
# from being dropped. The names, when present, are:
#
# executorch::threadpool executorch::kernels_optimized
# executorch::xnnpack_backend executorch::cuda_backend
#
# Check with if(TARGET executorch::<name>) rather than assuming one exists. A
# namespaced name that was never defined is a configure-time error that names
# the component, so a consumer who links one unconditionally gets a clear
Expand Down Expand Up @@ -399,6 +396,8 @@ if(TARGET executorch::threadpool)
)
endif()

executorch_define_component(backend_xnnpack executorch_backend_xnnpack)

# Find prebuilt _portable_lib.<EXT_SUFFIX>.so. This is the legacy contract used
# to build custom-op extensions against the Python module, and is kept working
# independently of the runtime target above.
Expand Down
Loading