目录
打包编译项目
打包编译项目有多种方法。过去,唯一的方法是使用 setuptools/distutils,这需要使用大量脆弱的内部机制 - distutils 主要用于编译 CPython,而 setuptools 则尽量避免更改编译部分,除非必要。但是,现在我们有了一些非常好的编译包选项!
最令人兴奋的进展是新的原生构建后端
- scikit-build-core:使用 CMake 构建 C/C++/Fortran。
- meson-python:使用 Meson 构建 C/C++/Fortran。
- maturin:使用 Cargo 构建 Rust。完全用 Rust 编写!
- enscons:使用 SCONs 构建 C/C++。(现在正在老化,但这是第一个原生后端!)
您应该熟悉 打包纯 Python 项目 - 元数据配置相同。
还有一些经典的 setuptools 插件
- scikit-build:使用 CMake 构建 C/C++/Fortran。
- setuptools-rust:使用 Cargo 构建 Rust。
如果您有一个非常复杂的构建,较新的原生构建后端可能尚不支持您的用例,但如果是这种情况,请询问 - 开发是由社区需求驱动的。如果您确实需要这种灵活性来实现原生后端尚未实现的功能,则较旧、更脆弱的基于 setuptools 的插件仍然更灵活一些。
pyproject.toml:build-system
PY001 包必须具有 pyproject.toml
文件 PP001 以选择后端
[build-system]
requires = ["scikit-build-core"]
build-backend = "scikit_build_core.build"
pyproject.toml:项目表
元数据以 基于标准 的格式指定
[project]
name = "package"
description = "A great package."
readme = "README.md"
authors = [
{ name = "My Name", email = "me@email.com" },
]
maintainers = [
{ name = "My Organization", email = "myemail@email.com" },
]
requires-python = ">=3.9"
dependencies = [
"typing_extensions",
]
classifiers = [
"Development Status :: 4 - Beta",
"License :: OSI Approved :: BSD License",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering :: Physics",
]
[project.urls]
Homepage = "https://github.com/organization/package"
Documentation = "https://package.readthedocs.io/"
"Bug Tracker" = "https://github.com/organization/package/issues"
Discussions = "https://github.com/organization/package/discussions"
Changelog = "https://package.readthedocs.io/en/latest/changelog.html"
您可以在 packaging.python.org、Flit 或 Whey 中阅读有关每个字段以及所有允许字段的更多信息。请注意,“主页”是特殊的,它替换了旧的 url 设置。
额外功能
建议使用额外功能来代替或除了创建需求文件。这些额外功能 a) 正确地与安装需求和其他内置工具交互,b) 通过 PyPI 安装时直接可用,以及 c) 在 requirements.txt
、install_requires
、pyproject.toml
和大多数其他传递需求的位置中允许。
这是一个简单额外功能的示例
[project.optional-dependencies]
test = [
"pytest >=6.0",
]
mpl = [
"matplotlib >=2.0",
]
可以通过使用包的名称来使用自依赖项,例如 dev = ["package[test,examples]"]
,但这需要 Pip 21.2 或更高版本。我们建议至少提供 test
和 docs
。
命令行
如果要发布用户可以从命令行运行的“应用程序”,则需要添加 script
入口点。格式为
[project.scripts]
cliapp = "package.__main__:main"
格式为命令行应用程序名称作为键,值为函数路径,后跟冒号,然后是调用的函数。如果您使用 __main__.py
作为文件,则 python -m
后跟模块也将工作以调用应用程序(在这种情况下,__name__
将为 "__main__"
)。
pyproject.toml 中的工具部分
这些工具都读取项目表。它们在 tool.*
设置中还有其他配置选项。
后端特定文件
示例 CMakeLists.txt
文件(使用 pybind11,因此也在 build-system.requires
中包含 pybind11
)
cmake_minimum_required(VERSION 3.15...3.26)
project(${SKBUILD_PROJECT_NAME} LANGUAGES CXX)
set(PYBIND11_FINDPYTHON ON)
find_package(pybind11 CONFIG REQUIRED)
pybind11_add_module(_core MODULE src/main.cpp)
install(TARGETS _core DESTINATION ${SKBUILD_PROJECT_NAME})
编译文件示例
示例 src/main.cpp
文件
#include <pybind11/pybind11.h>
int add(int i, int j) { return i + j; }
namespace py = pybind11;
PYBIND11_MODULE(_core, m) {
m.doc() = R"pbdoc(
Pybind11 example plugin
-----------------------
.. currentmodule:: python_example
.. autosummary::
:toctree: _generate
add
subtract
)pbdoc";
m.def("add", &add, R"pbdoc(
Add two numbers
Some other explanation about the add function.
)pbdoc");
m.def("subtract", [](int i, int j) { return i - j; }, R"pbdoc(
Subtract two numbers
Some other explanation about the subtract function.
)pbdoc");
}
包结构
建议(如上所述)是在 /src
中放置源代码,并在 /src/<package>
中放置 Python 包文件。
版本控制
查看上述工具的文档以了解工具支持的动态版本控制形式。
在 SDist 中包含/排除文件
每个工具都使用不同的机制来包含或删除 SDist 中的文件,尽管默认值是合理的。
分发
与纯 Python 不同,如果您想避免在用户系统上进行编译,则需要为每个平台和受支持的 Python 版本构建可重新分发的 wheel。有关建议的工作流程,请参阅 有关 wheel 的 CI 页面。
特殊注意事项
NumPy
现代版本的 NumPy (1.25+) 允许您在构建时针对较旧的版本,这 *强烈* 建议,这将在 NumPy 2.0 中成为必需。现在您添加
#define NPY_TARGET_VERSION NPY_1_22_API_VERSION
(其中该数字是您作为最小值支持的任何版本)然后确保您使用 NumPy 1.25+(或 2.0+,当它发布时)进行构建。在 1.25 之前,需要实际固定您支持的最旧的 NumPy(oldest-supported-numpy
包是最简单的方法)。如果您支持 Python < 3.9,则必须对这些版本使用旧方法。
如果使用 pybind11,则首先根本不需要在构建时使用 NumPy。