From d3145f5d67571f159ffc53d5f4b84d3562a11073 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Thu, 23 Oct 2025 12:04:01 +0900 Subject: [PATCH] Support ABI3 Signed-off-by: take-cheeze --- .github/workflows/build-and-test.yml | 5 +++++ .gitmodules | 3 +++ CMakeLists.txt | 9 +++++--- cmake/utils.cmake | 2 +- onnxoptimizer/cpp2py_export.cc | 31 +++++++++++++++++++--------- setup.py | 14 ++++++++++++- third_party/nanobind | 1 + 7 files changed, 50 insertions(+), 15 deletions(-) create mode 160000 third_party/nanobind diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 25fa754e1..a25ba0171 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -46,6 +46,11 @@ jobs: submodules: recursive - name: Build wheels uses: pypa/cibuildwheel@v3.2.0 + - name: Check ABI3 + run: | + pip install abi3audit + abi3audit --strict -v --report ./wheelhouse/*.whl + if: ${{ contains(fromJSON('["cp312", "cp313"]'), matrix.python) }} - uses: actions/upload-artifact@v4 with: name: artifact-${{ matrix.os }}-${{ matrix.python }} diff --git a/.gitmodules b/.gitmodules index d2486290e..017d2b0d3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "third_party/protobuf"] path = third_party/protobuf url = https://github.com/protocolbuffers/protobuf.git +[submodule "third_party/nanobind"] + path = third_party/nanobind + url = https://github.com/wjakob/nanobind.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 988c9a3f3..e723fb0b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,9 +67,12 @@ target_include_directories(onnx_optimizer_c_api PUBLIC ) if(ONNX_BUILD_PYTHON) - find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module) - find_package(pybind11) - pybind11_add_module(onnx_opt_cpp2py_export "onnxoptimizer/cpp2py_export.cc") + find_package( + Python 3 + REQUIRED COMPONENTS Interpreter Development.Module + OPTIONAL_COMPONENTS Development.SABIModule) + add_subdirectory(third_party/nanobind EXCLUDE_FROM_ALL) + nanobind_add_module(onnx_opt_cpp2py_export "onnxoptimizer/cpp2py_export.cc" STABLE_ABI) target_link_libraries(onnx_opt_cpp2py_export PRIVATE onnx_optimizer) endif() diff --git a/cmake/utils.cmake b/cmake/utils.cmake index 6cca9f364..2ec8e06ca 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -3,7 +3,7 @@ include(${PROJECT_SOURCE_DIR}/third_party/onnx/cmake/Utils.cmake) # Poor man's FetchContent function(add_subdirectory_if_no_target dir target) if (NOT TARGET ${target}) - add_subdirectory(${dir}) + add_subdirectory(${dir} EXCLUDE_FROM_ALL) endif() endfunction() diff --git a/onnxoptimizer/cpp2py_export.cc b/onnxoptimizer/cpp2py_export.cc index 04d2cd1d7..fea4e55e1 100644 --- a/onnxoptimizer/cpp2py_export.cc +++ b/onnxoptimizer/cpp2py_export.cc @@ -2,39 +2,50 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include -#include +#include +#include +#include -#include "onnx/py_utils.h" #include "onnxoptimizer/model_util.h" #include "onnxoptimizer/optimize.h" namespace ONNX_NAMESPACE { -namespace py = pybind11; -using namespace pybind11::literals; -PYBIND11_MODULE(onnx_opt_cpp2py_export, onnx_opt_cpp2py_export) { +namespace nb = nanobind; +using namespace nanobind::literals; + +template +bool ParseProtoFromPyBytes(Proto* proto, const nb::bytes& bytes) { + // Get the buffer from Python bytes object + char* buffer = nullptr; + Py_ssize_t length = 0; + PyBytes_AsStringAndSize(bytes.ptr(), &buffer, &length); + + return ParseProtoFromBytes(proto, buffer, length); +} + +NB_MODULE(onnx_opt_cpp2py_export, onnx_opt_cpp2py_export) { onnx_opt_cpp2py_export.doc() = "ONNX Optimizer"; onnx_opt_cpp2py_export.def( "optimize", - [](const py::bytes& bytes, const std::vector& names) { + [](const nb::bytes& bytes, const std::vector& names) { ModelProto proto{}; ParseProtoFromPyBytes(&proto, bytes); auto const result = optimization::Optimize(proto, names); std::string out; result.SerializeToString(&out); - return py::bytes(out); + return nb::bytes(out.data(), out.size()); }); onnx_opt_cpp2py_export.def( "optimize_fixedpoint", - [](const py::bytes& bytes, const std::vector& names) { + [](const nb::bytes& bytes, const std::vector& names) { ModelProto proto{}; ParseProtoFromPyBytes(&proto, bytes); auto const result = optimization::OptimizeFixed(proto, names); std::string out; result.SerializeToString(&out); - return py::bytes(out); + return nb::bytes(out.data(), out.size()); }); onnx_opt_cpp2py_export.def( diff --git a/setup.py b/setup.py index 8c7ac1896..9df9fb606 100644 --- a/setup.py +++ b/setup.py @@ -288,10 +288,21 @@ def run(self): # Extensions ################################################################################ +py_limited_api = sys.version_info[0] >= 3 and sys.version_info[1] >= 12 +if py_limited_api: + setup_opts = { + 'bdist_wheel': { + 'py_limited_api': 'cp312' + }, + } +else: + setup_opts = {} + ext_modules = [ setuptools.Extension( name=str('onnxoptimizer.onnx_opt_cpp2py_export'), - sources=[]) + sources=[], + py_limited_api=py_limited_api) ] ################################################################################ @@ -348,4 +359,5 @@ def run(self): 'onnxoptimizer=onnxoptimizer:main', ], }, + options=setup_opts, ) diff --git a/third_party/nanobind b/third_party/nanobind new file mode 160000 index 000000000..ab3456fc0 --- /dev/null +++ b/third_party/nanobind @@ -0,0 +1 @@ +Subproject commit ab3456fc06c483e3a824c91da7b5955882cac442