Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
5416595
Update
shoumikhin Jul 31, 2026
008351d
Update
shoumikhin Jul 31, 2026
b741e2d
Update
shoumikhin Jul 31, 2026
58b61c9
Update
shoumikhin Jul 31, 2026
2e51b61
Update
shoumikhin Jul 31, 2026
058a1f6
Update
shoumikhin Jul 31, 2026
79688cb
Update
shoumikhin Jul 31, 2026
077bb9d
Update
shoumikhin Aug 1, 2026
ab9ad38
Update
shoumikhin Aug 1, 2026
060cc4b
Update
shoumikhin Aug 1, 2026
8ca7e77
Update
shoumikhin Aug 1, 2026
23d62d4
Update
shoumikhin Aug 1, 2026
c076daa
Update
shoumikhin Aug 1, 2026
179b67c
Update
shoumikhin Aug 1, 2026
e18448d
Update
shoumikhin Aug 1, 2026
596690f
Update
shoumikhin Aug 1, 2026
e33f3c1
Update
shoumikhin Aug 1, 2026
2749cc7
Update
shoumikhin Aug 2, 2026
74f27c3
Update
shoumikhin Aug 2, 2026
24ee4f9
Update
shoumikhin Aug 2, 2026
b1075f5
Update
shoumikhin Aug 2, 2026
b5d2c6b
Update
shoumikhin Aug 2, 2026
3447ef5
Update
shoumikhin Aug 2, 2026
642fa5e
Update
shoumikhin Aug 2, 2026
aebfb4d
Update
shoumikhin Aug 2, 2026
607ef93
Update
shoumikhin Aug 2, 2026
0670cb3
Update
shoumikhin Aug 2, 2026
abb743a
Update
shoumikhin Aug 2, 2026
7e257ad
Update
shoumikhin Aug 2, 2026
546ca1c
Update
shoumikhin Aug 2, 2026
16fccef
Update
shoumikhin Aug 2, 2026
8fbcb0d
Update
shoumikhin Aug 2, 2026
1555421
Update
shoumikhin Aug 2, 2026
59cf985
Update
shoumikhin Aug 2, 2026
b2ff575
Update
shoumikhin Aug 2, 2026
d41a53d
Update
shoumikhin Aug 3, 2026
e9abdd5
Update
shoumikhin Aug 3, 2026
d3ee68a
Update
shoumikhin Aug 3, 2026
8bfba13
Update
shoumikhin Aug 3, 2026
c0ebd90
Update
shoumikhin Aug 3, 2026
7e6e924
Update
shoumikhin Aug 3, 2026
d363b85
Update
shoumikhin Aug 3, 2026
2c3b441
Update
shoumikhin Aug 3, 2026
395f1bd
Update
shoumikhin Aug 3, 2026
217b18d
Update
shoumikhin Aug 3, 2026
b9eade5
Update
shoumikhin Aug 3, 2026
f5a9b97
Update
shoumikhin Aug 3, 2026
0799a55
Update
shoumikhin Aug 3, 2026
a10d1a5
Update
shoumikhin Aug 3, 2026
23d417d
Update
shoumikhin Aug 3, 2026
deb58fd
Update
shoumikhin Aug 3, 2026
012df50
Update
shoumikhin Aug 3, 2026
59bfbb4
Update
shoumikhin Aug 3, 2026
581fbf3
Update
shoumikhin Aug 3, 2026
7719af1
Update
shoumikhin Aug 3, 2026
cf57e58
Update
shoumikhin Aug 3, 2026
4bc4d6a
Update
shoumikhin Aug 4, 2026
3ad2b2c
Update
shoumikhin Aug 4, 2026
bae80e5
Update
shoumikhin Aug 4, 2026
9e3f0ac
Update
shoumikhin Aug 4, 2026
b1cb34f
Update
shoumikhin Aug 4, 2026
fb295cb
Update
shoumikhin Aug 4, 2026
bb1959c
Update
shoumikhin Aug 4, 2026
45f4588
Update
shoumikhin Aug 4, 2026
379613e
Update
shoumikhin Aug 4, 2026
88e4d64
Update
shoumikhin Aug 4, 2026
373d87b
Update
shoumikhin Aug 4, 2026
46fb7ec
Update
shoumikhin Aug 4, 2026
68fcf62
Update
shoumikhin Aug 4, 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
880 changes: 880 additions & 0 deletions .ci/scripts/wheel/test_cpp_sdk.py

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions .ci/scripts/wheel/test_linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
# LICENSE file in the root directory of this source tree.

import platform
import tempfile
from pathlib import Path

import test_base
import test_cpp_sdk
from examples.models import Backend, Model

if __name__ == "__main__":
Expand Down Expand Up @@ -41,6 +44,12 @@

test_base.test_cmsis_nn_install()

# The wheel ships a prebuilt C++ runtime and a CMake package config, so
# check that a standalone application can actually link and run against
# them, and that the process still has a single backend registry.
with tempfile.TemporaryDirectory() as work_dir:
test_cpp_sdk.run_tests(Path(work_dir))

test_base.run_tests(
model_tests=[
test_base.ModelTest(
Expand Down
10 changes: 10 additions & 0 deletions .ci/scripts/wheel/test_linux_aarch64.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.

import tempfile
from pathlib import Path

import test_base
import test_cpp_sdk
from examples.models import Backend, Model

if __name__ == "__main__":
Expand All @@ -26,6 +30,12 @@
), f"OpenvinoBackend not found in registered backends: {registered}"
print("✓ OpenvinoBackend is registered")

# The wheel ships a prebuilt C++ runtime and a CMake package config, so check
# that a standalone application can actually link and run against them, and
# that the process still has a single backend registry.
with tempfile.TemporaryDirectory() as work_dir:
test_cpp_sdk.run_tests(Path(work_dir))

test_base.run_tests(
model_tests=[
test_base.ModelTest(
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/build-wheels-aarch64-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ on:
paths:
- .ci/**/*
- .github/workflows/build-wheels-aarch64-linux.yml
- '**/CMakeLists.txt'
- examples/**/*
- pyproject.toml
- setup.py
- tools/cmake/**/*
push:
branches:
- nightly
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/build-wheels-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ on:
paths:
- .ci/**/*
- .github/workflows/build-wheels-linux.yml
- '**/CMakeLists.txt'
- examples/**/*
- pyproject.toml
- setup.py
- tools/cmake/**/*
push:
branches:
- nightly
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/build-wheels-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ on:
paths:
- .ci/**/*
- .github/workflows/build-wheels-macos.yml
- '**/CMakeLists.txt'
- examples/**/*
- pyproject.toml
- setup.py
- tools/cmake/**/*
push:
branches:
- nightly
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/build-wheels-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ on:
paths:
- .ci/**/*
- .github/workflows/build-wheels-windows.yml
- '**/CMakeLists.txt'
- examples/**/*
- pyproject.toml
- setup.py
- tools/cmake/**/*
push:
branches:
- nightly
Expand Down
205 changes: 137 additions & 68 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -778,11 +778,6 @@ if(EXECUTORCH_BUILD_OPENVINO)
list(APPEND _executorch_backends openvino_backend)
endif()

if(EXECUTORCH_BUILD_QNN)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/backends/qualcomm)
list(APPEND _executorch_backends qnn_executorch_backend)
endif()

if(EXECUTORCH_BUILD_ENN)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/backends/samsung)
list(APPEND _executorch_backends enn_backend)
Expand Down Expand Up @@ -932,6 +927,61 @@ if(EXECUTORCH_BUILD_PTHREADPOOL AND EXECUTORCH_BUILD_CPUINFO)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/extension/threadpool)
endif()

# Consolidated shared library: bundles executorch_core plus commonly used
# extensions into a single libexecutorch.so. Defined before the pybind and
# kernel targets below so they can link this one runtime instead of embedding a
# private copy of the core, which would give the process a second backend
# registry.
if(EXECUTORCH_BUILD_SHARED)
executorch_add_shared_library(executorch_shared)
set_target_properties(
executorch_shared
PROPERTIES OUTPUT_NAME executorch
ARCHIVE_OUTPUT_NAME executorch_shared
EXPORT_NAME executorch-shared
)
target_include_directories(
executorch_shared PUBLIC ${_common_include_directories}
)
target_compile_definitions(
executorch_shared PUBLIC C10_USING_CUSTOM_GENERATED_MACROS
)
# Link executorch without WHOLE_ARCHIVE because its INTERFACE link options
# (from executorch_target_link_options_shared_lib) already force
# whole-archive. Everything else is pulled in through link options rather than
# the WHOLE_ARCHIVE link feature, because these archives also reference each
# other plainly and CMake before 3.29 refuses to mix a feature with a plain
# reference to the same item.
target_link_libraries(executorch_shared PRIVATE executorch)
set(_executorch_shared_whole_archive executorch_core)
foreach(_ext_target
extension_data_loader extension_flat_tensor extension_named_data_map
extension_module_static extension_tensor
)
if(TARGET ${_ext_target})
list(APPEND _executorch_shared_whole_archive ${_ext_target})
endif()
endforeach()
foreach(_whole_target ${_executorch_shared_whole_archive})
executorch_target_whole_archive(executorch_shared ${_whole_target})
endforeach()
configure_file(
tools/cmake/executorch.pc.in ${CMAKE_CURRENT_BINARY_DIR}/executorch.pc
@ONLY
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/executorch.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
)
endif()

# Added after the shared runtime for readability, so the dependency reads in the
# order it exists. CMake resolves target names at generate time, so a reference
# from an earlier subdirectory would work too, as several other backends here do.
if(EXECUTORCH_BUILD_QNN)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/backends/qualcomm)
list(APPEND _executorch_backends qnn_executorch_backend)
endif()

if(EXECUTORCH_BUILD_KERNELS_TORCHAO)
if(NOT TARGET cpuinfo)
message(
Expand Down Expand Up @@ -1016,10 +1066,19 @@ if(EXECUTORCH_BUILD_PYBIND)
# Ensure bundled_module waits for bundled_program's generated headers
add_dependencies(bundled_module bundled_program)

target_link_libraries(bundled_module PRIVATE extension_data_loader)
target_link_libraries(
bundled_module PUBLIC extension_module_static bundled_program
)
# extension_module_static and the data loader are bundled into
# libexecutorch.so, so link that instead of pulling private static copies in
# through this target's PUBLIC interface.
if(EXECUTORCH_BUILD_SHARED)
target_link_libraries(
bundled_module PUBLIC executorch_shared bundled_program
)
else()
target_link_libraries(bundled_module PRIVATE extension_data_loader)
target_link_libraries(
bundled_module PUBLIC extension_module_static bundled_program
)
endif()

target_include_directories(
bundled_module PUBLIC ${_common_include_directories}
Expand All @@ -1038,16 +1097,36 @@ if(EXECUTORCH_BUILD_PYBIND)
TORCH_PYTHON_LIBRARY torch_python PATHS "${TORCH_INSTALL_PREFIX}/lib"
)

set(_dep_libs
${TORCH_PYTHON_LIBRARY}
bundled_program
etdump
flatccrt
executorch
extension_data_loader
util
torch
)
# When the consolidated shared runtime is built, the pybind extension links it
# instead of whole-archiving the static core, so Python and C++ consumers
# share one backend registry. `executorch` and the extensions bundled into
# libexecutorch.so must stay off this list: their INTERFACE link options force
# whole-archive, which would give this module a private second registry.
# executorch_shared is named here for its include directories and compile
# definitions; executorch_target_link_shared_runtime below is what fixes its
# position on the link line.
if(EXECUTORCH_BUILD_SHARED)
set(_dep_libs
${TORCH_PYTHON_LIBRARY}
bundled_program
etdump
flatccrt
executorch_shared
util
torch
)
else()
set(_dep_libs
${TORCH_PYTHON_LIBRARY}
bundled_program
etdump
flatccrt
executorch
extension_data_loader
util
torch
)
endif()

# Build common AOTI functionality if needed by CUDA or Metal backends
if(EXECUTORCH_BUILD_CUDA)
Expand All @@ -1058,13 +1137,24 @@ if(EXECUTORCH_BUILD_PYBIND)
list(APPEND _dep_libs aoti_common)
endif()

# RPATH for _portable_lib.so
# RPATH for _portable_lib.so. It sits in
# <site-packages>/executorch/extension/pybindings, so torch is three levels up
# and the wheel's own lib/ directory is two. The second entry is
# wheel-specific: a normal install puts the runtime in CMAKE_INSTALL_LIBDIR
# instead, where this relative path would not reach it.
set(_portable_lib_rpath "$ORIGIN/../../../torch/lib")
if(EXECUTORCH_BUILD_SHARED AND EXECUTORCH_BUILD_WHEEL_DO_NOT_USE)
string(APPEND _portable_lib_rpath ":$ORIGIN/../../lib")
endif()

if(EXECUTORCH_BUILD_EXTENSION_MODULE)
# Always use static linking for pybindings to avoid runtime symbol
# resolution issues
list(APPEND _dep_libs extension_module_static)
# extension_module_static is already bundled into libexecutorch.so; linking
# it again here would whole-archive a second copy.
if(NOT EXECUTORCH_BUILD_SHARED)
# Always use static linking for pybindings to avoid runtime symbol
# resolution issues
list(APPEND _dep_libs extension_module_static)
endif()
# Add bundled_module if available
if(TARGET bundled_module)
list(APPEND _dep_libs bundled_module)
Expand Down Expand Up @@ -1150,7 +1240,11 @@ if(EXECUTORCH_BUILD_PYBIND)
target_compile_definitions(util PUBLIC C10_USING_CUSTOM_GENERATED_MACROS)

target_compile_options(util PUBLIC ${_pybind_compile_options})
target_link_libraries(util PRIVATE torch c10 executorch extension_tensor)
if(EXECUTORCH_BUILD_SHARED)
target_link_libraries(util PRIVATE torch c10 executorch_shared)
else()
target_link_libraries(util PRIVATE torch c10 executorch extension_tensor)
endif()

# pybind portable_lib
pybind11_add_module(portable_lib SHARED extension/pybindings/pybindings.cpp)
Expand All @@ -1167,6 +1261,7 @@ if(EXECUTORCH_BUILD_PYBIND)
target_include_directories(portable_lib PRIVATE ${TORCH_INCLUDE_DIRS})
target_compile_options(portable_lib PUBLIC ${_pybind_compile_options})
target_link_libraries(portable_lib PRIVATE ${_dep_libs})
executorch_target_link_shared_runtime(portable_lib)

# Set RPATH to find PyTorch and backend libraries relative to the installation
# location. This goes from executorch/extension/pybindings up to
Expand Down Expand Up @@ -1199,7 +1294,24 @@ if(EXECUTORCH_BUILD_PYBIND)
strip_python_lib(data_loader)
target_include_directories(data_loader PRIVATE ${_common_include_directories})
target_compile_options(data_loader PUBLIC ${_pybind_compile_options})
target_link_libraries(data_loader PRIVATE executorch)
# This module only exposes a pybind type and calls into no runtime symbols.
# The static target force-links every registration object, which would give
# this module its own operator registry alongside the one in the shared
# runtime, so resolve against the shared runtime instead when there is one.
if(TARGET executorch_shared)
target_link_libraries(data_loader PRIVATE executorch_shared)
if(NOT APPLE AND EXECUTORCH_BUILD_WHEEL_DO_NOT_USE)
# Wheel-specific: this installs beside the other pybind extensions, two
# levels below the wheel's lib/ directory, so it needs the same relative
# path they use to reach the shared runtime.
set_target_properties(
data_loader PROPERTIES BUILD_RPATH "$ORIGIN/../../lib"
INSTALL_RPATH "$ORIGIN/../../lib"
)
endif()
else()
target_link_libraries(data_loader PRIVATE executorch)
endif()
install(TARGETS data_loader
LIBRARY DESTINATION executorch/extension/pybindings
)
Expand Down Expand Up @@ -1246,49 +1358,6 @@ if(EXECUTORCH_BUILD_KERNELS_LLM)
list(APPEND _executorch_kernels custom_ops_aot_lib)
endif()

# Consolidated shared library: bundles executorch_core plus commonly used
# extensions into a single libexecutorch.so.
if(EXECUTORCH_BUILD_SHARED)
executorch_add_shared_library(executorch_shared)
set_target_properties(
executorch_shared
PROPERTIES OUTPUT_NAME executorch
ARCHIVE_OUTPUT_NAME executorch_shared
EXPORT_NAME executorch-shared
)
target_include_directories(
executorch_shared PUBLIC ${_common_include_directories}
)
target_compile_definitions(
executorch_shared PUBLIC C10_USING_CUSTOM_GENERATED_MACROS
)
# Link executorch without WHOLE_ARCHIVE because its INTERFACE link options
# (from executorch_target_link_options_shared_lib) already force
# whole-archive. Link executorch_core explicitly since executorch only has a
# PRIVATE dep on it (symbols wouldn't propagate otherwise).
target_link_libraries(
executorch_shared PRIVATE executorch
$<LINK_LIBRARY:WHOLE_ARCHIVE,executorch_core>
)
foreach(_ext_target
extension_data_loader extension_flat_tensor extension_named_data_map
extension_module_static extension_tensor
)
if(TARGET ${_ext_target})
target_link_libraries(
executorch_shared PRIVATE $<LINK_LIBRARY:WHOLE_ARCHIVE,${_ext_target}>
)
endif()
endforeach()
configure_file(
tools/cmake/executorch.pc.in ${CMAKE_CURRENT_BINARY_DIR}/executorch.pc
@ONLY
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/executorch.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
)
endif()

if(EXECUTORCH_BUILD_KERNELS_QUANTIZED)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/kernels/quantized)
executorch_target_link_options_shared_lib(quantized_ops_lib)
Expand Down
Loading
Loading