为基于CMake的项目构建后端
项目描述
scikit-build-core
[!注意]
我们每月举行一次公开的Scikit-build社区会议!请在每月第三个星期五中午12:00 EST加入我们参加Google Meet会议。[链接](https://meet.google.com/dvx-jkai-xhq "加入我们")。我们还在每月第一个星期五同一时间举行开发者会议。我们的过去会议记录[在这里](https://github.com/orgs/scikit-build/discussions/categories/community-meeting-notes "社区会议记录")。
scikit-build-core是一个使用CMake构建扩展模块的Python构建后端。它拥有一个简单而强大的静态配置系统(在pyproject.toml中),并通过CMake支持几乎无限的灵活性。它最初是为了满足科学用户的高要求而开发的,但可以构建任何使用CMake的软件包。
scikit-build-core是经典Scikit-build的从头重写。Scikit-build经典(基于setuptools)的关键特性也在这里
- 对大多数操作系统、编译器、IDE和库的优秀支持
- 支持C++特性和Fortran等其他语言
- 支持多线程构建
- 简单的CMakeFiles.txt文件,而不是成千上万的脆弱的setuptools/distutils代码
- 支持Apple Silicon和Windows ARM的交叉编译
scikit-build-core使用在scikit-build(经典)编写之后开发的Python打包标准构建。直接使用它相对于经典Scikit-build提供了以下功能
- 更好的警告、错误和日志记录
- 没有关于未使用变量的警告
- 根据需要自动添加Ninja和/或CMake
- 不依赖于setuptools、distutils或wheel
- 强大的配置系统,包括配置选项支持
- 自动将site-packages包含在
CMAKE_PREFIX_PATH
中 - 如果运行在CMake < 3.26.1上,则回退使用FindPython,支持PyPY SOABI & 有限API / 稳定ABI
- 通过配置选项支持有限API / 稳定ABI和pythonless标记
- 没有缓慢的生成器搜索,默认使用ninja/make或MSVC,尊重
CMAKE_GENERATOR
- 默认情况下SDists是可以重制的(UNIX,Python 3.9+,建议进行未压缩的比较)
- 支持构建之间的缓存(通过设置
build-dir
进行选择) - 支持写入额外的wheel文件夹(脚本、头文件、数据)
- 支持选择安装组件和构建目标
- 为模块和前缀目录提供专用入口点
- 几个集成的动态元数据插件(即将提供标准化支持)
- 实验性可编辑模式支持,可选的实验性自动重建(导入时)和可选的现场模式
- 支持WebAssembly(Emscripten/Pyodide)
- 支持免费线程的Python 3.13。
与经典scikit-build相比,以下存在一些限制
- 最低支持的CMake版本是3.15
- 最低支持的Python版本是3.7
一些即将开发的功能
- 轮子(wheels)还不能完全重制(大多数其他系统,包括setuptools也是如此)
- 一些可编辑模式注意事项(在文档中提及)
还计划其他后端
- setuptools集成处于高度实验阶段
- Hatchling插件处于高度实验阶段
推荐接口是本机pyproject构建器。还有一个基于setuptools的WIP接口正在开发中,以提供经典scikit-build的过渡路径,以及一个WIP的Hatchling插件。两者都可能在未来被移动到独立包中。
[!警告]
应仅使用基于 pyproject 的构建器;setuptools 后端处于实验阶段,可能在被正式认定为稳定之前移动到单独的包中,内部 API 仍在巩固中。本包的未来版本将支持创建新的构建扩展。
示例
要使用 scikit-build-core,请将其添加到您的 build-system.requires
,并将 scikit_build_core.build
构建器指定为您的 build-system.build-backend
。您 无需 指定 cmake
或 ninja
;如果系统版本不足,scikit-build-core 将自动要求它们。
[build-system]
requires = ["scikit-build-core"]
build-backend = "scikit_build_core.build"
[project]
name = "scikit_build_simplest"
version = "0.0.1"
您(也应该)指定 project
中的其余条目,但这些是最基本的启动项。
一个示例 CMakeLists.txt
cmake_minimum_required(VERSION 3.15...3.30)
project(${SKBUILD_PROJECT_NAME} LANGUAGES C)
find_package(Python COMPONENTS Interpreter Development.Module REQUIRED)
Python_add_library(_module MODULE src/module.c WITH_SOABI)
install(TARGETS _module DESTINATION ${SKBUILD_PROJECT_NAME})
Scikit-build-core 将将 CMake 3.26.1 中的 FindPython 回滚到较旧的 Python 版本,并在您从 PyPy 构建时为您处理 PyPy。您需要将所有您想要安装的内容安装到 site-modules 内部的完整最终路径中(因此您通常会使用包名作为前缀)。
更多示例请参阅 tests/packages。
配置
所有配置选项都可以放在 pyproject.toml
中,通过构建时的 -C
/--config-setting
或 pip
中的 -C
/--config-settings
传递,或者作为环境变量设置。在 toml 中使用 tool.scikit-build
,在 -C
选项中使用 skbuild.
,或使用环境变量中的 SKBUILD_*
。以下列出了默认值:
[tool.scikit-build]
# The versions of CMake to allow. If CMake is not present on the system or does
# not pass this specifier, it will be downloaded via PyPI if possible. An empty
# string will disable this check. The default on 0.10+ is "CMakeLists.txt",
# which will read it from the project's CMakeLists.txt file, or ">=3.15" if
# unreadable or <0.10.
cmake.version = ""
# A list of args to pass to CMake when configuring the project. Setting this in
# config or envvar will override toml. See also ``cmake.define``.
cmake.args = []
# A table of defines to pass to CMake when configuring the project. Additive.
cmake.define = {}
# DEPRECATED in 0.10, use build.verbose instead.
cmake.verbose = ""
# The build type to use when building the project. Valid options are: "Debug",
# "Release", "RelWithDebInfo", "MinSizeRel", "", etc.
cmake.build-type = "Release"
# The source directory to use when building the project. Currently only affects
# the native builder (not the setuptools plugin).
cmake.source-dir = "."
# DEPRECATED in 0.10; use build.targets instead.
cmake.targets = ""
# The versions of Ninja to allow. If Ninja is not present on the system or does
# not pass this specifier, it will be downloaded via PyPI if possible. An empty
# string will disable this check.
ninja.version = ">=1.5"
# If Ninja is not present on the system or is older than required, it will be
# downloaded via PyPI if this is false.
ninja.make-fallback = true
# The logging level to display, "DEBUG", "INFO", "WARNING", and "ERROR" are
# possible options.
logging.level = "WARNING"
# Files to include in the SDist even if they are skipped by default. Supports
# gitignore syntax.
sdist.include = []
# Files to exclude from the SDist even if they are included by default. Supports
# gitignore syntax.
sdist.exclude = []
# If set to True, try to build a reproducible distribution (Unix and Python 3.9+
# recommended). ``SOURCE_DATE_EPOCH`` will be used for timestamps, or a fixed
# value if not set.
sdist.reproducible = true
# If set to True, CMake will be run before building the SDist.
sdist.cmake = false
# A list of packages to auto-copy into the wheel. If this is not set, it will
# default to the first of ``src/<package>``, ``python/<package>``, or
# ``<package>`` if they exist. The prefix(s) will be stripped from the package
# name inside the wheel. If a dict, provides a mapping of package name to source
# directory.
wheel.packages = ["src/<package>", "python/<package>", "<package>"]
# The Python tags. The default (empty string) will use the default Python
# version. You can also set this to "cp37" to enable the CPython 3.7+ Stable ABI
# / Limited API (only on CPython and if the version is sufficient, otherwise
# this has no effect). Or you can set it to "py3" or "py2.py3" to ignore Python
# ABI compatibility. The ABI tag is inferred from this tag.
wheel.py-api = ""
# Fill out extra tags that are not required. This adds "x86_64" and "arm64" to
# the list of platforms when "universal2" is used, which helps older Pip's
# (before 21.0.1) find the correct wheel.
wheel.expand-macos-universal-tags = false
# The install directory for the wheel. This is relative to the platlib root. You
# might set this to the package name. The original dir is still at
# SKBUILD_PLATLIB_DIR (also SKBUILD_DATA_DIR, etc. are available). EXPERIMENTAL:
# An absolute path will be one level higher than the platlib root, giving access
# to "/platlib", "/data", "/headers", and "/scripts".
wheel.install-dir = ""
# A list of license files to include in the wheel. Supports glob patterns.
wheel.license-files = ["LICEN[CS]E*", "COPYING*", "NOTICE*", "AUTHORS*"]
# If set to True (the default), CMake will be run before building the wheel.
wheel.cmake = true
# Target the platlib or the purelib. If not set, the default is to target the
# platlib if wheel.cmake is true, and the purelib otherwise.
wheel.platlib = ""
# A set of patterns to exclude from the wheel. This is additive to the SDist
# exclude patterns. This applies to the final paths in the wheel, and can
# exclude files from CMake output as well. Editable installs may not respect
# this exclusion.
wheel.exclude = []
# The build tag to use for the wheel. If empty, no build tag is used.
wheel.build-tag = ""
# If CMake is less than this value, backport a copy of FindPython. Set to 0
# disable this, or the empty string.
backport.find-python = "3.26.1"
# Select the editable mode to use. Can be "redirect" (default) or "inplace".
editable.mode = "redirect"
# Turn on verbose output for the editable mode rebuilds.
editable.verbose = true
# Rebuild the project when the package is imported. The build-directory must be
# set.
editable.rebuild = false
# Extra args to pass directly to the builder in the build step.
build.tool-args = []
# The build targets to use when building the project. Empty builds the default
# target.
build.targets = []
# Verbose printout when building.
build.verbose = false
# The components to install. If empty, all default components are installed.
install.components = []
# Whether to strip the binaries. True for release builds on scikit-build-core
# 0.5+ (0.5-0.10.5 also incorrectly set this for debug builds).
install.strip = true
# The path (relative to platlib) for the file to generate.
generate[].path = ""
# The template to use for the file. This includes string.Template style
# placeholders for all the metadata. If empty, a template-path must be set.
generate[].template = ""
# The path to the template file. If empty, a template must be set.
generate[].template-path = ""
# The place to put the generated file. The "build" directory is useful for CMake
# files, and the "install" directory is useful for Python files, usually. You
# can also write directly to the "source" directory, will overwrite existing
# files & remember to gitignore the file.
generate[].location = "install"
# A message to print after a build failure.
messages.after-failure = ""
# A message to print after a successful build.
messages.after-success = ""
# List dynamic metadata fields and hook locations in this table.
metadata = {}
# Strictly check all config options. If False, warnings will be printed for
# unknown options. If True, an error will be raised.
strict-config = true
# Enable early previews of features not finalized yet.
experimental = false
# If set, this will provide a method for backward compatibility.
minimum-version = "0.10" # current version
# The build directory. Defaults to a temporary directory, but can be set.
build-dir = ""
# Immediately fail the build. This is only useful in overrides.
fail = false
大多数 CMake 环境变量都应受支持,可以使用 CMAKE_ARGS
设置额外的 CMake 参数。ARCHFLAGS
用于指定 macOS universal2 或交叉编译,就像 setuptools 一样。
您还可以指定 [[tool.scikit-build.overrides]]
来为不同的系统自定义值。有关详细信息,请参阅文档。
其他构建项目
Scikit-build-core 是一个二进制构建后端。还有其他二进制构建后端
- py-build-cmake:CMake 标准兼容构建器的一次尝试。重点关注交叉编译。使用 Flit 内部机制。
- cmeel:CMake 标准兼容构建器的一次尝试。重点关注围绕 site-packages 中特殊不可导入文件夹的生态系统构建(类似于 scikit-build 对
cmake.*
入口点的使用,但基于文件夹)。 - meson-python:基于 meson 的构建后端;与 scikit-build-core 有一些维护者重叠。
- maturin:使用 Cargo 的 Rust 项目的构建后端。
- enscons:基于 SCons 的后端,开发不太活跃(但它在现代标准支持方面是最早的!)
如果您不需要二进制构建,则不需要使用二进制构建后端!有一些非常好的 Python 构建后端;我们推荐 hatchling 作为初学者良好默认设置和高级用例良好支持的良好平衡。这是 scikit-build-core 本身使用的工具。
致谢
本工作的支持由 NSF 奖学金 OAC-2209877 提供。本材料中表达的意见、发现、结论或建议是作者的观点,不一定反映美国国家科学基金会的观点。
项目详情
下载文件
下载适用于您平台文件的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。