Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .ci/scripts/wheel/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def run_tests(model_tests: List[ModelTest]) -> None:
# Test that we can import the portable_lib module - verifies RPATH is correct
print("Testing portable_lib import...")
try:
from executorch.extension.pybindings._portable_lib import ( # noqa: F401
from executorch.extension.pybindings._C import ( # noqa: F401
_load_for_executorch,
)

Expand Down
10 changes: 4 additions & 6 deletions .ci/scripts/wheel/test_shared_libraries.py
Original file line number Diff line number Diff line change
Expand Up @@ -899,7 +899,7 @@ def test_python_extensions_import() -> None:
add_library(custom_op_check SHARED custom_op.cpp)
# The legacy contract: a custom-op library links the shipped Python extension,
# which owns the operator registry it registers into.
target_link_libraries(custom_op_check PRIVATE _portable_lib)
target_link_libraries(custom_op_check PRIVATE _C)
# The runtime headers include c10 headers, which belong to torch rather than to
# this wheel, so an out-of-tree operator project supplies them the same way it
# supplies torch itself. The package config does not and should not ship them.
Expand Down Expand Up @@ -1150,7 +1150,7 @@ def test_custom_op_compiles(work_dir: Path) -> None:
return

package_dir = _installed_package_dir()
if not list(package_dir.glob("extension/pybindings/_portable_lib*")):
if not list(package_dir.glob("extension/pybindings/_C*")):
print("- the wheel ships no Python extension, skipping the custom op check")
return

Expand Down Expand Up @@ -1531,10 +1531,8 @@ def test_extension_contains_no_component() -> None:
return

package_dir = _installed_package_dir()
extensions = sorted(
(package_dir / "extension" / "pybindings").glob("_portable_lib.*.so")
)
assert len(extensions) == 1, f"expected one _portable_lib, found {extensions}"
extensions = sorted((package_dir / "extension" / "pybindings").glob("_C.*.so"))
assert len(extensions) == 1, f"expected one _C, found {extensions}"
extension = extensions[0]

lib_dir = package_dir / "lib"
Expand Down
40 changes: 20 additions & 20 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -461,8 +461,8 @@ if(EXECUTORCH_BUILD_PTHREADPOOL)
if(APPLE)
# Use hidden visibility for pthreadpool on Apple platforms to avoid issues
# with pthreadpool symbols from libtorch_cpu taking precedence over the ones
# from the pthreadpool library statically linked in _portable_lib. The
# pthreadpool public APIs are marked as weak by default on some Apple
# from the pthreadpool library statically linked in the Python extension.
# The pthreadpool public APIs are marked as weak by default on some Apple
# platforms, so setting to hidden visibility works around this by not
# putting the symbol in the indirection table. See
# https://github.com/pytorch/executorch/issues/14321 for more details.
Expand Down Expand Up @@ -1189,19 +1189,19 @@ if(EXECUTORCH_BUILD_PYBIND)
list(APPEND _dep_libs aoti_common)
endif()

# RPATH for _portable_lib.so. It sits in
# RPATH for the Python extension. It sits in
# <site-packages>/executorch/extension/pybindings, so torch is three levels up
# and the wheel's own lib/ directory is two. Mach-O spells the loader relative
# token differently and takes a list rather than a colon joined string, so
# both differ here while the layout reasoning does not.
if(APPLE)
set(_portable_lib_origin "@loader_path")
set(_portable_lib_rpath_separator ";")
set(_python_extension_origin "@loader_path")
set(_python_extension_rpath_separator ";")
else()
set(_portable_lib_origin "$ORIGIN")
set(_portable_lib_rpath_separator ":")
set(_python_extension_origin "$ORIGIN")
set(_python_extension_rpath_separator ":")
endif()
set(_portable_lib_rpath "${_portable_lib_origin}/../../../torch/lib")
set(_python_extension_rpath "${_python_extension_origin}/../../../torch/lib")

if(EXECUTORCH_BUILD_EXTENSION_MODULE)
# extension_module_static is already bundled into libexecutorch.so; linking
Expand Down Expand Up @@ -1253,17 +1253,17 @@ if(EXECUTORCH_BUILD_PYBIND)
if(EXECUTORCH_BUILD_CUDA)
string(
APPEND
_portable_lib_rpath
"${_portable_lib_rpath_separator}${_portable_lib_origin}/../../backends/cuda"
_python_extension_rpath
"${_python_extension_rpath_separator}${_python_extension_origin}/../../backends/cuda"
)
endif()

if(EXECUTORCH_BUILD_QNN)
list(APPEND _dep_libs qnn_executorch_backend)
string(
APPEND
_portable_lib_rpath
"${_portable_lib_rpath_separator}${_portable_lib_origin}/../../backends/qualcomm"
_python_extension_rpath
"${_python_extension_rpath_separator}${_python_extension_origin}/../../backends/qualcomm"
)
endif()

Expand Down Expand Up @@ -1326,10 +1326,10 @@ if(EXECUTORCH_BUILD_PYBIND)
# portable_lib.py in the same python package. PyTorch requires C++20, so
# pybindings must be compiled with C++20.
set_target_properties(
portable_lib PROPERTIES OUTPUT_NAME "_portable_lib" CXX_STANDARD 20
portable_lib PROPERTIES OUTPUT_NAME "_C" CXX_STANDARD 20
)
target_compile_definitions(
portable_lib PUBLIC EXECUTORCH_PYTHON_MODULE_NAME=_portable_lib
portable_lib PUBLIC EXECUTORCH_PYTHON_MODULE_NAME=_C
)
target_include_directories(portable_lib PRIVATE ${TORCH_INCLUDE_DIRS})
target_compile_options(portable_lib PUBLIC ${_pybind_compile_options})
Expand Down Expand Up @@ -1366,8 +1366,8 @@ if(EXECUTORCH_BUILD_PYBIND)
# libtorch_cpu.dylib'
else()
set_target_properties(
portable_lib PROPERTIES BUILD_RPATH "${_portable_lib_rpath}"
INSTALL_RPATH "${_portable_lib_rpath}"
portable_lib PROPERTIES BUILD_RPATH "${_python_extension_rpath}"
INSTALL_RPATH "${_python_extension_rpath}"
)
endif()
executorch_target_shared_runtime_path(
Expand Down Expand Up @@ -1404,10 +1404,10 @@ if(EXECUTORCH_BUILD_PYBIND)
LIBRARY DESTINATION executorch/extension/pybindings
)

# Copy MLX metallib next to _portable_lib.so for editable installs. MLX uses
# dladdr() to find the directory containing the library with MLX code, then
# looks for mlx.metallib in that directory. When MLX is statically linked into
# _portable_lib.so, we need the metallib colocated with it.
# Copy the MLX metallib next to the Python extension for editable installs.
# MLX uses dladdr() to find the directory containing the library with MLX
# code, then looks for mlx.metallib in that directory. When MLX is statically
# linked into the Python extension, we need the metallib colocated with it.
executorch_target_copy_mlx_metallib(portable_lib)
endif()

Expand Down
4 changes: 2 additions & 2 deletions backends/cuda/runtime/platform/platform.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
Expand Down Expand Up @@ -75,14 +75,14 @@

#else
// Before loading the delegate .so, we need to ensure symbols from the current
// process (e.g., _portable_lib.so) are globally visible. Python loads modules
// process (e.g. the Python extension) are globally visible. Python loads modules
// with RTLD_LOCAL by default, so we re-open the current module with
// RTLD_GLOBAL | RTLD_NOLOAD to promote its symbols to global visibility.
// This allows the delegate .so to resolve symbols like aoti_torch_dtype_*.
static std::once_flag symbols_promoted_flag;
std::call_once(symbols_promoted_flag, []() {
Dl_info info;
// Get info about a symbol we know exists in _portable_lib.so
// Get info about a symbol we know exists in the Python extension
if (dladdr((void*)&load_library, &info) && info.dli_fname) {
// Re-open with RTLD_GLOBAL | RTLD_NOLOAD to promote symbols
void* handle =
Expand Down
8 changes: 4 additions & 4 deletions backends/mlx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -339,16 +339,16 @@ install(
# exist)
#
# where {binary_dir} is determined at runtime via dladdr() on the library
# containing MLX code. When MLX is statically linked into _portable_lib.so, this
# is the directory containing _portable_lib.so.
# containing MLX code. When MLX is statically linked into _C.so, this is the
# directory containing _C.so.
#
# For the installed library, we put metallib in lib/ alongside libmlx.a. The
# metallib is produced in the mlx_external build tree (MLX_METAL_JIT=ON does not
# install it); _mlx_metallib points there.
install(FILES ${_mlx_metallib} DESTINATION ${CMAKE_INSTALL_LIBDIR})

# Cache the metallib path for pybindings to copy it next to _portable_lib.so
# This enables editable installs to work correctly
# Cache the metallib path for pybindings to copy it next to _C.so This enables
# editable installs to work correctly
set(MLX_METALLIB_PATH
"${_mlx_metallib}"
CACHE INTERNAL "Path to mlx.metallib for pybindings"
Expand Down
10 changes: 5 additions & 5 deletions extension/pybindings/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ fbcode_target(_kind = runtime.genrule,
outs = {
"aten_lib.pyi": ["aten_lib.pyi"],
"core.pyi": ["core.pyi"],
"_portable_lib.pyi": ["_portable_lib.pyi"],
"_C.pyi": ["_C.pyi"],
},
cmd = "cp $(location :pybinding_types)/* $OUT/_portable_lib.pyi && cp $(location :pybinding_types)/* $OUT/aten_lib.pyi && cp $(location :pybinding_types)/* $OUT/core.pyi",
cmd = "cp $(location :pybinding_types)/* $OUT/_C.pyi && cp $(location :pybinding_types)/* $OUT/aten_lib.pyi && cp $(location :pybinding_types)/* $OUT/core.pyi",
visibility = ["//executorch/extension/pybindings/..."],
)

Expand All @@ -50,8 +50,8 @@ fbcode_target(_kind = executorch_pybindings,
fbcode_target(_kind = executorch_pybindings,
cppdeps = PORTABLE_MODULE_DEPS + MODELS_ATEN_OPS_LEAN_MODE_GENERATED_LIB,
# Give this an underscore prefix because it has a pure python wrapper.
python_module_name = "_portable_lib",
types = ["//executorch/extension/pybindings:pybindings_types_gen[_portable_lib.pyi]"],
python_module_name = "_C",
types = ["//executorch/extension/pybindings:pybindings_types_gen[_C.pyi]"],
visibility = ["PUBLIC"],
)

Expand All @@ -67,7 +67,7 @@ fbcode_target(_kind = runtime.python_library,
srcs = ["portable_lib.py"],
visibility = ["PUBLIC"],
deps = [
":_portable_lib",
":_C",
"//executorch/exir:_warnings",
],
)
Expand Down
6 changes: 3 additions & 3 deletions extension/pybindings/portable_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@
e,
)

# Let users import everything from the C++ _portable_lib extension as if this
# Let users import everything from the C++ _C extension as if this
# python file defined them. Although we could import these dynamically, it
# wouldn't preserve the static type annotations.
#
# Note that all of these are experimental, and subject to change without notice.
from executorch.extension.pybindings._portable_lib import ( # noqa: F401
from executorch.extension.pybindings._C import ( # noqa: F401
# Disable "imported but unused" (F401) checks.
_create_profile_block, # noqa: F401
_dump_profile_results, # noqa: F401
Expand All @@ -101,7 +101,7 @@
Verification, # noqa: F401
)

# Clean up so that `dir(portable_lib)` is the same as `dir(_portable_lib)`
# Clean up so that `dir(portable_lib)` is the same as `dir(_C)`
# (apart from some __dunder__ names).
del _torch
del _exir_warnings
Expand Down
2 changes: 1 addition & 1 deletion extension/pybindings/test/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fbcode_target(

fbcode_target(
_kind = runtime.python_test,
name = "test_pybindings_portable_lib",
name = "test_pybindings_C",
srcs = ["test_pybindings.py"],
preload_deps = ["//executorch/kernels/quantized:aot_lib"],
deps = [
Expand Down
28 changes: 14 additions & 14 deletions kernels/quantized/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -126,20 +126,20 @@ if(NOT CMAKE_GENERATOR STREQUAL "Xcode"
)

# pip wheels will need to be able to find the dependent libraries. On
# Linux, the .so has non-absolute dependencies on libs like
# "_portable_lib.so" without paths; as long as we `import torch` first,
# those dependencies will work. But Apple dylibs do not support
# non-absolute dependencies, so we need to tell the loader where to look
# for its libraries. The LC_LOAD_DYLIB entries for the portable_lib
# libraries will look like "@rpath/_portable_lib.cpython-310-darwin.so",
# so we can add an LC_RPATH entry to look in a directory relative to the
# installed location of our _portable_lib.so file. To see these LC_*
# values, run `otool -l libquantized_ops_lib.dylib`. "extension", not
# "extensions": the plural directory does not exist, so the parent's path
# reached nothing and this library could not find the extension it needs.
# torch is three directories up from here, and this library links it
# directly, so the hop has to be recorded or the only route is the
# absolute path from the build machine.
# Linux, the .so has non-absolute dependencies on libs like "_C.so"
# without paths; as long as we `import torch` first, those dependencies
# will work. But Apple dylibs do not support non-absolute dependencies, so
# we need to tell the loader where to look for its libraries. The
# LC_LOAD_DYLIB entries for the portable_lib libraries will look like
# "@rpath/_C.cpython-310-darwin.so", so we can add an LC_RPATH entry to
# look in a directory relative to the installed location of our _C.so
# file. To see these LC_* values, run `otool -l
# libquantized_ops_lib.dylib`. "extension", not "extensions": the plural
# directory does not exist, so the parent's path reached nothing and this
# library could not find the extension it needs. torch is three
# directories up from here, and this library links it directly, so the hop
# has to be recorded or the only route is the absolute path from the build
# machine.
if(APPLE)
set(RPATH
"@loader_path/../../extension/pybindings;@loader_path/../../../torch/lib"
Expand Down
2 changes: 1 addition & 1 deletion runtime/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
)
except ModuleNotFoundError as e:
raise ModuleNotFoundError(
"Prebuilt <site-packages>/extension/pybindings/_portable_lib.so "
"Prebuilt <site-packages>/extension/pybindings/_C.so "
"is not found. Please reinstall ExecuTorch from pip."
) from e

Expand Down
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -1997,8 +1997,8 @@ def run(self): # noqa C901
# portable kernels, and a selection of backends. This lets users
# load and execute .pte files from python.
BuiltExtension(
src="_portable_lib.cp*" if _is_windows() else "_portable_lib.*",
modpath="executorch.extension.pybindings._portable_lib",
src="_C.cp*" if _is_windows() else "_C.*",
modpath="executorch.extension.pybindings._C",
dependent_cmake_flags=["EXECUTORCH_BUILD_PYBIND"],
),
# Install the data_loader pybindings extension which provides the
Expand All @@ -2008,7 +2008,7 @@ def run(self): # noqa C901
modpath="executorch.extension.pybindings.data_loader",
dependent_cmake_flags=["EXECUTORCH_BUILD_PYBIND"],
),
# MLX metallib (Metal GPU kernels) must be colocated with _portable_lib.so
# MLX metallib (Metal GPU kernels) must be colocated with _C.so
# because MLX uses dladdr() to find the directory containing the library,
# then looks for mlx.metallib in that directory at runtime.
# After submodule migration, the path is backends/mlx/mlx/...
Expand Down
12 changes: 6 additions & 6 deletions shim_et/xplat/executorch/codegen/codegen.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ def copy_files(genrule_name, target, file_list):
default_outs = ["."],
)

def get_portable_lib_deps():
def get_C_deps():
return [
"//executorch/kernels/portable/cpu:math_constants",
"//executorch/kernels/portable/cpu:scalar_utils",
Expand Down Expand Up @@ -569,7 +569,7 @@ def build_portable_header_lib(name, oplist_header_name, feature = None, **kwargs
**kwargs
)

def build_portable_lib(
def build_C(
name,
et_operator_lib_deps = [],
oplist_header_name = None,
Expand Down Expand Up @@ -651,7 +651,7 @@ def build_portable_lib(
name = name,
srcs = portable_source_files,
exported_preprocessor_flags = ["-DEXECUTORCH_SELECTIVE_BUILD_DTYPE"],
deps = get_portable_lib_deps() + [":" + portable_header_lib],
deps = get_C_deps() + [":" + portable_header_lib],
compiler_flags = compiler_flags,
# WARNING: using a deprecated API to avoid being built into a shared
# library. In the case of dynamically loading so library we don't want
Expand Down Expand Up @@ -710,7 +710,7 @@ def build_optimized_lib(name, oplist_header_name, portable_header_lib, feature =
# sleef needs to be added as a direct dependency of the operator target when building for Android,
# or a linker error may occur. Not sure why this happens; it seems that platform deps of
# dependencies are not transitive
deps = get_portable_lib_deps() + get_optimized_lib_deps() + [":" + portable_header_lib] + select({
deps = get_C_deps() + get_optimized_lib_deps() + [":" + portable_header_lib] + select({
"ovr_config//os:android-arm64": [
"fbsource//third-party/sleef:sleef",
],
Expand Down Expand Up @@ -1038,8 +1038,8 @@ def executorch_generated_lib(
kernel_deps.remove("//executorch/kernels/portable:operators")

# Build portable lib.
portable_lib_name = name + "_portable_lib"
build_portable_lib(name = portable_lib_name, portable_header_lib = portable_header_lib, feature = feature, expose_operator_symbols = expose_operator_symbols, platforms = platforms)
portable_lib_name = name + "_C"
build_C(name = portable_lib_name, portable_header_lib = portable_header_lib, feature = feature, expose_operator_symbols = expose_operator_symbols, platforms = platforms)
kernel_deps.append(":{}".format(portable_lib_name))

if "//executorch/kernels/optimized:optimized_operators" in kernel_deps:
Expand Down
Loading
Loading