From ec01f745353e9c4aa9cbb5edcd91d8661dc13899 Mon Sep 17 00:00:00 2001 From: Bradley Lowekamp Date: Thu, 4 Dec 2025 12:29:05 -0500 Subject: [PATCH] Rewrite to use scikit-build-core Removed setup.py, and replaced with PEP 517 build-system. Refactored CMakeLists.txt to reduce number of external projects and directly install via CODE from the SimpleITK Python project. --- CMakeLists.txt | 407 +++++++++++++++++++++---------------------------- README.md | 141 +++++++++-------- pyproject.toml | 59 ++++++- setup.py | 46 ------ 4 files changed, 307 insertions(+), 346 deletions(-) delete mode 100644 setup.py diff --git a/CMakeLists.txt b/CMakeLists.txt index ca2f6c6..525bf76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,8 +3,8 @@ cmake_minimum_required(VERSION 3.26) project(SimpleITKPythonPackage NONE) -if(NOT DEFINED SimpleITKPythonPackage_SUPERBUILD) - set(SimpleITKPythonPackage_SUPERBUILD 1) +if(DEFINED SimpleITKPythonPackage_SUPERBUILD) + message(FATAL_ERROR "The SimpleITKPythonPackage_SUPERBUILD is no longer supported. Please refer to the SuperBuild CMakeLists.txt file to build SimpleITK Python packages.") endif() # Set a default build type if none was specified @@ -21,258 +21,203 @@ if(NOT DEFINED SimpleITK_SOURCE_DIR) set(SimpleITK_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/SimpleITK") endif() -if(SimpleITKPythonPackage_SUPERBUILD) - set(ep_common_cmake_cache_args) - if(NOT CMAKE_CONFIGURATION_TYPES) - list(APPEND ep_common_cmake_cache_args - -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} - ) - endif() - - #----------------------------------------------------------------------------- - # Options - option ( SimpleITK_PYTHON_THREADS "Enable threaded python usage by unlocking the GIL." ON ) - mark_as_advanced( SimpleITK_PYTHON_THREADS ) - - # - # When building different "flavor" of SimpleITK python packages on a given platform, - # explicitly setting the following options allow to speed up package generation by - # re-using existing resources. - # - # SimpleITK_SOURCE_DIR: Path to an existing source directory - # - # SWIG_EXECUTABLE: Path to an existing executable - # - # SimpleITK_DIR: Path to an existing SimpleITK build or install directory - # - - option ( SimpleITKPythonPackage_BUILD_PYTHON "Build SimpleITK python module" ON ) - mark_as_advanced( SimpleITKPythonPackage_BUILD_PYTHON ) - - # compile with multiple processors - include(ProcessorCount) - ProcessorCount(NPROC) - if (NOT NPROC EQUAL 0) - set( ENV{MAKEFLAGS} "-j${NPROC}" ) - endif() - - #----------------------------------------------------------------------------- - include(ExternalProject) - - # Add an empty external project - function(sitk_ExternalProject_Add_Empty proj depends) - set(depends_args) - if(NOT depends STREQUAL "") - set(depends_args DEPENDS ${depends}) - endif() - ExternalProject_add(${proj} - SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj} - DOWNLOAD_COMMAND "" - UPDATE_COMMAND "" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - BUILD_IN_SOURCE 1 - BUILD_ALWAYS 1 - INSTALL_COMMAND "" - ${depends_args} - ) - endfunction() - - - #----------------------------------------------------------------------------- - # A separate project is used to download SimpleITK, so that the SuperBuild - # subdirectory can be use for SimpleITK's SuperBuild to build the - # required Lua, GTest etc. - - # Sanity checks - if(DEFINED SimpleITK_SOURCE_DIR AND NOT EXISTS ${SimpleITK_SOURCE_DIR}) - message(FATAL_ERROR "SimpleITK_SOURCE_DIR variable is defined but corresponds to nonexistent directory: \"${SimpleITK_SOURCE_DIR}\"") - endif() - - message(STATUS "SuperBuild - SimpleITK_SOURCE_DIR: ${SimpleITK_SOURCE_DIR}") - - #----------------------------------------------------------------------------- - # SimpleITK "Core" libraries: This is the SimpleITK Superbuild project - # that build all the tools needed (GTest, PCRE, Swig, Lua & GTest) and - # then SimpleITK "core" libraries. - - message(STATUS "SuperBuild - SimpleITK-superbuild") - - # Sanity checks - if(DEFINED SimpleITK_DIR AND NOT EXISTS ${SimpleITK_DIR}) - message(FATAL_ERROR "SimpleITK_DIR variable is defined but corresponds to nonexistent directory") - endif() - if(DEFINED SWIG_EXECUTABLE AND NOT EXISTS ${SWIG_EXECUTABLE}) - message(FATAL_ERROR "SWIG_EXECUTABLE variable is defined but corresponds to nonexistent file") - endif() - - if(NOT DEFINED SimpleITK_DIR AND NOT DEFINED SWIG_EXECUTABLE) - - set(SimpleITK_SUPERBUILD_DIR ${CMAKE_BINARY_DIR}/sitk-sb) - - ExternalProject_add(SimpleITK-superbuild - SOURCE_DIR ${SimpleITK_SOURCE_DIR}/SuperBuild - BINARY_DIR ${SimpleITK_SUPERBUILD_DIR} - DOWNLOAD_COMMAND "" - UPDATE_COMMAND "" - CMAKE_CACHE_ARGS - ${ep_common_cmake_cache_args} - -DBUILD_EXAMPLES:BOOL=OFF - -DBUILD_TESTING:BOOL=OFF - -DBUILD_DOXYGEN:BOOL=OFF - -DWRAP_DEFAULT:BOOL=OFF - -DSimpleITK_INSTALL_DOC_DIR:STRING=SimpleITK - -DSimpleITK_BUILD_STRIP:BOOL=ON - -DSimpleITK_BUILD_DISTRIBUTE:BOOL=ON - -DSimpleITK_GIT_PROTOCOL:STRING=https - -DSKBUILD:BOOL=${SKBUILD} - USES_TERMINAL_CONFIGURE 1 - USES_TERMINAL_BUILD 1 - INSTALL_COMMAND "" - ) - - set(SimpleITK_DIR ${SimpleITK_SUPERBUILD_DIR}/SimpleITK-build) - set(ITK_DIR ${SimpleITK_SUPERBUILD_DIR}/ITK-prefix/lib/cmake/ITK) - if(WIN32) - set(SWIG_EXECUTABLE ${SimpleITK_SUPERBUILD_DIR}/swigwin/swig.exe) - else() - set(SWIG_EXECUTABLE ${SimpleITK_SUPERBUILD_DIR}/Swig/bin/swig) - endif() - else() - - sitk_ExternalProject_Add_Empty( - SimpleITK-superbuild - ) - - endif() - - message(STATUS "SuperBuild - SimpleITK_DIR: ${SimpleITK_DIR}") - message(STATUS "SuperBuild - ITK_DIR: ${ITK_DIR}") - message(STATUS "SuperBuild - SWIG_EXECUTABLE: ${SWIG_EXECUTABLE}") - - - #----------------------------------------------------------------------------- - if(NOT SimpleITKPythonPackage_BUILD_PYTHON) - return() - endif() - - - #----------------------------------------------------------------------------- - # Search for python interpreter and libraries - - message(STATUS "SuperBuild - Searching for python") - - if ( PYTHON_VERSION_STRING VERSION_GREATER_EQUAL "3.11.0") - - set(_SimpleITK_PYTHON_USE_LIMITED_API_DEFAULT ON) - else () - set(_SimpleITK_PYTHON_USE_LIMITED_API_DEFAULT OFF) - endif() - option( SimpleITK_PYTHON_USE_LIMITED_API "Use Python limited API, for minor version compatibility." ${_SimpleITK_PYTHON_USE_LIMITED_API_DEFAULT} ) - - # Sanity checks - if(DEFINED PYTHON_INCLUDE_DIR AND NOT EXISTS ${PYTHON_INCLUDE_DIR}) - message(FATAL_ERROR "PYTHON_INCLUDE_DIR variable is defined but corresponds to nonexistent directory") - endif() - if(DEFINED PYTHON_LIBRARY AND NOT EXISTS ${PYTHON_LIBRARY}) - message(FATAL_ERROR "PYTHON_LIBRARY variable is defined but corresponds to nonexistent file") - endif() - if(DEFINED PYTHON_EXECUTABLE AND NOT EXISTS ${PYTHON_EXECUTABLE}) - message(FATAL_ERROR "PYTHON_EXECUTABLE variable is defined but corresponds to nonexistent file") - endif() - - if(NOT DEFINED PYTHON_INCLUDE_DIR - OR NOT DEFINED PYTHON_LIBRARY - OR NOT DEFINED PYTHON_EXECUTABLE) - - find_package ( PythonLibs REQUIRED ) - find_package ( PythonInterp REQUIRED ) - - endif() - - message(STATUS "SuperBuild - PYTHON_INCLUDE_DIR: ${PYTHON_INCLUDE_DIR}") - message(STATUS "SuperBuild - PYTHON_LIBRARY: ${PYTHON_LIBRARY}") - message(STATUS "SuperBuild - PYTHON_EXECUTABLE: ${PYTHON_EXECUTABLE}") - - - #----------------------------------------------------------------------------- - # SimpleITK Python module: This project build only the SimpleITK python - # module. - - message(STATUS "SuperBuild - SimpleITK-python => Requires SimpleITK-superbuild") - - set(SimpleITK_PYTHON_DIR "${CMAKE_BINARY_DIR}/SimpleITK-python") - - ExternalProject_add(SimpleITK-python - SOURCE_DIR ${SimpleITK_SOURCE_DIR}/Wrapping/Python - BINARY_DIR ${SimpleITK_PYTHON_DIR} +set(ep_common_cmake_cache_args) +if(NOT CMAKE_CONFIGURATION_TYPES) + list(APPEND ep_common_cmake_cache_args + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + ) +endif() + + +#----------------------------------------------------------------------------- +# Options +option ( SimpleITK_PYTHON_THREADS "Enable threaded python usage by unlocking the GIL." ON ) +mark_as_advanced( SimpleITK_PYTHON_THREADS ) + +# +# When building different "flavor" of SimpleITK python packages on a given platform, +# explicitly setting the following options allow to speed up package generation by +# re-using existing resources. +# +# SimpleITK_SOURCE_DIR: Path to an existing source directory +# +# SWIG_EXECUTABLE: Path to an existing executable +# +# SimpleITK_DIR: Path to an existing SimpleITK build or install directory +# + +option ( SimpleITKPythonPackage_BUILD_PYTHON "Build SimpleITK python module" ON ) +mark_as_advanced( SimpleITKPythonPackage_BUILD_PYTHON ) + +# compile with multiple processors +include(ProcessorCount) +ProcessorCount(NPROC) +if (NOT NPROC EQUAL 0) + set( ENV{MAKEFLAGS} "-j${NPROC}" ) +endif() + +# Find SWIG executable - should be provided by the build environment +find_package ( SWIG ) +if ( NOT SWIG_FOUND ) + message(FATAL_ERROR "SWIG executable not found. Please set SWIG_EXECUTABLE variable to point to a valid SWIG executable.") +endif() +message(STATUS "SuperBuild - Found SWIG_EXECUTABLE: ${SWIG_EXECUTABLE}") +message(STATUS "SuperBuild - SWIG_VERSION: ${SWIG_VERSION}") + +#----------------------------------------------------------------------------- +include(ExternalProject) + +#----------------------------------------------------------------------------- + +# Sanity checks +if(DEFINED SimpleITK_SOURCE_DIR AND NOT EXISTS ${SimpleITK_SOURCE_DIR}) + message(FATAL_ERROR "SimpleITK_SOURCE_DIR variable is defined but corresponds to nonexistent directory: \"${SimpleITK_SOURCE_DIR}\"") +endif() + +message(STATUS "SuperBuild - SimpleITK_SOURCE_DIR: ${SimpleITK_SOURCE_DIR}") + +#----------------------------------------------------------------------------- +# SimpleITK "Core" libraries: This is the SimpleITK Superbuild project +# that build all the tools needed (GTest, PCRE, Swig, Lua & GTest) and +# then SimpleITK "core" libraries. + +message(STATUS "SuperBuild - SimpleITK-superbuild") + +# Sanity checks +if(DEFINED SimpleITK_DIR AND NOT EXISTS ${SimpleITK_DIR}) + message(FATAL_ERROR "SimpleITK_DIR variable is defined but corresponds to nonexistent directory") +endif() +if(DEFINED SWIG_EXECUTABLE AND NOT EXISTS ${SWIG_EXECUTABLE}) + message(FATAL_ERROR "SWIG_EXECUTABLE variable is defined but corresponds to nonexistent file") +endif() + +set( SimpleITK-python-deps "" ) + +if(NOT DEFINED SimpleITK_DIR) + + set(SimpleITK_SUPERBUILD_DIR ${CMAKE_BINARY_DIR}/sitk-sb) + + ExternalProject_add(SimpleITK-superbuild + SOURCE_DIR ${SimpleITK_SOURCE_DIR}/SuperBuild + BINARY_DIR ${SimpleITK_SUPERBUILD_DIR} DOWNLOAD_COMMAND "" UPDATE_COMMAND "" CMAKE_CACHE_ARGS ${ep_common_cmake_cache_args} - -DPython_INCLUDE_DIR:PATH=${PYTHON_INCLUDE_DIR} - -DPython_LIBRARY:PATH=${PYTHON_LIBRARY} - -DPython_EXECUTABLE:PATH=${PYTHON_EXECUTABLE} + -DBUILD_EXAMPLES:BOOL=OFF -DBUILD_TESTING:BOOL=OFF - -DSimpleITK_PYTHON_THREADS:BOOL=${SimpleITK_PYTHON_THREADS} - -DSimpleITK_PYTHON_USE_LIMITED_API:BOOL=${SimpleITK_PYTHON_USE_LIMITED_API} - -DSimpleITK_DIR:PATH=${SimpleITK_DIR} - -DITK_DIR:PATH=${ITK_DIR} - -DSWIG_EXECUTABLE:PATH=${SWIG_EXECUTABLE} + -DBUILD_DOXYGEN:BOOL=OFF + -DWRAP_DEFAULT:BOOL=OFF + -DITK_USE_BUILD_DIR:BOOL=ON + -DSimpleITK_INSTALL_DOC_DIR:STRING=SimpleITK -DSimpleITK_BUILD_STRIP:BOOL=ON - -DSKBUILD:BOOL=ON + -DSimpleITK_BUILD_DISTRIBUTE:BOOL=ON + -DSimpleITK_GIT_PROTOCOL:STRING=https + -DSimpleITK_USE_SYSTEM_SWIG:BOOL=ON + -DSWIG_EXECUTABLE:PATH=${SWIG_EXECUTABLE} + -DSKBUILD:BOOL=${SKBUILD} + -DUSE_CCACHE:BOOL=${USE_CCACHE} USES_TERMINAL_CONFIGURE 1 USES_TERMINAL_BUILD 1 INSTALL_COMMAND "" - DEPENDS SimpleITK-superbuild ) - message(STATUS "SuperBuild - SimpleITK_PYTHON_DIR: ${SimpleITK_PYTHON_DIR}") + set(SimpleITK_DIR ${SimpleITK_SUPERBUILD_DIR}/SimpleITK-build) + set(ITK_DIR ${SimpleITK_SUPERBUILD_DIR}/ITK-build) + list(APPEND SimpleITK-python-deps SimpleITK-superbuild) +endif() - #----------------------------------------------------------------------------- - # SimpleITKPythonPackage: This project adds install rules for the "Runtime" component - # of both SimpleITK code and python libraries. +message(STATUS "SuperBuild - SimpleITK_DIR: ${SimpleITK_DIR}") +message(STATUS "SuperBuild - ITK_DIR: ${ITK_DIR}") +message(STATUS "SuperBuild - SWIG_EXECUTABLE: ${SWIG_EXECUTABLE}") - message(STATUS "SuperBuild - ${PROJECT_NAME} => Requires SimpleITK-python") - ExternalProject_add(${PROJECT_NAME} - SOURCE_DIR ${CMAKE_SOURCE_DIR} - BINARY_DIR ${CMAKE_BINARY_DIR}/${PROJECT_NAME}-build - DOWNLOAD_COMMAND "" - UPDATE_COMMAND "" - CMAKE_CACHE_ARGS - ${ep_common_cmake_cache_args} - -DSimpleITKPythonPackage_SUPERBUILD:BOOL=0 - -DSimpleITK_DIR:PATH=${SimpleITK_DIR} - -DSimpleITK_PYTHON_DIR:PATH=${SimpleITK_PYTHON_DIR} - -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX} - USES_TERMINAL_CONFIGURE 1 - INSTALL_COMMAND "" - DEPENDS SimpleITK-python - ) +#----------------------------------------------------------------------------- +if(NOT SimpleITKPythonPackage_BUILD_PYTHON) + return() +endif() - install(SCRIPT ${CMAKE_BINARY_DIR}/${PROJECT_NAME}-build/cmake_install.cmake) -else() +#----------------------------------------------------------------------------- +# Search for python interpreter and libraries - #----------------------------------------------------------------------------- - # Install SimpleITK Core "Runtime" components - install(CODE " -unset(CMAKE_INSTALL_COMPONENT) -set(COMPONENT \"Runtime\") -include\(\"${SimpleITK_DIR}/cmake_install.cmake\") -unset(CMAKE_INSTALL_COMPONENT) -") +message(STATUS "SuperBuild - Searching for python") + +if ( PYTHON_VERSION_STRING VERSION_GREATER_EQUAL "3.11.0") - # Install SimpleITK Python "Runtime" components - install(CODE " + set(_SimpleITK_PYTHON_USE_LIMITED_API_DEFAULT ON) +else () + set(_SimpleITK_PYTHON_USE_LIMITED_API_DEFAULT OFF) +endif() +option( SimpleITK_PYTHON_USE_LIMITED_API "Use Python limited API, for minor version compatibility." ${_SimpleITK_PYTHON_USE_LIMITED_API_DEFAULT} ) + +# Sanity checks +if(DEFINED Python_INCLUDE_DIR AND NOT EXISTS ${Python_INCLUDE_DIR}) + message(FATAL_ERROR "Python_INCLUDE_DIR variable is defined but corresponds to nonexistent directory") +endif() +if(DEFINED Python_LIBRARY AND NOT EXISTS ${Python_LIBRARY}) + message(FATAL_ERROR "Python_LIBRARY variable is defined but corresponds to nonexistent file") +endif() +if(DEFINED Python_EXECUTABLE AND NOT EXISTS ${Python_EXECUTABLE}) + message(FATAL_ERROR "Python_EXECUTABLE variable is defined but corresponds to nonexistent file") +endif() + +if(NOT DEFINED Python_INCLUDE_DIR + OR NOT DEFINED Python_LIBRARY + OR NOT DEFINED Python_EXECUTABLE) + + find_package( Python COMPONENTS Interpreter Development REQUIRED ) + +endif() + +message(STATUS "SuperBuild - Python_INCLUDE_DIR: ${Python_INCLUDE_DIR}") +message(STATUS "SuperBuild - Python_LIBRARY: ${Python_LIBRARY}") +message(STATUS "SuperBuild - Python_EXECUTABLE: ${Python_EXECUTABLE}") + + +#----------------------------------------------------------------------------- +# SimpleITK Python module: This project build only the SimpleITK python +# module. + +message(STATUS "SuperBuild - SimpleITK-python => Requires ${SimpleITK-python-deps}") +message(STATUS "SuperBuild - INSTALL_DIR: ${SKBUILD_SCRIPTS_DIR}") +set(SimpleITK_PYTHON_DIR "${CMAKE_BINARY_DIR}/SimpleITK-python") + +ExternalProject_add(SimpleITK-python + SOURCE_DIR ${SimpleITK_SOURCE_DIR}/Wrapping/Python + BINARY_DIR ${SimpleITK_PYTHON_DIR} + DOWNLOAD_COMMAND "" + UPDATE_COMMAND "" + INSTALL_COMMAND "" + CMAKE_CACHE_ARGS + ${ep_common_cmake_cache_args} + -DPython_INCLUDE_DIR:PATH=${Python_INCLUDE_DIR} + -DPython_LIBRARY:PATH=${Python_LIBRARY} + -DPython_EXECUTABLE:PATH=${Python_EXECUTABLE} + -DBUILD_TESTING:BOOL=OFF + -DSimpleITK_PYTHON_THREADS:BOOL=${SimpleITK_PYTHON_THREADS} + -DSimpleITK_PYTHON_USE_LIMITED_API:BOOL=${SimpleITK_PYTHON_USE_LIMITED_API} + -DSimpleITK_DIR:PATH=${SimpleITK_DIR} + -DITK_DIR:PATH=${ITK_DIR} + -DSWIG_EXECUTABLE:PATH=${SWIG_EXECUTABLE} + -DSimpleITK_BUILD_STRIP:BOOL=ON + -DSKBUILD:BOOL=ON + -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX} + USES_TERMINAL_CONFIGURE 1 + USES_TERMINAL_BUILD 1 + + DEPENDS "${SimpleITK-python-deps}" + ) + + +#----------------------------------------------------------------------------- +# Install SimpleITK Python "Runtime" components +install(CODE " unset(CMAKE_INSTALL_COMPONENT) set(COMPONENT \"Runtime\") include\(\"${SimpleITK_PYTHON_DIR}/cmake_install.cmake\") unset(CMAKE_INSTALL_COMPONENT) ") -endif() - diff --git a/README.md b/README.md index 1a7f19d..b5c882d 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,29 @@ # SimpleITKPythonPackage -This project provides a `setup.py` script that can build, install, and package SimpleITK for Python. [SimpleITK](http://www.simpleitk.org) is a simplified programming layer on top of the [Insight Segmentation and Registration Toolkit](https://itk.org) (ITK). ITK is an open-source, cross-platform system that provides developers with an extensive suite of software tools for image analysis. +This project provides a modern build system using [scikit-build-core](https://scikit-build-core.readthedocs.io/) to build, install, and package SimpleITK for Python. [SimpleITK](http://www.simpleitk.org) is a simplified programming layer on top of the [Insight Segmentation and Registration Toolkit](https://itk.org) (ITK). ITK is an open-source, cross-platform system that provides developers with an extensive suite of software tools for image analysis. SimpleITK is available for binary downloads from [PyPI](https://pypi.python.org/pypi/SimpleITK) for many common platforms. Also a source distribution is available of this repository which may be used when an appropriate binary [wheel](http://pythonwheels.com) is not available. To install SimpleITK: ```bash -pip install SimpleITK +python -m pip install SimpleITK ``` ## Installing SimpleITK for Python from the Python Packaging Source ```bash -pip install --no-binary :all: SimpleITK +python -m pip install --no-binary SimpleITK SimpleITK ``` ### Prerequisites -The build requirements are specified in the pyproject.toml file via [PEP 518](https://peps.python.org/pep-0518/). The requirements should be automatically downloaded when using a [PEP 517](https://peps.python.org/pep-0517/) compliant build front-end. +The build requirements are specified in the `pyproject.toml` file via [PEP 518](https://peps.python.org/pep-0518/). The requirements should be automatically downloaded when using a [PEP 517](https://peps.python.org/pep-0517/) compliant build front-end like `pip` or `build`. Additionally building *requires*: * Git -* C++ Compiler - Platform specific requirements are summarized in [scikit-build documentation](http://scikit-build.readthedocs.io). -* Python - * pip >= 9.0.0 +* C++ Compiler - Platform specific requirements are summarized in [scikit-build-core documentation](https://scikit-build-core.readthedocs.io/) +* Python >= 3.10 Please ensure that `pip` is up to date. @@ -32,100 +31,114 @@ Please ensure that `pip` is up to date. python -m pip install --upgrade pip ``` -### Compilations and Installation from Github +## Detailed build instructions + +### Building SimpleITK Python wheels + +Build the SimpleITK Python wheel with the following command: -SimpleITK can be compiled and install directly from the github repository: +To build only a wheel (not sdist): ```bash -pip install git+https://github.com/SimpleITK/SimpleITKPythonPackage.git -v +python -m build --wheel ``` -### Compilation and Installation from Source Distribution +### Building Source Distribution -Alternatively, SimpleITK for Python can be compiled and installed from the SimpleITKPythonPackage python source distribution. +The Python [build](https://pypa-build.readthedocs.io/en/latest/) package should be used to build the source distribution: ```bash -pip install SimpleITKPythonPackage-1.0.0.tar.gz +python -m build --sdist ``` -The source distributions are available from [PyPI](https://pypi.python.org/pypi/SimpleITK). +### Configuration Options -## Automated wheels building with scripts +You can pass configuration options to the build using `-C` or `--config-settings`: -Steps required to build wheels on Linux, MacOSX and Windows have been automated. The -following sections outline how to use the associated scripts. - -### Linux +```bash +# Enable verbose build output +python -m build -C build.verbose=true -On any linux distribution with `docker` and `bash` installed, running the script -`dockcross-manylinux-build-wheels.sh` will create 32 and 64-bit wheels for both -python 2.x and python 3.x in the `dist` directory. +# Set CMake build type +python -m build -C cmake.build-type=Debug -For example: +# Pass CMake defines +python -m build -C cmake.define.SOME_OPTION=ON -```bash -$ git clone git://github.com/SimpleITK/SimpleITKPythonPackage.git -[...] - -$ ./scripts/dockcross-manylinux-build-wheels.sh -[...] - -$ ls -1 dist/ -SimpleITK-0.11.0-cp27-cp27m-manylinux1_i686.whl -SimpleITK-0.11.0-cp27-cp27m-manylinux1_x86_64.whl -SimpleITK-0.11.0-cp27-cp27mu-manylinux1_i686.whl -SimpleITK-0.11.0-cp27-cp27mu-manylinux1_x86_64.whl -SimpleITK-0.11.0-cp33-cp33m-manylinux1_i686.whl -SimpleITK-0.11.0-cp33-cp33m-manylinux1_x86_64.whl -SimpleITK-0.11.0-cp34-cp34m-manylinux1_i686.whl -SimpleITK-0.11.0-cp34-cp34m-manylinux1_x86_64.whl -SimpleITK-0.11.0-cp35-cp35m-manylinux1_i686.whl -SimpleITK-0.11.0-cp35-cp35m-manylinux1_x86_64.whl +# Use a persistent build directory for faster rebuilds +python -m build -C build-dir=build ``` -## Prerequisites +For more configuration options, see the [scikit-build-core documentation](https://scikit-build-core.readthedocs.io/en/latest/configuration/index.html). -Building wheels requires: -* [CMake](https://cmake.org) -* Git -* C++ Compiler - Platform specific requirements are summarized in [scikit-build documentation](http://scikit-build.readthedocs.io). -* Python +### Efficiently building wheels for different versions of Python -## Detailed build instructions +If on a given platform you would like to build wheels for different versions of Python, you can build the SimpleITK core libraries first and reuse them when building each wheel. -### Building SimpleITK Python wheels +Here are the steps: -Build the SimpleITK Python wheel with the following command: +1. Build `SimpleITKPythonPackage` with `SimpleITKPythonPackage_BUILD_PYTHON` set to `OFF`: +```bash +python -m build -C build-dir=build -Ccmake.define.SimpleITKPythonPackage_BUILD_PYTHON=OFF ``` -python -m build . + +2. Build wheels for different Python versions by passing the pre-built paths via config settings: + +```bash +python3.10 -m build --wheel -C cmake.define.SimpleITK_DIR=/path/to/build/sitk-sb/SimpleITK-build \ + -C cmake.define.ITK_DIR=/path/to/build/sitk-sb/ITK-build + +python3.11 -m build --wheel -C cmake.define.SimpleITK_DIR=/path/to/build/sitk-sb/SimpleITK-build \ + -C cmake.define.ITK_DIR=/path/to/build/sitk-sb/ITK-build + ``` -### Building Source Distribution -The Python [build](https://pypa-build.readthedocs.io/en/latest/) package should be used to build the source distribution: +### Development and Editable Installs + +For development, you can install SimpleITK in editable mode: +```bash +pip install -e . --no-build-isolation ``` -python -m build --sdist . + +For faster rebuilds during development, use a persistent build directory: + +```bash +pip install -e . --no-build-isolation -C build-dir=build ``` -### Efficiently building wheels for different version of python +For more information on editable installs, see the [scikit-build-core editable documentation](https://scikit-build-core.readthedocs.io/en/latest/configuration/index.html#editable-installs). -If on a given platform you would like to build wheels for different version of python, you can build the SimpleITK core libraries first and reuse them when building each wheel. +## Build System -Here are the steps: +This package uses [scikit-build-core](https://scikit-build-core.readthedocs.io/), a modern Python build backend that uses CMake. Key features include: -1. Build `SimpleITKPythonPackage` with `SimpleITKPythonPackage_BUILD_PYTHON` set to `OFF` +- **Automatic dependency management**: CMake and Ninja are automatically provided if needed +- **PEP 517/518 compliant**: Works with modern Python build tools +- **Configurable**: Extensive configuration options via `pyproject.toml` or command-line +- **Cross-platform**: Supports Windows, macOS, and Linux +- **Fast rebuilds**: Optional persistent build directories for development -2. Build "flavor" of package using: +### Available CMake Options -``` -python setup.py bdist_wheel -- \ - -DSimpleITK_DIR:PATH=/path/to/SimpleITKPythonPackage-core-build/SimpleITK-superbuild/SimpleITK-build \ - -DSWIG_EXECUTABLE:PATH=/path/to/SimpleITKPythonPackage-core-build/SimpleITK-superbuild/Swig/bin/swig +The following CMake options can be set via config settings: + +- `SimpleITKPythonPackage_BUILD_PYTHON`: Build Python bindings (default: ON) +- `SimpleITK_PYTHON_THREADS`: Enable threaded Python usage by unlocking the GIL (default: ON) +- `SimpleITK_PYTHON_USE_LIMITED_API`: Use Python Limited API for minor version compatibility (default: ON for Python >= 3.11) +- `SimpleITK_DIR`: Path to existing SimpleITK build directory (for reusing builds) +- `USE_CCACHE`: Enable ccache for faster rebuilds (default: OFF) + +Example: + +```bash +python -m build -C cmake.define.SimpleITK_PYTHON_THREADS=OFF \ + -C cmake.define.USE_CCACHE=ON ``` ## Miscellaneous -Written by Jean-Christophe Fillion-Robin from Kitware Inc. +Written by Jean-Christophe Fillion-Robin from Kitware Inc. and Bradley Lowekamp. It is covered by the Apache License, Version 2.0: diff --git a/pyproject.toml b/pyproject.toml index 47da5e4..00a98eb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,8 +1,57 @@ [build-system] requires = [ - "scikit-build>=0.17.6", - "wheel", - "cmake>=3.26.0", - "ninja; platform_system!='Windows'" + "scikit-build-core>=0.10", + "swig==4.4.0" ] -build-backend = "setuptools.build_meta" +build-backend = "scikit_build_core.build" + + +[project] +name = "SimpleITK" +version = "2.5.3" +description = "SimpleITK is a simplified interface to the Insight Toolkit (ITK) for image registration and segmentation" +readme = "README.md" +requires-python = ">=3.8" +license = {text = "Apache-2.0"} +authors = [ + {name = "Insight Software Consortium", email = "insight-users@itk.org"} +] +keywords = ["SimpleITK", "ITK", "InsightToolkit", "segmentation", "registration"] +classifiers = [ + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: C++", + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Education", + "Intended Audience :: Healthcare Industry", + "Intended Audience :: Science/Research", + "Topic :: Scientific/Engineering", + "Topic :: Scientific/Engineering :: Medical Science Apps.", + "Topic :: Scientific/Engineering :: Information Analysis", + "Topic :: Software Development :: Libraries", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX", + "Operating System :: Unix", + "Operating System :: MacOS" +] + +[project.urls] +Homepage = "http://simpleitk.org/" +Documentation = "https://simpleitk.readthedocs.io/en/release/" +"Bug Tracker" = "https://github.com/SimpleITK/SimpleITK/issues" +"Source Code" = "https://github.com/SimpleITK/SimpleITK" + +[tool.scikit-build] +minimum-version = "0.10" +cmake.version = ">=3.26.0" +wheel.packages = ["SimpleITK"] +wheel.install-dir = "." +sdist.include = [ + "CMakeLists.txt", + "README.md", + "SimpleITK/**" +] +sdist.exclude = [ + "SimpleITK/.ExternalData/**", + "**/.git*" +] \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100644 index c25e619..0000000 --- a/setup.py +++ /dev/null @@ -1,46 +0,0 @@ -from __future__ import print_function -from os import sys -from skbuild import setup - -with open('SimpleITK/Readme.md', encoding='utf-8') as f: - long_description = f.read() - - -setup( - name='SimpleITK', - version='2.5.3', - author='Insight Software Consortium', - author_email='insight-users@itk.org', - packages=['SimpleITK'], - package_dir={'SimpleITK':'SimpleITK'}, - description=r'SimpleITK is a simplified interface to the Insight Toolkit (ITK) for image registration and segmentation', - long_description = long_description, - long_description_content_type='text/markdown', - classifiers=[ - "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python", - "Programming Language :: C++", - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Education", - "Intended Audience :: Healthcare Industry", - "Intended Audience :: Science/Research", - "Topic :: Scientific/Engineering", - "Topic :: Scientific/Engineering :: Medical Science Apps.", - "Topic :: Scientific/Engineering :: Information Analysis", - "Topic :: Software Development :: Libraries", - "Operating System :: Microsoft :: Windows", - "Operating System :: POSIX", - "Operating System :: Unix", - "Operating System :: MacOS" - ], - license='Apache', - keywords = 'SimpleITK ITK InsightToolkit segmentation registration', - url = r'http://simpleitk.org/', - project_urls={ - "Bug Tracker": "https://github.com/SimpleITK/SimpleITK/issues", - "Documentation": "https://simpleitk.readthedocs.io/en/release/", - "Source Code": "https://github.com/SimpleITK/SimpleITK", - }, - install_requires=[], - zip_safe=False - )