随着 PyTorch 的成功,越来越多的 C++ 项目使用 Python 作为用户交互的前端语言,通过 pybind11 等库连接 Python 前端接口与 C++ 高性能后端实现。
例如,NVIDIA 也在主推 cuteDSL 作为 CUTLASS 的 Python 接口。
本文主要介绍 scikit-build-core
,一个利用 pyproject.toml
来定义 CMake 构建命令的工具,让开发者方便地在 Python 和 C++ 间协同开发。
Python package 构建流程: https://doi.org/10.25080/FMKR8387
在 pyproject.toml
中声明
[build-system]
requires = ["scikit-build-core"]
build-backend = "scikit_build_core.build"
开发者需要在 pyproject.toml
中声明使用 scikit-build-core 作为项目的构建后端,然后可以详细定义在构建项目的时候需要执行的 CMake 命令和参数:
[tool.scikit-build]
build-dir = "build"
cmake.version = ">=3.26.1"
ninja.version = ">=1.11"
cmake.source-dir = "."
cmake.args = ["-G Ninja"]
cmake.build-type = "RelWithDebInfo"
[tool.scikit-build.cmake.define]
SOME_DEFINE = "Foo"
SOME_OPTION = true
FOOD_GROUPS = [
"Apple",
"Lemon;Lime",
"Banana",
"Pineapple;Mango",
]
在 CMake 侧,开发者可以复用一些在 pyproject.toml
中定义的参数,避免重复定义:
cmake_minimum_required(VERSION 3.15)
project(
${SKBUILD_PROJECT_NAME}
VERSION ${SKBUILD_PROJECT_VERSION}
LANGUAGES C CXX)
构建和安装
运行 uv pip install .
,可以在本地进行项目的构建,如果你需要将构建产物安装到 site-packages
目录中使得 Python 解释器可以 import,需要在 CMakeLists.txt
中用 install
声明哪些文件/目标需要被安装,scikit-build-core 会自动将 CMake 中的 CMAKE_INSTALL_PREFIX
参数设置为当前 Python 环境中的 site-packages/${SKBUILD_PROJECT_NAME}
目录。
同时,scikit-build-core 会自动将当前 Python 环境的 site-packages
目录添加到 CMAKE_PREFIX_PATH
中,因此开发者通过 uv pip install
等方式安装的 Python 包可以被 CMake 轻易地发现 (只要正确地使用 find_package(Python)
)。
举个例子,如果你需要将 __init__.pyi
等文件同编译好的二进制文件一起被 ship 到安装目录的话,你需要在 CMakeLists.txt
文件中通过 install
命令显式地进行指定。
sdist
sdist 是一种分发 Python 软件包源码 (source code) 的格式,有点类似 Debian 包 .deb
对应的 .dsc
。
scikit-build-core 支持通过 pyproject.toml
指定构建 sdist 包,从而让用户能够下载 Python 包所需要的源码在本地进行构建。
sdist.include = []
sdist.exclude = []
sdist.reproducible = true
sdist.cmake = false
scikit-build-core 允许用户指定 include
、exclude
等字段批量 mark 需要被包含到 sdist 包中的文件。
如果需要在打包前运行一下 cmake (如 dump 版本号等操作),则通过 sdist.cmake
选项指定。
wheel
当然,scikit-build-core 同样也支持构建二进制分发的格式 .whl
:
wheel.exclude = ["**.pyx"]
wheel.py-api = "py3" # "cp38"