콘텐츠로 이동

Maturin Cheat Sheet

Overview

Maturin is a build tool for building and publishing Python packages with Rust extensions (via PyO3, rust-cpython, or cffi bindings). It compiles Rust code into native Python extension modules and packages them as wheels that can be installed with pip. Maturin handles cross-compilation, manylinux compliance, and multi-platform builds.

Maturin integrates with the Python packaging ecosystem as a PEP 517 build backend, meaning it works seamlessly with pip, build, and other standard tools. It supports building for multiple Python versions, architectures, and operating systems from a single command.

Installation

# Via pip
pip install maturin

# Via pipx
pipx install maturin

# Via cargo
cargo install maturin

# macOS
brew install maturin

# Verify
maturin --version

Core Commands

CommandDescription
maturin initInitialize a new project
maturin new <name>Create new project from template
maturin developBuild and install locally for development
maturin buildBuild wheel packages
maturin publishBuild and publish to PyPI
maturin sdistBuild source distribution
maturin uploadUpload pre-built wheels
maturin list-pythonList detected Python installations
maturin generate-ciGenerate CI configuration

Project Setup

Create New Project

# Create with PyO3 bindings (default)
maturin new my-rust-lib
cd my-rust-lib

# Create with cffi bindings
maturin new --bindings cffi my-cffi-lib

# Initialize in existing directory
maturin init --bindings pyo3

Project Structure

my-rust-lib/
  Cargo.toml
  pyproject.toml
  src/
    lib.rs
  python/
    my_rust_lib/
      __init__.py

Cargo.toml

[package]
name = "my-rust-lib"
version = "0.1.0"
edition = "2021"

[lib]
name = "my_rust_lib"
crate-type = ["cdylib"]

[dependencies]
pyo3 = { version = "0.22", features = ["extension-module"] }

pyproject.toml

[build-system]
requires = ["maturin>=1.0,<2.0"]
build-backend = "maturin"

[project]
name = "my-rust-lib"
version = "0.1.0"
description = "A Python library written in Rust"
requires-python = ">=3.9"

[tool.maturin]
python-source = "python"
features = ["pyo3/extension-module"]
module-name = "my_rust_lib._core"

Rust Code (PyO3)

// src/lib.rs
use pyo3::prelude::*;

#[pyfunction]
fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
    Ok((a + b).to_string())
}

#[pyfunction]
fn fibonacci(n: u64) -> PyResult<u64> {
    let mut a: u64 = 0;
    let mut b: u64 = 1;
    for _ in 0..n {
        let temp = b;
        b = a + b;
        a = temp;
    }
    Ok(a)
}

#[pymodule]
fn my_rust_lib(m: &Bound<'_, PyModule>) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
    m.add_function(wrap_pyfunction!(fibonacci, m)?)?;
    Ok(())
}

Development Workflow

# Build and install in current virtualenv (editable-like)
maturin develop

# With release optimizations
maturin develop --release

# With specific Python
maturin develop --interpreter python3.12

# With extra features
maturin develop --features "feature1,feature2"

# Build wheel for distribution
maturin build --release

# Build for specific Python versions
maturin build --release --interpreter python3.10 python3.11 python3.12

Configuration

Cross-Compilation

# Build for Linux (manylinux)
maturin build --release --target x86_64-unknown-linux-gnu

# Build for macOS universal
maturin build --release --target universal2-apple-darwin

# Build for Windows
maturin build --release --target x86_64-pc-windows-msvc

# Build manylinux wheels (using Docker)
maturin build --release --manylinux 2_28

Advanced pyproject.toml

[tool.maturin]
# Python source directory
python-source = "python"

# Rust features to enable
features = ["pyo3/extension-module"]

# Strip debug symbols
strip = true

# Module name (if different from package)
module-name = "my_package._native"

# Manylinux compatibility
manylinux = "2_28"

# Include additional data files
include = [
    { path = "LICENSE", format = "sdist" },
    { path = "py.typed", format = "wheel" },
]

# Exclude files
exclude = ["tests/", "benches/"]

Advanced Usage

Publishing

# Publish to PyPI
maturin publish --username __token__ --password pypi-xxx

# Publish to Test PyPI
maturin publish --repository-url https://test.pypi.org/legacy/

# Build and upload separately
maturin build --release
maturin upload target/wheels/*.whl

CI/CD Generation

# Generate GitHub Actions workflow
maturin generate-ci github > .github/workflows/ci.yml

# Generate for multiple platforms
maturin generate-ci --platform linux --platform macos --platform windows github

Python Classes from Rust

use pyo3::prelude::*;

#[pyclass]
struct Calculator {
    value: f64,
}

#[pymethods]
impl Calculator {
    #[new]
    fn new() -> Self {
        Calculator { value: 0.0 }
    }

    fn add(&mut self, n: f64) {
        self.value += n;
    }

    fn result(&self) -> f64 {
        self.value
    }

    fn __repr__(&self) -> String {
        format!("Calculator(value={})", self.value)
    }
}

#[pymodule]
fn my_rust_lib(m: &Bound<'_, PyModule>) -> PyResult<()> {
    m.add_class::<Calculator>()?;
    Ok(())
}

Async Support

use pyo3::prelude::*;
use pyo3_asyncio_0_21::tokio::future_into_py;

#[pyfunction]
fn fetch_url<'py>(py: Python<'py>, url: String) -> PyResult<Bound<'py, PyAny>> {
    future_into_py(py, async move {
        let response = reqwest::get(&url).await.map_err(|e| {
            pyo3::exceptions::PyIOError::new_err(e.to_string())
        })?;
        let text = response.text().await.map_err(|e| {
            pyo3::exceptions::PyIOError::new_err(e.to_string())
        })?;
        Ok(text)
    })
}

Troubleshooting

IssueSolution
maturin develop failsActivate virtualenv first; check Rust toolchain
Import error after buildVerify module-name in pyproject.toml matches
Manylinux build failsUse --manylinux off for testing; check glibc version
Cross-compile errorsInstall target: rustup target add <target>
PyO3 version mismatchMatch PyO3 version with maturin compatibility
Slow buildsUse maturin develop (debug) for iteration
# List available Python interpreters
maturin list-python

# Build with verbose output
maturin build -v

# Check what would be built
maturin build --release --out dist/
ls dist/

# Debug: show resolved configuration
maturin develop -v 2>&1 | head -20