scikit-build-core
[!NOTE]
我们每月举行一次公开的 Scikit-build 社区会议! 请在每月第三个 星期五 12:00 PM ET 通过 Google Meet](https://meet.google.com/tgz-umhu-onf) 加入我们。我们过去的一些会议记录 在此处可获取。
Scikit-build-core 是一个用于 Python 的构建后端,它使用 CMake 来构建 扩展模块。它在 pyproject.toml 中拥有简单而强大的静态配置系统, 并通过 CMake 支持几乎无限的灵活性。它最初是为满足科学用户的 苛刻需求而开发的,但可以构建任何使用 CMake 的包。
Scikit-build-core 是对经典 Scikit-build 的彻底重写。经典 scikit-build(基于 setuptools)的关键特性在此同样存在:
- 对大多数操作系统、编译器、IDE 和库的出色支持
- 对 C++ 特性以及 Fortran 等其他语言的支持
- 对多线程构建的支持
- 使用简单的 CMakeLists.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 和 Limited API / Stable ABI
- 通过配置选项支持 Limited API / Stable ABI 和 pythonless 标签
- 无缓慢的生成器搜索,默认使用 ninja/make 或 MSVC,并尊重
CMAKE_GENERATOR - SDists 默认是可复现的(UNIX,Python 3.9+,建议进行未压缩比较), 并且 wheels 也可以设置为可复现(可选)
- 支持在构建之间进行缓存(通过设置
build-dir可选启用) - 支持写入额外的 wheel 文件夹(scripts、headers、data)
- 支持选择安装组件和构建目标
- 为模块和前缀目录提供专用的入口点
- 多个集成的动态元数据插件,支持跨后端
[[tool.dynamic-metadata]]标准 - 支持可编辑模式,包括可选的实验性导入时自动重建和 可选的原地模式
- 支持 WebAssembly(Emscripten/Pyodide)。
- 支持 free-threaded Python 3.13+, 包括 free-threaded stable ABI(PEP 803)。
- 一个
scikit-buildCLI,包括scikit-build init用于搭建新项目。
当前要求:
- 最低支持的 CMake 版本为 3.15
- 最低支持的 Python 版本为 3.9(1.0.x 及更早版本支持 3.8+)
推荐的接口是原生的 pyproject 构建器。其他后端也可用:
- Setuptools 集成(使用
[setuptools]额外依赖) - Hatchling 插件(使用
[hatchling]额外依赖)
[!WARNING]
setuptools 和 hatchling 后端未来可能会迁移到独立包中,因此请通过
scikit-build-core[setuptools]和scikit-build-core[hatchling]额外依赖来依赖它们,以便在迁移发生时得到保护。
示例
启动新项目的最快方式是 scikit-build init(也可通过
uvx scikit-build-core init 获取),它会生成一个最小的 CMake +
scikit-build-core 起始项目。各部分描述如下。
要使用 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...4.4)
project(scikit_build_simplest LANGUAGES C)
find_package(Python COMPONENTS Interpreter Development.Module REQUIRED)
Python_add_library(_module MODULE src/module.c WITH_SOABI)
install(TARGETS _module DESTINATION scikit_build_simplest)
install(DESTINATION ...) 是相对于 site-packages 的,因此上述的 _module
扩展在包被
pip install 时位于 scikit_build_simplest/_module.*。Scikit-build-core 会将 FindPython 从 CMake 3.26.1 回
溯到旧版本的 Python,并且如果你是从
PyPy 构建,它会为你处理 PyPy。你需要将所需的一切安装到 site-packages 内的完整最终路径
中(因此你通常会将所有内容以包名作为前缀)
-- 包括任何 __init__.py,CMake 可以使用 install(FILES src/__init__.py DESTINATION scikit_build_simplest) 将其放置在扩展旁边。
最重要的可选配置是:
[build-system]
requires = ["scikit-build-core>=1.0"]
build-backend = "scikit_build_core.build"
[tool.scikit-build]
minimum-version = "build-system.requires"
这将使 scikit-build-core 能够读取你对它自身的最小版本要求, 并针对该版本保持兼容模式;如果未来我们更改了默认设置, 你的包将继续以完全相同的方式构建。
入门指南 逐步讲解了一个完整的包。更多示例位于 tests/packages。
配置
所有配置选项都可以放在 pyproject.toml 中,通过 pip、uv 和 build 中的 -C 传递,
或设置为环境变量。在 toml 中使用 tool.scikit-build,对于 -C 选项使用 skbuild.,
对于环境变量使用 SKBUILD_*。
有关变量的完整参考和说明,请参阅在线 文档
以下是快速摘要和一些默认值:
顶级
| 选项 | 默认值 | 描述 |
|---|---|---|
metadata | {} | 在此表中列出动态元数据字段和钩子位置。 |
env | {} | 用于设置 CMake 子进程环境变量的表。 |
strict-config | true | 严格检查所有配置选项。 |
experimental | false | 启用尚未最终确定的功能的早期预览。 |
minimum-version | "1.0"(当前版本) | 如果设置,这将提供向后兼容的方法。 |
build-dir | "" | CMake 构建目录。默认为唯一的临时目录。 |
cmake
| 选项 | 默认值 | 描述 |
|---|---|---|
cmake.version | "" | 允许作为 Python 兼容说明符的 CMake 版本。 |
cmake.args | [] | 配置项目时传递给 CMake 的参数列表。 |
cmake.define | {} | 配置项目时传递给 CMake 的定义表。可累加。 |
cmake.build-type | "Release" | 构建项目时使用的构建类型。 |
cmake.source-dir | "." | 构建项目时使用的源目录。 |
cmake.fresh | false | 丢弃任何缓存的 CMake 配置并从头开始配置,类似于 cmake --fresh。 |
cmake.python-hints | true | 不传递当前环境的 Python 提示,例如 Python_EXECUTABLE。 |
ninja
| 选项 | 默认值 | 描述 |
|---|---|---|
ninja.version | ">=1.5" | 允许使用的 Ninja 版本。 |
ninja.make-fallback | true | 如果未找到合适的 Ninja 可执行文件,则使用 Make 作为回退。 |
logging
| 选项 | 默认值 | 描述 |
|---|---|---|
logging.level | "WARNING" | 要显示的日志级别。(choices: NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL) |
sdist
| 选项 | 默认值 | 描述 |
|---|---|---|
sdist.include | [] | 即使默认被跳过,也要包含在 SDist 中的文件。支持 gitignore 语法。 |
sdist.exclude | [] | 即使默认被包含,也要从 SDist 中排除的文件。支持 gitignore 语法。 |
sdist.inclusion-mode | "default" ("classic") | 用于计算要包含和排除的文件的方法。(选项:classic, default, manual, explicit) |
sdist.reproducible | true | 尝试构建可复现的发行版。 |
sdist.cmake | false | 如果设置为 True,将在构建 SDist 之前运行 CMake。 |
sdist.force-include | {} | 强制将文件包含到 SDist 中。 |
sdist.resolve-symlinks | "all" | 在 SDist 中解析哪些符号链接,并存储目标的内容。(选项:all, external, none, classic) |
wheel
| 选项 | 默认值 | 描述 |
|---|---|---|
wheel.packages | ["src/<package>", "python/<package>", "<package>"] | 自动复制到 wheel 中的包列表。 |
wheel.py-api | "" | wheel 文件中使用的 Python 版本标签。 |
wheel.expand-macos-universal-tags | false | 填写非必需的额外标签。 |
wheel.install-dir | "" | 相对于 platlib wheel 路径的 CMake 安装前缀。 |
wheel.license-files | "" | 包含在 wheel 中的许可证文件列表。支持 glob 模式。 |
wheel.cmake | true | 作为构建 wheel 的一部分运行 CMake。 |
wheel.platlib | "" | 目标为 platlib 或 purelib。 |
wheel.exclude | [] | 从 wheel 中排除的一组模式。 |
wheel.build-tag | "" | 用于 wheel 的构建标签。如果为空,则不使用构建标签。 |
wheel.force-include | {} | 强制将文件包含到 wheel 中。 |
wheel.reproducible | false | 尝试构建可重现的 wheel。 |
backport
| 选项 | 默认值 | 描述 |
|---|---|---|
backport.find-python | "3.26.1" | 如果 CMake 小于此值,则回退一份 FindPython 的副本。 |
editable
| 选项 | 默认值 | 描述 |
|---|---|---|
editable.mode | "redirect" | 选择要使用的可编辑模式。(choices: redirect, inplace) |
editable.verbose | true | 为可编辑模式的重建开启详细输出。 |
editable.rebuild | false | 在导入包时重建项目。 |
editable.rebuild-dir | "" | 将可重建的可编辑包安装到此树中(editable.rebuild 的较新替代方案)。 |
build
| 选项 | 默认值 | 描述 |
|---|---|---|
build.tool-args | [] | 在构建步骤中直接传递给构建器的额外参数。 |
build.targets | [] | 构建项目时使用的构建目标。 |
build.verbose | false | 构建时的详细输出。 |
build.requires | [] | 额外的 build-system.requires。 |
install
| 选项 | 默认值 | 描述 |
|---|---|---|
install.components | [] | 要安装的组件。 |
install.targets | [] | 在安装步骤中通过 cmake --build --target 运行的构建目标。 |
install.strip | true | 是否剥离二进制文件。 |
generate[]
| 选项 | 默认值 | 描述 |
|---|---|---|
generate[].path | "" | 要生成的文件的路径(相对于 platlib)。 |
generate[].template | "" | 用于该文件的模板字符串。 |
generate[].template-path | "" | 模板文件的路径。如果为空,则必须设置模板。 |
generate[].location | "install" | 放置生成文件的位置。(选项:install, build, source) |
messages
| 选项 | 默认值 | 描述 |
|---|---|---|
messages.after-failure | "" | 构建失败后打印的消息。 |
messages.after-success | "" | 构建成功后打印的消息。 |
search
| 选项 | 默认值 | 描述 |
|---|---|---|
search.site-packages | true | 将 python 构建环境的 site_packages 文件夹添加到 CMake 前缀路径中。 |
大多数 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:用于 Rust 项目的构建后端,使用 Cargo。
- enscons:基于 SCons 的后端,开发不太活跃(但它比现代标准支持中的所有其他后端都要早!)
如果你不需要二进制构建,你就不需要使用二进制构建后端!有一些非常好的 Python 构建后端;我们推荐 hatchling,因为它在初学者的好默认值和高级用例的良好支持之间取得了良好的平衡。这是 scikit-build-core 本身使用的工具。
致谢
本工作的支持由 NSF 资助 OAC-2209877 提供。本材料中表达的任何观点、发现、结论或建议均为作者的观点,不一定反映国家科学基金会的观点。