diff --git a/CMakeLists.txt b/CMakeLists.txt index 418b6704..55278a91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ set(CMAKE_CXX_FLAGS_DEBUG ${SYMENGINE_CXX_FLAGS_DEBUG}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SYMENGINE_CXX_FLAGS}") include_directories(${SYMENGINE_INCLUDE_DIRS}) +set(WITH_PY_LIMITED_API OFF CACHE STRING "Use CPython's limited API") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") find_package(Python REQUIRED) find_package(Cython REQUIRED) diff --git a/cmake/FindPython.cmake b/cmake/FindPython.cmake index 52539cb7..b0ff460f 100644 --- a/cmake/FindPython.cmake +++ b/cmake/FindPython.cmake @@ -38,15 +38,17 @@ message(STATUS "Python version: ${PYTHON_VERSION}") string(REPLACE "." "" PYTHON_VERSION_WITHOUT_DOTS ${PYTHON_VERSION}) if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - FIND_LIBRARY(PYTHON_LIBRARY NAMES - python${PYTHON_VERSION} - python${PYTHON_VERSION}m - python${PYTHON_VERSION_WITHOUT_DOTS} - PATHS ${PYTHON_LIB_PATH} ${PYTHON_PREFIX_PATH}/lib ${PYTHON_PREFIX_PATH}/libs - PATH_SUFFIXES ${CMAKE_LIBRARY_ARCHITECTURE} - NO_DEFAULT_PATH - NO_SYSTEM_ENVIRONMENT_PATH - ) + if (WITH_PY_LIMITED_API) + set(PYTHON_LIBRARY_NAMES python3) + else() + set(PYTHON_LIBRARY_NAMES python${PYTHON_VERSION} python${PYTHON_VERSION}m python${PYTHON_VERSION_WITHOUT_DOTS}) + endif() + FIND_LIBRARY(PYTHON_LIBRARY NAMES ${PYTHON_LIBRARY_NAMES} + PATHS ${PYTHON_LIB_PATH} ${PYTHON_PREFIX_PATH}/lib ${PYTHON_PREFIX_PATH}/libs + PATH_SUFFIXES ${CMAKE_LIBRARY_ARCHITECTURE} + NO_DEFAULT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + ) endif() execute_process( @@ -64,6 +66,12 @@ execute_process( ) string(STRIP ${PYTHON_EXTENSION_SOABI_tmp} PYTHON_EXTENSION_SOABI_tmp) +if (WITH_PY_LIMITED_API) + if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + set(PYTHON_EXTENSION_SOABI_tmp ".abi3") + endif() +endif() + set(PYTHON_EXTENSION_SOABI ${PYTHON_EXTENSION_SOABI_tmp} CACHE STRING "Suffix for python extensions") @@ -130,4 +138,9 @@ macro(ADD_PYTHON_LIBRARY name) target_link_libraries(${name} ${PYTHON_LIBRARY}) set_target_properties(${name} PROPERTIES SUFFIX ".pyd") ENDIF() + IF(WITH_PY_LIMITED_API) + target_compile_definitions(${name} PRIVATE + Py_LIMITED_API=${WITH_PY_LIMITED_API} + CYTHON_LIMITED_API=1) + ENDIF() endmacro(ADD_PYTHON_LIBRARY) diff --git a/setup.py b/setup.py index 1c5e9207..6af03109 100644 --- a/setup.py +++ b/setup.py @@ -65,6 +65,7 @@ def get_build_dir(dist): ('build-type=', None, 'build type: Release or Debug'), ('define=', 'D', 'options to cmake :='), + ('py-limited-api=', None, 'Use Py_LIMITED_API with given version.'), ] def _process_define(arg): @@ -91,6 +92,7 @@ def initialize_options(self): self.symengine_dir = None self.generator = None self.build_type = "Release" + self.py_limited_api = None def finalize_options(self): _build_ext.finalize_options(self) @@ -122,6 +124,13 @@ def cmake_build(self): cmake_cmd.extend(process_opts(cmake_opts)) if not path.exists(path.join(build_dir, "CMakeCache.txt")): cmake_cmd.extend(self.get_generator()) + + if self.py_limited_api: + assert self.py_limited_api.startswith("cp3") + py_ver_minor = int(self.py_limited_api[3:]) + h = 3 * 16**6 + py_ver_minor * 16**4 + cmake_cmd.append(f"-DWITH_PY_LIMITED_API={h}") + if subprocess.call(cmake_cmd, cwd=build_dir) != 0: raise OSError("error calling cmake")