From e7fc6c376b94e0969ef755365efe7dac86b12135 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Thu, 2 May 2024 04:39:24 -0400 Subject: [PATCH] build: enable Python limited API (#2215) Closes #1997. Closes #2202. ## Summary by CodeRabbit - **New Features** - Added support for Python 3.9 on macOS and Windows platforms. - Introduced new build configurations for better integration and compatibility. - **Bug Fixes** - Removed unsupported Python 3.8 configurations for certain platforms to ensure compatibility. - **Refactor** - Updated minimum required CMake version to improve build stability and performance. - Streamlined Python API settings in build configurations for enhanced functionality. - **Documentation** - Updated build and wheel repair commands in documentation to reflect current support and configurations. --------- Signed-off-by: Jinzhe Zeng --- .github/workflows/wheel.yml | 45 ----------------------------------- CMakeLists.txt | 19 ++++++++++----- pyproject.toml | 18 +++++++++++--- reacnetgenerator/dps.pyx | 14 +++++++---- reacnetgenerator/utils_np.pyx | 1 + 5 files changed, 39 insertions(+), 58 deletions(-) diff --git a/.github/workflows/wheel.yml b/.github/workflows/wheel.yml index 054503089..4c1d0b460 100644 --- a/.github/workflows/wheel.yml +++ b/.github/workflows/wheel.yml @@ -22,62 +22,17 @@ jobs: matrix: include: # linux-64 - - os: ubuntu-latest - python: 37 - platform_id: manylinux_x86_64 - os: ubuntu-latest python: 38 platform_id: manylinux_x86_64 - - os: ubuntu-latest - python: 39 - platform_id: manylinux_x86_64 - - os: ubuntu-latest - python: 310 - platform_id: manylinux_x86_64 - - os: ubuntu-latest - python: 311 - platform_id: manylinux_x86_64 - - os: ubuntu-latest - python: 312 - platform_id: manylinux_x86_64 # macos-x86-64 - - os: macos-latest - python: 37 - platform_id: macosx_x86_64 - - os: macos-latest - python: 38 - platform_id: macosx_universal2 - os: macos-latest python: 39 platform_id: macosx_universal2 - - os: macos-latest - python: 310 - platform_id: macosx_universal2 - - os: macos-latest - python: 311 - platform_id: macosx_universal2 - - os: macos-latest - python: 312 - platform_id: macosx_universal2 # win-64 - - os: windows-2019 - python: 37 - platform_id: win_amd64 - os: windows-2019 python: 38 platform_id: win_amd64 - - os: windows-2019 - python: 39 - platform_id: win_amd64 - - os: windows-2019 - python: 310 - platform_id: win_amd64 - - os: windows-2019 - python: 311 - platform_id: win_amd64 - - os: windows-2019 - python: 312 - platform_id: win_amd64 steps: - uses: actions/checkout@v4 - name: Build wheels diff --git a/CMakeLists.txt b/CMakeLists.txt index 05efb5728..386fe3a50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,9 @@ -cmake_minimum_required(VERSION 3.18...3.28) +cmake_minimum_required(VERSION 3.26...3.28) project(${SKBUILD_PROJECT_NAME} LANGUAGES C CXX) find_package( Python - COMPONENTS Interpreter Development.Module + COMPONENTS Interpreter Development.SABIModule # NumPy REQUIRED) @@ -52,10 +52,16 @@ add_custom_command( VERBATIM) python_add_library( - dps MODULE ${CMAKE_CURRENT_BINARY_DIR}/dps.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/reacnetgenerator/c_stack.cpp WITH_SOABI) + dps + MODULE + USE_SABI + 3.7 + ${CMAKE_CURRENT_BINARY_DIR}/dps.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/reacnetgenerator/c_stack.cpp + WITH_SOABI) target_include_directories(dps PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/reacnetgenerator) +target_compile_definitions(dps PRIVATE CYTHON_LIMITED_API=1) if(CMAKE_BUILD_TYPE STREQUAL "Debug") target_compile_definitions(dps PRIVATE CYTHON_TRACE=1 CYTHON_TRACE_NOGIL=1) endif() @@ -73,9 +79,10 @@ if(FALSE) DEPENDS reacnetgenerator/utils_np.pyx VERBATIM) - python_add_library(utils_np MODULE ${CMAKE_CURRENT_BINARY_DIR}/utils_np.c - WITH_SOABI) + python_add_library(utils_np MODULE USE_SABI 3.11 + ${CMAKE_CURRENT_BINARY_DIR}/utils_np.c WITH_SOABI) target_link_libraries(utils_np PRIVATE Python::NumPy) + target_compile_definitions(utils_np PRIVATE CYTHON_LIMITED_API=1) if(CMAKE_BUILD_TYPE STREQUAL "Debug") target_compile_definitions(utils_np PRIVATE CYTHON_TRACE=1 CYTHON_TRACE_NOGIL=1) diff --git a/pyproject.toml b/pyproject.toml index 544841eee..57921e802 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,10 +2,10 @@ requires = [ "scikit-build-core>=0.9.0", # "oldest-supported-numpy; python_version < '3.9'", - "numpy>=2.0.0rc0; python_version >= '3.9'", + # "numpy>=2.0.0rc0; python_version >= '3.9'", "nodejs-wheel~=20.9", "pyyaml", - "cython>=0.16", + "cython>=3.0.1", ] build-backend = "scikit_build_core.build" @@ -100,10 +100,11 @@ docs = [ [tool.scikit-build] minimum-version = "0.9" +wheel.py-api = "cp37" metadata.version.provider = "scikit_build_core.metadata.setuptools_scm" sdist.include = ["reacnetgenerator/_version.py"] sdist.exclude = ["reacnetgenerator/static/webpack/"] -cmake.version = ">=3.18" +cmake.version = ">=3.26" [tool.setuptools_scm] write_to = "reacnetgenerator/_version2.py" @@ -118,6 +119,17 @@ before-test = ["python -m pip install replace-pip-with-uv-pip"] [tool.cibuildwheel.linux] environment-pass = ["CIBW_BUILD"] +# Use abi3audit to catch issues with Limited API wheels +repair-wheel-command = [ + "auditwheel repair -w {dest_dir} {wheel}", + "pipx run abi3audit --strict --report {wheel}", +] + +[tool.cibuildwheel.macos] +repair-wheel-command = [ + "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}", + "pipx run abi3audit --strict --report {wheel}", +] [tool.pyright] include = [ diff --git a/reacnetgenerator/dps.pyx b/reacnetgenerator/dps.pyx index c6bbdfa29..b73393ca9 100644 --- a/reacnetgenerator/dps.pyx +++ b/reacnetgenerator/dps.pyx @@ -6,6 +6,8 @@ """Connect molecule with Depth-First Search.""" from libc.stdlib cimport free, malloc +import cython + cdef extern from "c_stack.h": # This function is copied from https://zhuanlan.zhihu.com/p/38212302 @@ -14,6 +16,7 @@ cdef extern from "c_stack.h": int pop() +@cython.binding(False) def dps(bonds, levels): """Connect molecule with Depth-First Search. @@ -35,7 +38,7 @@ def dps(bonds, levels): bondlist = [] cdef int _N = len(bonds) cdef int *visited = malloc(_N * sizeof(int)) - cdef int i, s, b_c, l + cdef int i, s, b_c, ll, ib, nb cdef C_Stack st for i in range(_N): visited[i]=0 @@ -52,11 +55,13 @@ def dps(bonds, levels): elif visited[s]==1: continue mol.append(s) - for b, l in zip(bonds[s], levels[s]): + nb = len(bonds[s]) + for ib in range(nb): + b = bonds[s][ib] + ll = levels[s][ib] b_c = b if visited[b_c]==0: - # bond.append((s, b, l) if i < b else (b, s, l)) - bond.append((s, b, l) if s < b else (b, s, l)) + bond.append((s, b, ll) if s < b else (b, s, ll)) st.push(b_c) visited[s]=1 mol.sort() @@ -67,6 +72,7 @@ def dps(bonds, levels): return molecule, bondlist +@cython.binding(False) def dps_reaction(reactdict): """Find A+B->C+D reactions. diff --git a/reacnetgenerator/utils_np.pyx b/reacnetgenerator/utils_np.pyx index 0a4db110e..e2141d67c 100644 --- a/reacnetgenerator/utils_np.pyx +++ b/reacnetgenerator/utils_np.pyx @@ -15,6 +15,7 @@ DTYPE8 = np.int8 ctypedef np.int8_t DTYPE8_t +@cython.binding(False) @cython.boundscheck(False) @cython.wraparound(False) cpdef idx_to_signal(DTYPE_t[:] idx, int step):