• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

.github/H25-Aug-2021-514469

cargo-crates/H03-May-2022-2,186,6991,756,551

ci/H25-Aug-2021-5240

maturin/H25-Aug-2021-12593

src/H03-May-2022-7,1925,719

sysconfig/H03-May-2022-21

test-crates/H25-Aug-2021-3,5162,901

test-data/H03-May-2022-21

tests/H25-Aug-2021-755606

.cirrus.ymlH A D25-Aug-2021782 2825

.dockerignoreH A D25-Aug-2021162 1716

.gitignoreH A D25-Aug-2021101 1413

Cargo.lockH A D25-Aug-202151.2 KiB2,1231,900

Cargo.tomlH A D25-Aug-20212.4 KiB8072

Changelog.mdH A D25-Aug-202120.1 KiB488319

Code-of-Conduct.mdH A D25-Aug-20213.2 KiB7555

DockerfileH A D25-Aug-20211.3 KiB4128

Platform Support.mdH A D25-Aug-20211.7 KiB1810

Readme.mdH A D25-Aug-202121.2 KiB485343

license-apacheH A D25-Aug-202110.6 KiB202169

license-mitH A D25-Aug-20211 KiB2622

pyproject.tomlH A D25-Aug-2021579 2218

setup.pyH A D03-May-20224.5 KiB12877

test-dockerfile.shH A D25-Aug-20212.3 KiB6536

Readme.md

1# Maturin
2
3_formerly pyo3-pack_
4
5[![Actions Status](https://github.com/PyO3/maturin/workflows/Run%20tests/badge.svg)](https://github.com/PyO3/maturin/actions)
6[![FreeBSD](https://img.shields.io/cirrus/github/PyO3/maturin/main?style=flat-square)](https://cirrus-ci.com/github/PyO3/maturin)
7[![Crates.io](https://img.shields.io/crates/v/maturin.svg?style=flat-square)](https://crates.io/crates/maturin)
8[![PyPI](https://img.shields.io/pypi/v/maturin.svg?style=flat-square)](https://pypi.org/project/maturin/)
9[![Chat on Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg?style=flat-square)](https://gitter.im/PyO3/Lobby)
10
11Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages.
12
13This project is meant as a zero configuration replacement for [setuptools-rust](https://github.com/PyO3/setuptools-rust) and [milksnake](https://github.com/getsentry/milksnake).
14It supports building wheels for python 3.5+ on windows, linux, mac and freebsd, can upload them to [pypi](https://pypi.org/) and has basic pypy support.
15
16## Usage
17
18You can either download binaries from the [latest release](https://github.com/PyO3/maturin/releases/latest) or install it with pip:
19
20```shell
21pip install maturin
22```
23
24There are three main commands:
25
26 * `maturin publish` builds the crate into python packages and publishes them to pypi.
27 * `maturin build` builds the wheels and stores them in a folder (`target/wheels` by default), but doesn't upload them. It's possible to upload those with [twine](https://github.com/pypa/twine).
28 * `maturin develop` builds the crate and installs it as a python module directly in the current virtualenv. Note that while `maturin develop` is faster, it doesn't support all the feature that running `pip install` after `maturin build` supports.
29
30`pyo3` and `rust-cpython` bindings are automatically detected, for cffi or binaries you need to pass `-b cffi` or `-b bin`.
31maturin doesn't need extra configuration files and doesn't clash with an existing setuptools-rust or milksnake configuration.
32You can even integrate it with testing tools such as [tox](https://tox.readthedocs.io/en/latest/).
33There are examples for the different bindings in the `test-crates` folder.
34
35The name of the package will be the name of the cargo project, i.e. the name field in the `[package]` section of `Cargo.toml`.
36The name of the module, which you are using when importing, will be the `name` value in the `[lib]` section (which defaults to the name of the package). For binaries, it's simply the name of the binary generated by cargo.
37
38## Python packaging basics
39
40Python packages come in two formats:
41A built form called wheel and source distributions (sdist), both of which are archives.
42A wheel can be compatible with any python version, interpreter (cpython and pypy, mainly), operating system and hardware architecture (for pure python wheels),
43can be limited to a specific platform and architecture (e.g. when using ctypes or cffi) or to a specific python interpreter and version on a specific architecture and operating system (e.g. with pyo3 and rust-cpython).
44
45When using `pip install` on a package, pip tries to find a matching wheel and install that. If it doesn't find one, it downloads the source distribution and builds a wheel for the current platform,
46which requires the right compilers to be installed. Installing a wheel is much faster than installing a source distribution as building wheels is generally slow.
47
48When you publish a package to be installable with `pip install`, you upload it to [pypi](https://pypi.org/), the official package repository.
49For testing, you can use [test pypi](https://test.pypi.org/) instead, which you can use with `pip install --index-url https://test.pypi.org/simple/`.
50Note that for publishing for linux, [you need to use the manylinux docker container](#manylinux-and-auditwheel).
51
52## pyo3 and rust-cpython
53
54For pyo3 and rust-cpython, maturin can only build packages for installed python versions. On linux and mac, all python versions in `PATH` are used.
55If you don't set your own interpreters with `-i`, a heuristic is used to search for python installations.
56On windows all versions from the python launcher (which is installed by default by the python.org installer) and all conda environments except base are used. You can check which versions are picked up with the `list-python` subcommand.
57
58pyo3 will set the used python interpreter in the environment variable `PYTHON_SYS_EXECUTABLE`, which can be used from custom build scripts.
59
60## Cffi
61
62Cffi wheels are compatible with all python versions including pypy. If `cffi` isn't installed and python is running inside a virtualenv, maturin will install it, otherwise you have to install it yourself (`pip install cffi`).
63
64maturin uses cbindgen to generate a header file, which can be customized by configuring cbindgen through a `cbindgen.toml` file inside your project root. Aternatively you can use a build script that writes a header file to `$PROJECT_ROOT/target/header.h`.
65
66Based on the header file maturin generates a module which exports an `ffi` and a `lib` object.
67
68<details>
69<summary>Example of a custom build script</summary>
70
71```rust
72use cbindgen;
73use std::env;
74use std::path::Path;
75
76fn main() {
77    let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
78
79    let bindings = cbindgen::Builder::new()
80        .with_no_includes()
81        .with_language(cbindgen::Language::C)
82        .with_crate(crate_dir)
83        .generate()
84        .unwrap();
85    bindings.write_to_file(Path::new("target").join("header.h"));
86}
87```
88
89</details>
90
91## Mixed rust/python projects
92
93To create a mixed rust/python project, create a folder with your module name (i.e. `lib.name` in Cargo.toml) next to your Cargo.toml and add your python sources there:
94
95```
96my-project
97├── Cargo.toml
98├── my_project
99│   ├── __init__.py
100│   └── bar.py
101├── pyproject.toml
102├── Readme.md
103└── src
104    └── lib.rs
105```
106
107You can specify a different python source directory in `Cargo.toml` by setting `package.metadata.maturin.python-source`, for example
108
109```toml
110[package.metadata.maturin]
111python-source = "python"
112```
113
114then the project structure would look like this:
115
116```
117my-project
118├── Cargo.toml
119├── python
120│   └── my_project
121│       ├── __init__.py
122│       ├── __init__.py
123│       └── bar.py
124├── pyproject.toml
125├── Readme.md
126└── src
127    └── lib.rs
128```
129
130maturin will add the native extension as a module in your python folder. When using develop, maturin will copy the native library and for cffi also the glue code to your python folder. You should add those files to your gitignore.
131
132With cffi you can do `from .my_project import lib` and then use `lib.my_native_function`, with pyo3/rust-cpython you can directly `from .my_project import my_native_function`.
133
134Example layout with pyo3 after `maturin develop`:
135
136```
137my-project
138├── Cargo.toml
139├── my_project
140│   ├── __init__.py
141│   ├── bar.py
142│   └── my_project.cpython-36m-x86_64-linux-gnu.so
143├── Readme.md
144└── src
145    └── lib.rs
146```
147
148## Python metadata
149
150maturin supports [PEP 621](https://www.python.org/dev/peps/pep-0621/), you can specify python package metadata in `pyproject.toml`.
151maturin merges metadata from `Cargo.toml` and `pyproject.toml`, `pyproject.toml` take precedence over `Cargo.toml`.
152
153To specify python dependencies, add a list `dependencies` in a `[project]` section in the `pyproject.toml`. This list is equivalent to `install_requires` in setuptools:
154
155```toml
156[project]
157dependencies = ["flask~=1.1.0", "toml==0.10.0"]
158```
159
160Pip allows adding so called console scripts, which are shell commands that execute some function in you program. You can add console scripts in a section `[project.scripts]`.
161The keys are the script names while the values are the path to the function in the format `some.module.path:class.function`, where the `class` part is optional. The function is called with no arguments. Example:
162
163```toml
164[project.scripts]
165get_42 = "my_project:DummyClass.get_42"
166```
167
168You can also specify [trove classifiers](https://pypi.org/classifiers/) in your Cargo.toml under `project.classifiers`:
169
170```toml
171[project]
172classifiers = ["Programming Language :: Python"]
173```
174
175## Source distribution
176
177maturin supports building through `pyproject.toml`. To use it, create a `pyproject.toml` next to your `Cargo.toml` with the following content:
178
179```toml
180[build-system]
181requires = ["maturin>=0.11,<0.12"]
182build-backend = "maturin"
183```
184
185If a `pyproject.toml` with a `[build-system]` entry is present, maturin will build a source distribution of your package, unless `--no-sdist` is specified.
186The source distribution will contain the same files as `cargo package`. To only build a source distribution, pass `--interpreter` without any values.
187
188You can then e.g. install your package with `pip install .`. With `pip install . -v` you can see the output of cargo and maturin.
189
190You can use the options `compatibility`, `skip-auditwheel`, `bindings`, `strip`, `cargo-extra-args` and `rustc-extra-args` under `[tool.maturin]` the same way you would when running maturin directly.
191The `bindings` key is required for cffi and bin projects as those can't be automatically detected. Currently, all builds are in release mode (see [this thread](https://discuss.python.org/t/pep-517-debug-vs-release-builds/1924) for details).
192
193For a non-manylinux build with cffi bindings you could use the following:
194
195```toml
196[build-system]
197requires = ["maturin>=0.11,<0.12"]
198build-backend = "maturin"
199
200[tool.maturin]
201bindings = "cffi"
202compatibility = "linux"
203```
204
205`manylinux` option is also accepted as an alias of `compatibility` for backward compatibility with old version of maturin.
206
207To include arbitrary files in the sdist for use during compilation specify `sdist-include` as an array of globs:
208
209```toml
210[tool.maturin]
211sdist-include = ["path/**/*"]
212```
213
214There's a `maturin sdist` command for only building a source distribution as workaround for [pypa/pip#6041](https://github.com/pypa/pip/issues/6041).
215
216## Manylinux and auditwheel
217
218For portability reasons, native python modules on linux must only dynamically link a set of very few libraries which are installed basically everywhere, hence the name manylinux.
219The pypa offers special docker images and a tool called [auditwheel](https://github.com/pypa/auditwheel/) to ensure compliance with the [manylinux rules](https://www.python.org/dev/peps/pep-0571/#the-manylinux2010-policy).
220If you want to publish widely usable wheels for linux pypi, **you need to use a manylinux docker image**.
221
222The Rust compiler since version 1.47 [requires at least glibc 2.11](https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1470-2020-10-08), so you need to use at least manylinux2010.
223For publishing, we recommend enforcing the same manylinux version as the image with the manylinux flag, e.g. use `--manylinux 2014` if you are building in `quay.io/pypa/manylinux2014_x86_64`.
224The [messense/maturin-action](https://github.com/messense/maturin-action) github action already takes care of this if you set e.g. `manylinux: 2014`.
225
226maturin contains a reimplementation of auditwheel automatically checks the generated library and gives the wheel the proper.
227If your system's glibc is too new or you link other shared libraries, it will assign the `linux` tag.
228You can also manually disable those checks and directly use native linux target with `--manylinux off`.
229
230For full manylinux compliance you need to compile in a CentOS docker container. The [konstin2/maturin](https://hub.docker.com/r/konstin2/maturin) image is based on the manylinux2010 image,
231and passes arguments to the `maturin` binary. You can use it like this:
232
233```
234docker run --rm -v $(pwd):/io konstin2/maturin build --release  # or other maturin arguments
235```
236
237Note that this image is very basic and only contains python, maturin and stable rust. If you need additional tools, you can run commands inside the manylinux container.
238See [konstin/complex-manylinux-maturin-docker](https://github.com/konstin/complex-manylinux-maturin-docker) for a small educational example or [nanoporetech/fast-ctc-decode](https://github.com/nanoporetech/fast-ctc-decode/blob/b226ea0f2b2f4f474eff47349703d57d2ea4801b/.github/workflows/publish.yml) for a real world setup.
239
240maturin itself is manylinux compliant when compiled for the musl target. The binaries on the release pages have additional keyring integration (through the `password-storage` feature), which is not manylinux compliant.
241
242## PyPy
243
244maturin can build and upload wheels for pypy with pyo3. This pypy has been only tested manually with pypy3.7-7.3 and on linux. See [#115](https://github.com/PyO3/maturin/issues/115) for more details.
245
246### Build
247
248```
249USAGE:
250    maturin build [FLAGS] [OPTIONS]
251
252FLAGS:
253    -h, --help
254            Prints help information
255
256        --no-sdist
257            Don't build a source distribution
258
259        --release
260            Pass --release to cargo
261
262        --skip-auditwheel
263            Don't check for manylinux compliance
264
265        --strip
266            Strip the library for minimum file size
267
268        --universal2
269            Control whether to build universal2 wheel for macOS or not. Only applies to macOS targets, do nothing
270            otherwise
271    -V, --version
272            Prints version information
273
274
275OPTIONS:
276    -m, --manifest-path <PATH>
277            The path to the Cargo.toml [default: Cargo.toml]
278
279        --target <TRIPLE>
280            The --target option for cargo [env: CARGO_BUILD_TARGET=]
281
282    -b, --bindings <bindings>
283            Which kind of bindings to use. Possible values are pyo3, rust-cpython, cffi and bin
284
285        --cargo-extra-args <cargo-extra-args>...
286            Extra arguments that will be passed to cargo as `cargo rustc [...] [arg1] [arg2] -- [...]`
287
288            Use as `--cargo-extra-args="--my-arg"`
289
290            Note that maturin invokes cargo twice: Once as `cargo metadata` and then as `cargo rustc`. maturin tries to
291            pass only the shared subset of options to cargo metadata, but this is may be a bit flaky.
292        --compatibility <compatibility>
293            Control the platform tag on linux.
294
295            Options are `manylinux` tags (for example `manylinux2014`/`manylinux_2_24`) or `musllinux` tags (for example
296            `musllinux_1_2`) and `linux` for the native linux tag.
297
298            Note that `manylinux1` is unsupported by the rust compiler. Wheels with the native `linux` tag will be
299            rejected by pypi, unless they are separately validated by `auditwheel`.
300
301            The default is the lowest compatible `manylinux` tag, or plain `linux` if nothing matched
302
303            This option is ignored on all non-linux platforms
304    -i, --interpreter <interpreter>...
305            The python versions to build wheels for, given as the names of the interpreters. Uses autodiscovery if not
306            explicitly set
307    -o, --out <out>
308            The directory to store the built wheels in. Defaults to a new "wheels" directory in the project's target
309            directory
310        --rustc-extra-args <rustc-extra-args>...
311            Extra arguments that will be passed to rustc as `cargo rustc [...] -- [...] [arg1] [arg2]`
312
313            Use as `--rustc-extra-args="--my-arg"`
314```
315### Publish
316
317```
318USAGE:
319    maturin publish [FLAGS] [OPTIONS]
320
321FLAGS:
322        --debug
323            Do not pass --release to cargo
324
325    -h, --help
326            Prints help information
327
328        --no-sdist
329            Don't build a source distribution
330
331        --no-strip
332            Do not strip the library for minimum file size
333
334        --skip-auditwheel
335            Don't check for manylinux compliance
336
337        --skip-existing
338            Continue uploading files if one already exists. (Only valid when uploading to PyPI. Other implementations
339            may not support this.)
340        --universal2
341            Control whether to build universal2 wheel for macOS or not. Only applies to macOS targets, do nothing
342            otherwise
343    -V, --version
344            Prints version information
345
346
347OPTIONS:
348    -m, --manifest-path <PATH>
349            The path to the Cargo.toml [default: Cargo.toml]
350
351        --target <TRIPLE>
352            The --target option for cargo [env: CARGO_BUILD_TARGET=]
353
354    -b, --bindings <bindings>
355            Which kind of bindings to use. Possible values are pyo3, rust-cpython, cffi and bin
356
357        --cargo-extra-args <cargo-extra-args>...
358            Extra arguments that will be passed to cargo as `cargo rustc [...] [arg1] [arg2] -- [...]`
359
360            Use as `--cargo-extra-args="--my-arg"`
361
362            Note that maturin invokes cargo twice: Once as `cargo metadata` and then as `cargo rustc`. maturin tries to
363            pass only the shared subset of options to cargo metadata, but this is may be a bit flaky.
364        --compatibility <compatibility>
365            Control the platform tag on linux.
366
367            Options are `manylinux` tags (for example `manylinux2014`/`manylinux_2_24`) or `musllinux` tags (for example
368            `musllinux_1_2`) and `linux` for the native linux tag.
369
370            Note that `manylinux1` is unsupported by the rust compiler. Wheels with the native `linux` tag will be
371            rejected by pypi, unless they are separately validated by `auditwheel`.
372
373            The default is the lowest compatible `manylinux` tag, or plain `linux` if nothing matched
374
375            This option is ignored on all non-linux platforms
376    -i, --interpreter <interpreter>...
377            The python versions to build wheels for, given as the names of the interpreters. Uses autodiscovery if not
378            explicitly set
379    -o, --out <out>
380            The directory to store the built wheels in. Defaults to a new "wheels" directory in the project's target
381            directory
382    -p, --password <password>
383            Password for pypi or your custom registry. Note that you can also pass the password through MATURIN_PASSWORD
384
385    -r, --repository-url <registry>
386            The url of registry where the wheels are uploaded to [default: https://upload.pypi.org/legacy/]
387
388        --rustc-extra-args <rustc-extra-args>...
389            Extra arguments that will be passed to rustc as `cargo rustc [...] -- [...] [arg1] [arg2]`
390
391            Use as `--rustc-extra-args="--my-arg"`
392    -u, --username <username>
393            Username for pypi or your custom registry
394```
395
396### Develop
397
398```
399USAGE:
400    maturin develop [FLAGS] [OPTIONS]
401
402FLAGS:
403    -h, --help
404            Prints help information
405
406        --release
407            Pass --release to cargo
408
409        --strip
410            Strip the library for minimum file size
411
412    -V, --version
413            Prints version information
414
415
416OPTIONS:
417    -b, --binding-crate <binding-crate>
418            Which kind of bindings to use. Possible values are pyo3, rust-cpython, cffi and bin
419
420        --cargo-extra-args <cargo-extra-args>...
421            Extra arguments that will be passed to cargo as `cargo rustc [...] [arg1] [arg2] --`
422
423            Use as `--cargo-extra-args="--my-arg"`
424    -m, --manifest-path <manifest-path>
425            The path to the Cargo.toml [default: Cargo.toml]
426
427        --rustc-extra-args <rustc-extra-args>...
428            Extra arguments that will be passed to rustc as `cargo rustc [...] -- [arg1] [arg2]`
429
430            Use as `--rustc-extra-args="--my-arg"`
431```
432
433### Upload
434
435```
436Uploads python packages to pypi
437
438It is mostly similar to `twine upload`, but can only upload python wheels and source distributions.
439
440USAGE:
441    maturin upload [FLAGS] [OPTIONS] [FILE]...
442
443FLAGS:
444    -h, --help
445            Prints help information
446
447        --skip-existing
448            Continue uploading files if one already exists. (Only valid when uploading to PyPI. Other implementations
449            may not support this.)
450    -V, --version
451            Prints version information
452
453
454OPTIONS:
455    -p, --password <password>
456            Password for pypi or your custom registry. Note that you can also pass the password through MATURIN_PASSWORD
457
458    -r, --repository-url <registry>
459            The url of registry where the wheels are uploaded to [default: https://upload.pypi.org/legacy/]
460
461    -u, --username <username>
462            Username for pypi or your custom registry
463
464
465ARGS:
466    <FILE>...
467            The python packages to upload
468
469```
470
471## Code
472
473The main part is the maturin library, which is completely documented and should be well integrable. The accompanying `main.rs` takes care username and password for the pypi upload and otherwise calls into the library.
474
475The `sysconfig` folder contains the output of `python -m sysconfig` for different python versions and platform, which is helpful during development.
476
477You need to install `cffi` and `virtualenv` (`pip install cffi virtualenv`) to run the tests.
478
479There are some optional hacks that can speed up the tests (over 80s to 17s on my machine).
4801. By running `cargo build --release --manifest-path test-crates/cargo-mock/Cargo.toml` you can activate a cargo cache avoiding to rebuild the pyo3 test crates with every python version.
4812. Delete `target/test-cache` to clear the cache (e.g. after changing a test crate) or remove `test-crates/cargo-mock/target/release/cargo` to deactivate it.
4823. By running the tests with the `faster-tests` feature, binaries are stripped and wheels are only stored and not compressed.
483
484You might want to have look into my by now slightly outdated [blog post](https://blog.schuetze.link/2018/07/21/a-dive-into-packaging-native-python-extensions.html) which explains the intricacies of building native python packages.
485