From: John Mulligan Date: Mon, 13 Apr 2026 21:24:24 +0000 (-0400) Subject: cmake/modules: add PythonPackage.cmake X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=42ddb5eafd51e2a9f306322d836a3d2f7388f027;p=ceph.git cmake/modules: add PythonPackage.cmake Time is marching on and the state of the art with python packaging has not stood still. In Python 3.12, distutils has been removed after being deprecated for a couple of versions. According to the Python Packaging User Guide [1]: "However, `python setup.py` and the use of `setup.py` as a command line tool are deprecated." Currently, ceph provides a decent sized and growing library of python code in `src/python-common/ceph`. It currently relies on `setup.py` and the deprecated `python setup.py install` command. This change aims to be the first step in moving toward a more contemporary approach so that we don't get caught late when the older approaches really stop working. Because ceph's primary diver of "build stuff" is CMake, there was an existing `cmake/modules/Distutils.cmake` that invokes a `python setup.py install` command. Rather than risk breaking older distros we add a new `cmake/modules/PythonPackage.cmake` file that uses the PEP 517/518 [2][3] style of packaging. I could not find some existing CMake support for this so unfortunately I had to write this. The approach taken is loosely based on what the rpm build process does. It invokes pip's wheel subcommand to build a wheel (during the build phase) and then uses pip to install the wheel to install the content to the system. A future commit will add conditional support for using this approach in src/python-common. [1] https://packaging.python.org/en/latest/discussions/setup-py-deprecated/ [2] https://peps.python.org/pep-0517/ [3] https://peps.python.org/pep-0518/ Signed-off-by: John Mulligan --- diff --git a/cmake/modules/PythonPackage.cmake b/cmake/modules/PythonPackage.cmake new file mode 100644 index 000000000000..7453edf875a6 --- /dev/null +++ b/cmake/modules/PythonPackage.cmake @@ -0,0 +1,84 @@ +find_package(Python3 ${WITH_PYTHON3} EXACT + QUIET + REQUIRED + COMPONENTS Interpreter) + +function(create_python_package pkgname) + set(options BUILD_ISOLATION) + set(oneValueArgs WHEELDIR) + cmake_parse_arguments(PARSE_ARGV 0 pypkg + "${options}" "${oneValueArgs}" "") + if(NOT "${pypkg_WHEELDIR}") + set(pypkg_WHEELDIR "${CMAKE_CURRENT_BINARY_DIR}/wheels/${pkgname}") + endif() + + python_package_build_pip_wheel( + "${pkgname}" "${pypkg_WHEELDIR}" "${pypkg_BUILD_ISOLATION}" + ) + python_package_install_pip_wheel("${pkgname}" "${pypkg_WHEELDIR}") +endfunction(create_python_package) + + +function( + python_package_build_pip_wheel + pkgname + wheeldir + build_isolation +) + list(APPEND build_args + --wheel-dir "${wheeldir}" + --no-deps + --use-pep517 + --disable-pip-version-check + --no-clean + --progress-bar=off + --verbose + ) + if(NOT "${build_isolation}") + list(APPEND build_args --no-build-isolation) + endif() + list(APPEND build_args "${CMAKE_CURRENT_SOURCE_DIR}") + + add_custom_command( + OUTPUT ${wheeldir} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/pyproject.toml + COMMAND ${Python3_EXECUTABLE} -m pip wheel ${build_args} + ) + if(NOT TARGET build-wheel-${pkgname}) + add_custom_target(build-wheel-${pkgname} ALL + DEPENDS ${wheeldir}) + endif() +endfunction(python_package_build_pip_wheel) + +function( + python_package_install_pip_wheel + pkgname + wheeldir +) + list(APPEND install_args + "--prefix=${CMAKE_INSTALL_PREFIX}" + --no-deps + --disable-pip-version-check + --progress-bar=off + --root-user-action=ignore + --verbose + --ignore-installed + --no-warn-script-location + --no-index + --no-cache-dir + --find-links "${wheeldir}" + "${pkgname}" + ) + + install(CODE " + set(args \"${install_args}\") + if(DEFINED ENV{DESTDIR}) + list(INSERT args 1 --root=\$ENV{DESTDIR}) + endif() + message(DEBUG PythonPackage.install_cmd= + \"${Python3_EXECUTABLE} -m pip install\" \"\${args}\") + execute_process( + COMMAND ${Python3_EXECUTABLE} -m pip install \${args} + WORKING_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}\" + COMMAND_ERROR_IS_FATAL ANY)") +endfunction(python_package_install_pip_wheel)