From 2e85e5f832ee75251a998023d028ea07988685d0 Mon Sep 17 00:00:00 2001 From: Max Bachmann Date: Sat, 21 Sep 2024 18:29:36 +0200 Subject: [PATCH] Port build system to scikit-build-core (#397) --- .github/workflows/branchbuild.yml | 1 + CHANGELOG.rst | 15 ++-- CMakeLists.txt | 2 +- MANIFEST.in | 30 -------- _custom_build/backend.py | 98 --------------------------- pyproject.toml | 91 +++++++++++++++++++++++-- setup.py | 87 ------------------------ src/rapidfuzz/CMakeLists.txt | 28 ++++---- src/rapidfuzz/__init__.py | 2 +- src/rapidfuzz/distance/CMakeLists.txt | 25 ++++--- tools/sdist.patch | 13 ++-- 11 files changed, 134 insertions(+), 258 deletions(-) delete mode 100644 MANIFEST.in delete mode 100644 _custom_build/backend.py delete mode 100644 setup.py diff --git a/.github/workflows/branchbuild.yml b/.github/workflows/branchbuild.yml index 844c1ef7..ca581fc7 100644 --- a/.github/workflows/branchbuild.yml +++ b/.github/workflows/branchbuild.yml @@ -148,6 +148,7 @@ jobs: submodules: 'true' - uses: "actions/setup-python@v5" with: + allow-prereleases: true python-version: "${{ matrix.python-version }}" - name: build diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7de15c31..7291b9a6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,13 +1,19 @@ Changelog --------- +[3.10.0] - 2024-09-21 +^^^^^^^^^^^^^^^^^^^^^ +Fixed +~~~~~ +- drop support for Python 3.8 +- switch build system to `scikit-build-core` + [3.9.7] - 2024-09-02 ^^^^^^^^^^^^^^^^^^^^ Fixed -~~~~~~~ +~~~~~ * fix crash in ``cdist`` due to Visual Studio upgrade - [3.9.6] - 2024-08-06 ^^^^^^^^^^^^^^^^^^^^ Changed @@ -41,14 +47,12 @@ Fixed ~~~~~ * fix supported versions of taskflow in cmake to be in the range v3.3 - v3.7 - [3.9.1] - 2024-05-19 ^^^^^^^^^^^^^^^^^^^^ Fixed ~~~~~ * disable AVX2 on MacOS since it did lead to illegal instructions being generated - [3.9.0] - 2024-05-02 ^^^^^^^^^^^^^^^^^^^^ Changed @@ -59,14 +63,12 @@ Fixed ~~~~~ * fix cmake version parsing - [3.8.1] - 2024-04-07 ^^^^^^^^^^^^^^^^^^^^ Fixed ~~~~~ * use the correct version of ``rapidfuzz-cpp`` when building against a system installed version - [3.8.0] - 2024-04-06 ^^^^^^^^^^^^^^^^^^^^ Added @@ -78,7 +80,6 @@ Fixed - fix some minor errors in the type hints - fix potentially incorrect results of JaroWinkler when using high prefix weights - [3.7.0] - 2024-03-21 ^^^^^^^^^^^^^^^^^^^^ Changed diff --git a/CMakeLists.txt b/CMakeLists.txt index d6466e6c..a734f181 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.12...3.29) +cmake_minimum_required(VERSION 3.15...3.30) set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) set(CMAKE_POSITION_INDEPENDENT_CODE ON) diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 211ea2bc..00000000 --- a/MANIFEST.in +++ /dev/null @@ -1,30 +0,0 @@ -include MANIFEST.in -include setup.py -include CHANGELOG.rst -include CMakeLists.txt -include README.md -include LICENSE -include pyproject.toml -include _custom_build/backend.py -include src/rapidfuzz/py.typed -recursive-include src/rapidfuzz *.pyi - -recursive-include src/rapidfuzz CMakeLists.txt -recursive-include cmake * -recursive-include src/rapidfuzz *.hpp *.h *.cpp *.cxx *.pyx *.pxd -recursive-include tests * -recursive-include docs * -include src/rapidfuzz/__init__.pxd -include src/rapidfuzz/rapidfuzz.h - -include extern/rapidfuzz-cpp/LICENSE -include extern/rapidfuzz-cpp/CMakeLists.txt -recursive-include extern/rapidfuzz-cpp/rapidfuzz *.hpp *.impl - -include extern/taskflow/LICENSE -include extern/taskflow/CMakeLists.txt -include extern/taskflow/TaskflowConfig.cmake.in -include extern/taskflow/taskflow/algorithm/* -include extern/taskflow/taskflow/core/* -include extern/taskflow/taskflow/utility/* -include extern/taskflow/taskflow/taskflow.hpp diff --git a/_custom_build/backend.py b/_custom_build/backend.py deleted file mode 100644 index 1212afe3..00000000 --- a/_custom_build/backend.py +++ /dev/null @@ -1,98 +0,0 @@ -from __future__ import annotations - -import platform as _platform -import subprocess as _subprocess - -from packaging import version as _version -from packaging.tags import sys_tags as _sys_tags -from setuptools import build_meta as _orig -from skbuild.cmaker import get_cmake_version as _get_cmake_version -from skbuild.exceptions import SKBuildError as _SKBuildError - -prepare_metadata_for_build_wheel = _orig.prepare_metadata_for_build_wheel -build_wheel = _orig.build_wheel -build_sdist = _orig.build_sdist -get_requires_for_build_sdist = _orig.get_requires_for_build_sdist - -cmake_wheels = { - "win_amd64", - "win_arm64", - "win32", - "musllinux_1_1_x86_64", - "musllinux_1_1_s390x", - "musllinux_1_1_ppc64le", - "musllinux_1_1_i686", - "musllinux_1_1_aarch64", - "manylinux_2_17_s390x", - "manylinux_2_17_ppc64le", - "manylinux_2_17_aarch64", - "manylinux_2_17_x86_64", - "manylinux_2_17_i686", - "manylinux_2_12_x86_64", - "manylinux_2_12_i686", - "macosx_10_10_universal2", -} - -ninja_wheels = { - "win_amd64", - "win_arm64", - "win32", - "musllinux_1_1_x86_64", - "musllinux_1_1_s390x", - "musllinux_1_1_ppc64le", - "musllinux_1_1_i686", - "musllinux_1_1_aarch64", - "manylinux_2_17_s390x", - "manylinux_2_17_ppc64le", - "manylinux_2_17_aarch64", - "manylinux_2_5_x86_64", - "manylinux_2_5_i686", - "macosx_10_9_universal2", -} - - -def _cmake_required(): - try: - if _version.parse(_get_cmake_version().split("-")[0]) >= _version.parse("3.12"): - print("Using System version of cmake") - return False - except _SKBuildError: - pass - - for tag in _sys_tags(): - if tag.platform in cmake_wheels: - return True - - print("No cmake wheel available on platform") - return False - - -def _ninja_required(): - if _platform.system() == "Windows": - print("Ninja is part of the MSVC installation on Windows") - return False - - for generator in ("ninja", "make"): - try: - _subprocess.check_output([generator, "--version"]) - print(f"Using System version of {generator}") - return False - except (OSError, _subprocess.CalledProcessError): - pass - - for tag in _sys_tags(): - if tag.platform in ninja_wheels: - return True - - print("No Ninja wheel available on platform") - return False - - -def get_requires_for_build_wheel(config_settings=None): - packages = [] - if _cmake_required(): - packages.append("cmake") - if _ninja_required(): - packages.append("ninja") - - return _orig.get_requires_for_build_wheel(config_settings) + packages diff --git a/pyproject.toml b/pyproject.toml index fd738178..efff1059 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,11 +1,94 @@ [build-system] requires = [ - "setuptools>=42", - "scikit-build~=0.18.0", + "scikit-build-core>=0.10.7", "Cython >=3.0.11, <3.1.0" ] -build-backend = "backend" -backend-path = ["_custom_build"] +build-backend = "scikit_build_core.build" + +[project] +name = "RapidFuzz" +dynamic = ["version"] +requires-python = ">= 3.9" +authors = [ + {name = "Max Bachmann", email = "pypi@maxbachmann.de"}, +] +description = "rapid fuzzy string matching" +readme = "README.md" +classifiers=[ + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "License :: OSI Approved :: MIT License", +] +Homepage = "https://github.com/rapidfuzz/RapidFuzz" +Documentation = "https://rapidfuzz.github.io/RapidFuzz/" +Repository = "https://github.com/rapidfuzz/RapidFuzz.git" +Issues = "https://github.com/rapidfuzz/RapidFuzz/issues" +Changelog = "https://github.com/rapidfuzz/RapidFuzz/blob/main/CHANGELOG.rst" + +[project.optional-dependencies] +all = [ + "numpy" +] + +[project.entry-points.pyinstaller40] +hook-dirs = "rapidfuzz.__pyinstaller:get_hook_dirs" +tests = "rapidfuzz.__pyinstaller:get_PyInstaller_tests" + +[tool.scikit-build] +minimum-version = "build-system.requires" +sdist.include = [ + "src/rapidfuzz/*.cxx", + "src/rapidfuzz/distance/*.cxx", +] +sdist.exclude = [ + ".github" +] +wheel.exclude = [ + "**.pyx", + "**.cxx", + "**.pxd", + "**.cpp", + "**.hpp", + "**.h", + "CMakeLists.txt", + "generate.sh" +] +wheel.packages = ["src/rapidfuzz"] +wheel.cmake = false +messages.after-success = "{yellow}Cmake unavailable, falling back to pure Python Extension" + +[[tool.scikit-build.overrides]] +if.any.system-cmake = ">=3.15" +if.any.cmake-wheel = true +wheel.cmake = true +messages.after-success = "{green}C++ Extension built successfully" + +[[tool.scikit-build.overrides]] +if.failed = true +if.env.CIBUILDWHEEL = false +if.env.CONDA_BUILD = false +if.env.PIWHEELS_BUILD = false +if.env.RAPIDFUZZ_BUILD_EXTENSION = false +wheel.cmake = false +messages.after-success = "{yellow}Failed to build C++ Extension, falling back to pure Python Extension" + +[[tool.scikit-build.overrides]] +if.any.env.CIBUILDWHEEL = true +if.any.env.CONDA_BUILD = true +if.any.env.PIWHEELS_BUILD = true +if.any.env.RAPIDFUZZ_BUILD_EXTENSION = true +wheel.cmake = true +messages.after-success = "{green}C++ Extension built successfully" +messages.after-failure = "{red}Failed to build C++ Extension in a packaged build" + +[tool.scikit-build.metadata.version] +provider = "scikit_build_core.metadata.regex" +input = "src/rapidfuzz/__init__.py" + [tool.black] line-length = 120 diff --git a/setup.py b/setup.py deleted file mode 100644 index 1c185a2f..00000000 --- a/setup.py +++ /dev/null @@ -1,87 +0,0 @@ -from __future__ import annotations - -import os - - -def show_message(*lines): - print("=" * 74) - for line in lines: - print(line) - print("=" * 74) - - -with open("README.md", encoding="utf8") as f: - readme = f.read() - -setup_args = { - "name": "rapidfuzz", - "version": "3.9.7", - "extras_require": {"full": ["numpy"]}, - "url": "https://github.com/rapidfuzz/RapidFuzz", - "author": "Max Bachmann", - "author_email": "pypi@maxbachmann.de", - "description": "rapid fuzzy string matching", - "long_description": readme, - "long_description_content_type": "text/markdown", - "license": "MIT", - "classifiers": [ - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "License :: OSI Approved :: MIT License", - ], - "packages": ["rapidfuzz", "rapidfuzz.distance", "rapidfuzz.__pyinstaller"], - "entry_points": { - "pyinstaller40": [ - "hook-dirs = rapidfuzz.__pyinstaller:get_hook_dirs", - "tests = rapidfuzz.__pyinstaller:get_PyInstaller_tests", - ], - }, - "package_dir": { - "": "src", - }, - "package_data": { - "rapidfuzz": ["*.pyi", "py.typed", "__init__.pxd", "rapidfuzz.h"], - "rapidfuzz.distance": ["*.pyi"], - }, - "python_requires": ">=3.9", -} - - -def run_setup(with_binary): - if with_binary: - from skbuild import setup - - setup(**setup_args) - else: - from setuptools import setup - - setup(**setup_args) - - -# when packaging only build wheels which include the C extension -packaging = "1" in { - os.environ.get("CIBUILDWHEEL", "0"), - os.environ.get("CONDA_BUILD", "0"), - os.environ.get("PIWHEELS_BUILD", "0"), - os.environ.get("RAPIDFUZZ_BUILD_EXTENSION", "0"), -} -if packaging: - run_setup(True) -else: - try: - run_setup(True) - except BaseException: - show_message( - "WARNING: The C extension could not be compiled, speedups are not enabled.", - "Failure information, if any, is above.", - "Retrying the build without the C extension now.", - ) - run_setup(False) - show_message( - "WARNING: The C extension could not be compiled, speedups are not enabled.", - "Plain-Python build succeeded.", - ) diff --git a/src/rapidfuzz/CMakeLists.txt b/src/rapidfuzz/CMakeLists.txt index 2e7a3549..a4bfbba3 100644 --- a/src/rapidfuzz/CMakeLists.txt +++ b/src/rapidfuzz/CMakeLists.txt @@ -4,13 +4,17 @@ function(create_cython_target _name) ${CMAKE_CURRENT_LIST_DIR}/${_name}.cxx PARENT_SCOPE) else() - find_package(Cython REQUIRED) - # should use target_include_directories once this is supported by - # scikit-build - include_directories(${RF_BASE_DIR}/rapidfuzz) - add_cython_target(${_name} CXX) + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${_name}.cxx" + MAIN_DEPENDENCY "${CMAKE_CURRENT_LIST_DIR}/${_name}.pyx" + VERBATIM + COMMAND + Python::Interpreter -m cython "${CMAKE_CURRENT_LIST_DIR}/${_name}.pyx" + --cplus -I "${CMAKE_CURRENT_LIST_DIR}" + --output-file "${CMAKE_CURRENT_BINARY_DIR}/${_name}.cxx") + set(${_name} - ${_name} + ${CMAKE_CURRENT_BINARY_DIR}/${_name}.cxx PARENT_SCOPE) endif() endfunction(create_cython_target) @@ -39,7 +43,7 @@ if(RAPIDFUZZ_ARCH_X64 OR RAPIDFUZZ_ARCH_X86) target_include_directories(_feature_detector_cpp PRIVATE ${RF_BASE_DIR}/rapidfuzz) target_link_libraries(_feature_detector_cpp PRIVATE rapidfuzz::rapidfuzz) - install(TARGETS _feature_detector_cpp LIBRARY DESTINATION src/rapidfuzz) + install(TARGETS _feature_detector_cpp DESTINATION rapidfuzz) endif() create_cython_target(utils_cpp) @@ -47,14 +51,14 @@ rf_add_library(utils_cpp ${utils_cpp} ${CMAKE_CURRENT_LIST_DIR}/utils.cpp) target_compile_features(utils_cpp PUBLIC cxx_std_17) target_include_directories(utils_cpp PRIVATE ${RF_BASE_DIR}/rapidfuzz) target_link_libraries(utils_cpp PRIVATE rapidfuzz::rapidfuzz) -install(TARGETS utils_cpp LIBRARY DESTINATION src/rapidfuzz) +install(TARGETS utils_cpp DESTINATION rapidfuzz) create_cython_target(fuzz_cpp) rf_add_library(fuzz_cpp ${fuzz_cpp}) target_compile_features(fuzz_cpp PUBLIC cxx_std_17) target_include_directories(fuzz_cpp PRIVATE ${RF_BASE_DIR}/rapidfuzz) target_link_libraries(fuzz_cpp PRIVATE rapidfuzz::rapidfuzz) -install(TARGETS fuzz_cpp LIBRARY DESTINATION src/rapidfuzz) +install(TARGETS fuzz_cpp DESTINATION rapidfuzz) if(RAPIDFUZZ_ARCH_X64 OR RAPIDFUZZ_ARCH_X86) # on macOs this generates illegal instructions @@ -72,7 +76,7 @@ if(RAPIDFUZZ_ARCH_X64 OR RAPIDFUZZ_ARCH_X86) target_include_directories(fuzz_cpp_avx2 PRIVATE ${RF_BASE_DIR}/rapidfuzz) target_link_libraries(fuzz_cpp_avx2 PRIVATE rapidfuzz::rapidfuzz) - install(TARGETS fuzz_cpp_avx2 LIBRARY DESTINATION src/rapidfuzz) + install(TARGETS fuzz_cpp_avx2 DESTINATION rapidfuzz) endif() endif() @@ -89,7 +93,7 @@ if(RAPIDFUZZ_ARCH_X86) target_include_directories(fuzz_cpp_sse2 PRIVATE ${RF_BASE_DIR}/rapidfuzz) target_link_libraries(fuzz_cpp_sse2 PRIVATE rapidfuzz::rapidfuzz) - install(TARGETS fuzz_cpp_sse2 LIBRARY DESTINATION src/rapidfuzz) + install(TARGETS fuzz_cpp_sse2 DESTINATION rapidfuzz) endif() create_cython_target(process_cpp_impl) @@ -185,4 +189,4 @@ if(NOT Windows) endif() endif() -install(TARGETS process_cpp_impl LIBRARY DESTINATION src/rapidfuzz) +install(TARGETS process_cpp_impl DESTINATION rapidfuzz) diff --git a/src/rapidfuzz/__init__.py b/src/rapidfuzz/__init__.py index 66e10fa8..63e5062a 100644 --- a/src/rapidfuzz/__init__.py +++ b/src/rapidfuzz/__init__.py @@ -6,7 +6,7 @@ __author__: str = "Max Bachmann" __license__: str = "MIT" -__version__: str = "3.9.7" +__version__: str = "3.10.0" from rapidfuzz import distance, fuzz, process, utils diff --git a/src/rapidfuzz/distance/CMakeLists.txt b/src/rapidfuzz/distance/CMakeLists.txt index e9350911..59f7cbc7 100644 --- a/src/rapidfuzz/distance/CMakeLists.txt +++ b/src/rapidfuzz/distance/CMakeLists.txt @@ -4,14 +4,17 @@ function(create_cython_target _name) ${CMAKE_CURRENT_LIST_DIR}/${_name}.cxx PARENT_SCOPE) else() - find_package(Cython REQUIRED) - # should use target_include_directories once this is supported by - # scikit-build - include_directories(${RF_BASE_DIR}/rapidfuzz - ${RF_BASE_DIR}/rapidfuzz/distance) - add_cython_target(${_name} CXX) + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${_name}.cxx" + MAIN_DEPENDENCY "${CMAKE_CURRENT_LIST_DIR}/${_name}.pyx" + VERBATIM + COMMAND + Python::Interpreter -m cython "${CMAKE_CURRENT_LIST_DIR}/${_name}.pyx" + --cplus -I "${CMAKE_CURRENT_LIST_DIR}/.." + --output-file "${CMAKE_CURRENT_BINARY_DIR}/${_name}.cxx") + set(${_name} - ${_name} + ${CMAKE_CURRENT_BINARY_DIR}/${_name}.cxx PARENT_SCOPE) endif() endfunction(create_cython_target) @@ -39,7 +42,7 @@ target_include_directories( _initialize_cpp PRIVATE ${RF_BASE_DIR}/rapidfuzz ${RF_BASE_DIR}/rapidfuzz/distance) target_link_libraries(_initialize_cpp PRIVATE rapidfuzz::rapidfuzz) -install(TARGETS _initialize_cpp LIBRARY DESTINATION src/rapidfuzz/distance) +install(TARGETS _initialize_cpp DESTINATION rapidfuzz/distance) create_cython_target(metrics_cpp) rf_add_library(metrics_cpp ${metrics_cpp}) @@ -48,7 +51,7 @@ target_include_directories( metrics_cpp PRIVATE ${RF_BASE_DIR}/rapidfuzz ${RF_BASE_DIR}/rapidfuzz/distance) target_link_libraries(metrics_cpp PRIVATE rapidfuzz::rapidfuzz) -install(TARGETS metrics_cpp LIBRARY DESTINATION src/rapidfuzz/distance) +install(TARGETS metrics_cpp DESTINATION rapidfuzz/distance) if(RAPIDFUZZ_ARCH_X64 OR RAPIDFUZZ_ARCH_X86) # on macOs this generates illegal instructions @@ -69,7 +72,7 @@ if(RAPIDFUZZ_ARCH_X64 OR RAPIDFUZZ_ARCH_X86) metrics_cpp_avx2 PRIVATE ${RF_BASE_DIR}/rapidfuzz ${RF_BASE_DIR}/rapidfuzz/distance) target_link_libraries(metrics_cpp_avx2 PRIVATE rapidfuzz::rapidfuzz) - install(TARGETS metrics_cpp_avx2 LIBRARY DESTINATION src/rapidfuzz/distance) + install(TARGETS metrics_cpp_avx2 DESTINATION rapidfuzz/distance) endif() endif() @@ -89,5 +92,5 @@ if(RAPIDFUZZ_ARCH_X86) metrics_cpp_sse2 PRIVATE ${RF_BASE_DIR}/rapidfuzz ${RF_BASE_DIR}/rapidfuzz/distance) target_link_libraries(metrics_cpp_sse2 PRIVATE rapidfuzz::rapidfuzz) - install(TARGETS metrics_cpp_sse2 LIBRARY DESTINATION src/rapidfuzz/distance) + install(TARGETS metrics_cpp_sse2 DESTINATION rapidfuzz/distance) endif() diff --git a/tools/sdist.patch b/tools/sdist.patch index 2c7610c8..cc463ec2 100644 --- a/tools/sdist.patch +++ b/tools/sdist.patch @@ -1,14 +1,13 @@ diff --git a/pyproject.toml b/pyproject.toml -index 77671b1..7692f90 100644 +index 517f32d..1e855ed 100644 --- a/pyproject.toml +++ b/pyproject.toml -@@ -1,8 +1,7 @@ +@@ -1,7 +1,6 @@ [build-system] requires = [ - "setuptools>=42", -- "scikit-build~=0.18.0", +- "scikit-build-core>=0.10.7", - "Cython >=3.0.11, <3.1.0" -+ "scikit-build~=0.18.0" ++ "scikit-build-core>=0.10.7" ] - build-backend = "backend" - backend-path = ["_custom_build"] + build-backend = "scikit_build_core.build" +