Setuptools Rust extension plugin
—
Configuration and building of Rust extensions as Python modules or standalone binaries. setuptools-rust provides comprehensive support for different binding types, cross-compilation, build customization, and integration with the Python packaging ecosystem.
Define Rust extensions that will be built as Python modules, with full control over build options, features, and binding types.
class RustExtension:
def __init__(
self,
target: Union[str, Dict[str, str]],
path: str = "Cargo.toml",
args: Optional[Sequence[str]] = (),
cargo_manifest_args: Optional[Sequence[str]] = (),
features: Optional[Sequence[str]] = (),
rustc_flags: Optional[Sequence[str]] = (),
rust_version: Optional[str] = None,
quiet: bool = False,
debug: Optional[bool] = None,
binding: Binding = Binding.PyO3,
strip: Strip = Strip.No,
script: bool = False,
native: bool = False,
optional: bool = False,
py_limited_api: Literal["auto", True, False] = "auto",
env: Optional[Dict[str, str]] = None,
):
"""
Configure a Rust extension for building as a Python module.
Parameters:
- target: Extension target name or dict mapping target to module name
- path: Path to Cargo.toml file (default: "Cargo.toml")
- args: Additional arguments passed to cargo build
- cargo_manifest_args: Arguments passed to cargo for manifest operations
- features: List of Cargo features to enable
- rustc_flags: Additional flags passed to rustc
- rust_version: Minimum required Rust version
- quiet: Suppress cargo output during build
- debug: Enable debug build (None uses setuptools debug setting)
- binding: Binding type (PyO3, RustCPython, NoBinding, Exec)
- strip: Symbol stripping mode (No, Debug, All)
- script: Install as console script
- native: Use native target (no cross-compilation)
- optional: Mark extension as optional (build failures won't stop installation)
- py_limited_api: Python limited API compatibility
- env: Environment variables for the build process
"""
def get_lib_name(self, *, quiet: bool) -> str:
"""
Parse Cargo.toml to get the shared library name.
Parameters:
- quiet: Suppress output during parsing
Returns:
str: The shared library name from Cargo.toml
"""
def get_rust_version(self) -> Optional[SimpleSpec]:
"""
Get parsed Rust version requirement.
Returns:
Optional[SimpleSpec]: Parsed version requirement or None
"""
def get_cargo_profile(self) -> Optional[str]:
"""
Extract cargo profile from build arguments.
Returns:
Optional[str]: Cargo profile name or None
"""
def entry_points(self) -> List[str]:
"""
Generate console script entry points for the extension.
Returns:
List[str]: List of entry point specifications
"""
def install_script(self, module_name: str, exe_path: str) -> None:
"""
Install console script for the extension.
Parameters:
- module_name: Name of the Python module
- exe_path: Path to the executable
"""
def metadata(self, *, quiet: bool) -> CargoMetadata:
"""
Get cargo metadata for the extension (cached).
Parameters:
- quiet: Suppress cargo output
Returns:
CargoMetadata: Cargo metadata dictionary
"""Define Rust binaries that will be built as standalone executables, inheriting most functionality from RustExtension but with binary-specific behavior.
class RustBin(RustExtension):
def __init__(
self,
target: Union[str, Dict[str, str]],
path: str = "Cargo.toml",
args: Optional[Sequence[str]] = (),
cargo_manifest_args: Optional[Sequence[str]] = (),
features: Optional[Sequence[str]] = (),
rust_version: Optional[str] = None,
quiet: bool = False,
debug: Optional[bool] = None,
strip: Strip = Strip.No,
optional: bool = False,
env: Optional[dict[str, str]] = None,
):
"""
Configure a Rust binary for building as a standalone executable.
Parameters: Same as RustExtension except:
- No binding parameter (always uses Exec binding)
- No script, native, or py_limited_api parameters
"""
def entry_points(self) -> List[str]:
"""
Generate entry points for binary (returns empty list).
Returns:
List[str]: Empty list (binaries don't create console scripts)
"""Enumeration of supported Rust-Python binding types, determining how the Rust code interfaces with Python.
class Binding(IntEnum):
PyO3 = auto() # Extension built using PyO3 bindings
RustCPython = auto() # Extension built using rust-cpython bindings
NoBinding = auto() # Bring your own bindings
Exec = auto() # Build executable instead of extension
def __repr__(self) -> str:
"""String representation of the binding type."""Control symbol stripping in built extensions for size optimization and debugging.
class Strip(IntEnum):
No = auto() # Do not strip symbols
Debug = auto() # Strip debug symbols only
All = auto() # Strip all symbols
def __repr__(self) -> str:
"""String representation of the stripping mode."""from setuptools import setup
from setuptools_rust import RustExtension, Binding
setup(
name="my-pyo3-extension",
rust_extensions=[
RustExtension(
"my_package.rust_module",
path="rust/Cargo.toml",
binding=Binding.PyO3,
features=["python-extension"],
)
],
zip_safe=False,
)RustExtension(
"my_package.cross_compiled",
path="Cargo.toml",
args=["--target", "x86_64-pc-windows-gnu"],
env={"CARGO_BUILD_TARGET": "x86_64-pc-windows-gnu"},
)RustExtension(
"my_package.debug_module",
path="Cargo.toml",
debug=True,
features=["debugging", "profiling"],
rustc_flags=["-C", "debuginfo=2"],
)RustExtension(
"my_package.optional_rust",
path="optional/Cargo.toml",
optional=True, # Build failure won't stop installation
quiet=True, # Suppress cargo output
)from setuptools import setup
from setuptools_rust import RustBin, Strip
setup(
name="my-rust-tools",
rust_extensions=[
RustBin(
"my-cli-tool",
path="cli/Cargo.toml",
strip=Strip.All, # Strip all symbols for smaller binary
)
],
)from typing import Union, Dict, List, Optional, Sequence, Literal, Any, NewType
from enum import IntEnum, auto
CargoMetadata = NewType("CargoMetadata", Dict[str, Any])
class SimpleSpec:
"""Parsed Rust version requirement specification."""
class _BuiltModule:
"""Internal type representing a built module."""Install with Tessl CLI
npx tessl i tessl/pypi-setuptools-rust