@@ -8,6 +8,24 @@ parent: Topical Guides
88
99{% include toc.html %}
1010
11+ <!-- [[[cog
12+ from cog_helpers import code_fence, render_cookie, TOMLMatcher
13+ with render_cookie(backend="skbuild", vcs=False) as skbuild:
14+ skbuild_cmakelists_txt = skbuild.joinpath("CMakeLists.txt").read_text(encoding="utf-8").strip()
15+ skbuild_src_main_cpp = skbuild.joinpath("src/main.cpp").read_text(encoding="utf-8").strip()
16+ skbuild_pyproject = TOMLMatcher.from_file(skbuild / "pyproject.toml")
17+ with render_cookie(backend="mesonpy", vcs=False) as mesonpy:
18+ mesonpy_meson_build = mesonpy.joinpath("meson.build").read_text(encoding="utf-8").strip()
19+ mesonpy_src_main_cpp = mesonpy.joinpath("src/main.cpp").read_text(encoding="utf-8").strip()
20+ mesonpy_pyproject = TOMLMatcher.from_file(mesonpy / "pyproject.toml")
21+ assert "tool.meson-python" not in mesonpy_pyproject
22+ with render_cookie(backend="maturin", vcs=False) as maturin:
23+ maturin_cargo_toml = maturin.joinpath("Cargo.toml").read_text(encoding="utf-8").strip()
24+ maturin_src_lib_rs = maturin.joinpath("src/lib.rs").read_text(encoding="utf-8").strip()
25+ maturin_pyproject = TOMLMatcher.from_file(maturin / "pyproject.toml")
26+ ]]] -->
27+ <!-- [[[end]]] -->
28+
1129# Packaging Compiled Projects
1230
1331There are a variety of ways to package compiled projects. In the past, the only
@@ -52,27 +70,48 @@ selects the backend:
5270
5371{% tabs %} {% tab skbc Scikit-build-core %}
5472
73+ <!-- [[[cog
74+ with code_fence("toml"):
75+ print(skbuild_pyproject.get_source("build-system"))
76+ ]]] -->
77+ <!-- prettier-ignore-start -->
5578``` toml
5679[build-system ]
57- requires = [" scikit-build-core" ]
80+ requires = [" pybind11 " , " scikit-build-core>=0.11 " ]
5881build-backend = " scikit_build_core.build"
5982```
83+ <!-- prettier-ignore-end -->
84+ <!-- [[[end]]] -->
6085
6186{% endtab %} {% tab meson Meson-python %}
6287
88+ <!-- [[[cog
89+ with code_fence("toml"):
90+ print(mesonpy_pyproject.get_source("build-system"))
91+ ]]] -->
92+ <!-- prettier-ignore-start -->
6393``` toml
6494[build-system ]
65- requires = [" meson-python" ]
95+ requires = [" meson-python>=0.18 " , " pybind11 " ]
6696build-backend = " mesonpy"
6797```
98+ <!-- prettier-ignore-end -->
99+ <!-- [[[end]]] -->
68100
69101{% endtab %} {% tab maturin Maturin %}
70102
103+ <!-- [[[cog
104+ with code_fence("toml"):
105+ print(maturin_pyproject.get_source("build-system"))
106+ ]]] -->
107+ <!-- prettier-ignore-start -->
71108``` toml
72109[build-system ]
73- requires = [" maturin" ]
110+ requires = [" maturin>=1.9,<2 " ]
74111build-backend = " maturin"
75112```
113+ <!-- prettier-ignore-end -->
114+ <!-- [[[end]]] -->
76115
77116{% endtab %} {% endtabs %}
78117
@@ -83,20 +122,49 @@ build-backend = "maturin"
83122These tools all read the project table. They also have extra configuration
84123options in ` tool.* ` settings.
85124
125+ {% tabs %} {% tab skbc Scikit-build-core %}
126+
86127<!-- [[[cog
87- from cog_helpers import code_fence, render_cookie
88- with render_cookie(backend="skbuild") as skbuild:
89- skbuild_cmakelists_txt = skbuild.joinpath("CMakeLists.txt").read_text(encoding="utf-8").strip()
90- skbuild_src_main_cpp = skbuild.joinpath("src/main.cpp").read_text(encoding="utf-8").strip()
91- with render_cookie(backend="mesonpy") as mesonpy:
92- mesonpy_meson_build = mesonpy.joinpath("meson.build").read_text(encoding="utf-8").strip()
93- mesonpy_src_main_cpp = mesonpy.joinpath("src/main.cpp").read_text(encoding="utf-8").strip()
94- with render_cookie(backend="maturin") as maturin:
95- maturin_cargo_toml = maturin.joinpath("Cargo.toml").read_text(encoding="utf-8").strip()
96- maturin_src_lib_rs = maturin.joinpath("src/lib.rs").read_text(encoding="utf-8").strip()
128+ with code_fence("toml"):
129+ print(skbuild_pyproject.get_source("tool.scikit-build"))
97130]]] -->
131+ <!-- prettier-ignore-start -->
132+ ``` toml
133+ [tool .scikit-build ]
134+ minimum-version = " build-system.requires"
135+ build-dir = " build/{wheel_tag}"
136+ ```
137+ <!-- prettier-ignore-end -->
98138<!-- [[[end]]] -->
99139
140+ These options are not required, but can improve your experience.
141+
142+ {% endtab %} {% tab meson Meson-python %}
143+
144+ No ` tool.meson-python ` configuration required for this example.
145+
146+ {% endtab %} {% tab maturin Maturin %}
147+
148+ <!-- [[[cog
149+ with code_fence("toml"):
150+ print(maturin_pyproject.get_source("tool.maturin"))
151+ ]]] -->
152+ <!-- prettier-ignore-start -->
153+ ``` toml
154+ [tool .maturin ]
155+ module-name = " package._core"
156+ python-packages = [" package" ]
157+ python-source = " src"
158+ sdist-generator = " git" # default is cargo
159+ ```
160+ <!-- prettier-ignore-end -->
161+ <!-- [[[end]]] -->
162+
163+ Maturin assumes you follow Rust's package structure, so we need a little bit of
164+ configuration here to follow the convention of the other tools here.
165+
166+ {% endtab %} {% endtabs %}
167+
100168## Backend specific files
101169
102170{% tabs %} {% tab skbc Scikit-build-core %}
@@ -180,18 +248,18 @@ with code_fence("toml"):
180248[package ]
181249name = " package"
182250version = " 0.1.0"
183- edition = " 2018 "
251+ edition = " 2021 "
184252
185253[lib ]
186254name = " _core"
187255# "cdylib" is necessary to produce a shared library for Python to import from.
188256crate-type = [" cdylib" ]
189257
190258[dependencies ]
191- rand = " 0.8.3 "
259+ rand = " 0.9.2 "
192260
193261[dependencies .pyo3 ]
194- version = " 0.19.1 "
262+ version = " 0.27.2 "
195263# "extension-module" tells pyo3 we want to build an extension module (skips linking against libpython.so)
196264# "abi3-py310" tells pyo3 (and maturin) to build using the stable ABI with minimum Python version 3.10
197265features = [" extension-module" , " abi3-py310" ]
@@ -302,26 +370,29 @@ with code_fence("rs"):
302370``` rs
303371use pyo3 :: prelude :: * ;
304372
305- #[pyfunction]
306- fn add (x : i64 , y : i64 ) -> i64 {
307- x + y
308- }
309-
310- #[pyfunction]
311- fn subtract (x : i64 , y : i64 ) -> i64 {
312- x - y
313- }
314-
315373/// A Python module implemented in Rust. The name of this function must match
316374/// the `lib.name` setting in the `Cargo.toml`, else Python will not be able to
317375/// import the module.
318376#[pymodule]
319- fn _core (_py : Python , m : & PyModule ) -> PyResult <()> {
320- m . add_function (wrap_pyfunction! (add , m )? )? ;
321- m . add_function (wrap_pyfunction! (subtract , m )? )? ;
322- m . add (" __version__" , env! (" CARGO_PKG_VERSION" ))? ;
377+ mod _core {
378+ use super :: * ;
379+
380+ #[pyfunction]
381+ fn add (x : i64 , y : i64 ) -> i64 {
382+ x + y
383+ }
384+
385+ #[pyfunction]
386+ fn subtract (x : i64 , y : i64 ) -> i64 {
387+ x - y
388+ }
389+
323390
324- Ok (())
391+ #[pymodule_init]
392+ fn pymodule_init (m : & Bound <'_ , PyModule >) -> PyResult <()> {
393+ m . add (" __version__" , env! (" CARGO_PKG_VERSION" ))? ;
394+ Ok (())
395+ }
325396}
326397```
327398<!-- prettier-ignore-end -->
@@ -332,7 +403,8 @@ fn _core(_py: Python, m: &PyModule) -> PyResult<()> {
332403## Package structure
333404
334405The recommendation (followed above) is to have source code in ` /src ` , and the
335- Python package files in ` /src/<package> ` .
406+ Python package files in ` /src/<package> ` . The compiled files also can go in
407+ ` /src ` .
336408
337409## Versioning
338410
@@ -348,25 +420,26 @@ though the defaults are reasonable.
348420
349421Unlike pure Python, you'll need to build redistributable wheels for each
350422platform and supported Python version if you want to avoid compilation on the
351- user's system. See [ the CI page on wheels] [ gha_wheels ] for a suggested workflow.
423+ user's system using cibuildwheel. See [ the CI page on wheels] [ gha_wheels ] for a
424+ suggested workflow.
352425
353426## Special considerations
354427
355428### NumPy
356429
357430Modern versions of NumPy (1.25+) allow you to target older versions when
358- building, which is _ highly_ recommended, and this will become required in NumPy
359- 2.0. Now you add:
431+ building, which is _ highly_ recommended, and this became required in NumPy 2.0.
432+ Now you add:
360433
361434``` cpp
362435#define NPY_TARGET_VERSION NPY_1_22_API_VERSION
363436```
364437
365438(Where that number is whatever version you support as a minimum) then make sure
366- you build with NumPy 1.25+ (or 2.0+ when it comes out ). Before 1.25, it was
367- necessary to actually pin the oldest NumPy you supported (the
368- `oldest-supported-numpy` package is the easiest method). If you support Python <
369- 3.9, you'll have to use the old method for those versions.
439+ you build with NumPy 1.25+ (or 2.0+). Before 1.25, it was necessary to actually
440+ pin the oldest NumPy you supported (the `oldest-supported-numpy` package is the
441+ easiest method). If you support Python < 3.9, you'll have to use the old method
442+ for those versions.
370443
371444If using pybind11, you don't need NumPy at build-time in the first place.
372445
0 commit comments