Setuptools Rust extension plugin
—
Distutils commands for building and cleaning Rust extensions, providing seamless integration with standard Python packaging workflows. These commands handle the cargo build process and manage build artifacts.
Build Rust extensions using cargo, with support for cross-compilation, custom build options, and integration with Python packaging.
class build_rust(RustCommand):
description = "build Rust extensions (compile/link to build directory)"
user_options = [
(
"inplace",
"i",
"ignore build-lib and put compiled extensions into the source "
+ "directory alongside your pure Python modules",
),
("debug", "d", "Force debug to true for all Rust extensions "),
("release", "r", "Force debug to false for all Rust extensions "),
("qbuild", None, "Force enable quiet option for all Rust extensions "),
(
"build-temp",
"t",
"directory for temporary files (cargo 'target' directory) ",
),
("target=", None, "Build for the target triple"),
]
boolean_options = ["inplace", "debug", "release", "qbuild"]
def initialize_options(self) -> None:
"""Initialize all command options to default values."""
def finalize_options(self) -> None:
"""Finalize and validate command options."""
def run_for_extension(self, ext: RustExtension) -> None:
"""
Build a single Rust extension.
Parameters:
- ext: RustExtension instance to build
"""
def build_extension(
self,
ext: RustExtension,
forced_target_triple: Optional[str] = None
) -> List[_BuiltModule]:
"""
Build a Rust extension using cargo.
Parameters:
- ext: RustExtension to build
- forced_target_triple: Override target triple for cross-compilation
Returns:
List[_BuiltModule]: List of built module information
"""
def install_extension(
self,
ext: RustExtension,
dylib_paths: List[_BuiltModule]
) -> None:
"""
Install built extension to the appropriate location.
Parameters:
- ext: RustExtension that was built
- dylib_paths: List of built modules to install
"""
def get_dylib_ext_path(
self,
ext: RustExtension,
target_fname: str
) -> str:
"""
Get the installation path for a built extension.
Parameters:
- ext: RustExtension being installed
- target_fname: Target filename
Returns:
str: Full path where extension should be installed
"""
def install_extension(
self,
ext: RustExtension,
dylib_paths: List[_BuiltModule]
) -> None:
"""
Install built extension to the appropriate location.
Parameters:
- ext: RustExtension that was built
- dylib_paths: List of built modules to install
"""Clean build artifacts and temporary files created during Rust extension building.
class clean_rust(RustCommand):
description = "clean Rust extensions (compile/link to build directory)"
def initialize_options(self) -> None:
"""Initialize all command options to default values."""
def run_for_extension(self, ext: RustExtension) -> None:
"""
Clean build artifacts for a single Rust extension.
Parameters:
- ext: RustExtension to clean
"""Abstract base class providing common functionality for Rust extension commands.
class RustCommand(Command, ABC):
"""Abstract base class for Rust extension commands."""
def initialize_options(self) -> None:
"""Initialize all command options to default values."""
def finalize_options(self) -> None:
"""Finalize and validate command options."""
def run(self) -> None:
"""Run the command for all Rust extensions."""
@abstractmethod
def run_for_extension(self, extension: RustExtension) -> None:
"""
Run command for a single extension (must be implemented by subclasses).
Parameters:
- extension: RustExtension to process
"""# Build all Rust extensions
python setup.py build_rust
# Build with debug information
python setup.py build_rust --debug
# Build in release mode
python setup.py build_rust --release
# Build in-place (for development)
python setup.py build_rust --inplace
# Quiet build (suppress cargo output)
python setup.py build_rust --qbuild
# Custom cargo arguments
python setup.py build_rust --cargo-args="--features=extra"
# Clean build artifacts
python setup.py clean_rust# Build everything including Rust extensions
python setup.py build
# Install including Rust extensions
python setup.py install
# Create wheel with Rust extensions
python setup.py bdist_wheel
# Development installation with in-place Rust builds
pip install -e .from setuptools import setup, Distribution
from setuptools_rust import build_rust, RustExtension
# Create a distribution with Rust extensions
dist = Distribution({
'name': 'my-package',
'rust_extensions': [
RustExtension('my_package.rust_module', 'Cargo.toml')
]
})
# Build the Rust extensions
build_cmd = build_rust(dist)
build_cmd.initialize_options()
build_cmd.finalize_options()
build_cmd.run()class CustomBuildRust(build_rust):
"""Custom build command with additional options."""
user_options = build_rust.user_options + [
("custom-flag", None, "enable custom build flag"),
]
def initialize_options(self):
super().initialize_options()
self.custom_flag = None
def run_for_extension(self, ext):
if self.custom_flag:
# Add custom build logic
ext.args = list(ext.args) + ["--features", "custom"]
super().run_for_extension(ext)The build commands integrate automatically with setuptools through entry points defined in pyproject.toml:
[project.entry-points."distutils.commands"]
build_rust = "setuptools_rust:build_rust"
clean_rust = "setuptools_rust:clean_rust"This allows the commands to be discovered and used by setuptools automatically when setuptools-rust is installed.
The commands respect standard environment variables and setuptools configuration:
from typing import List, Optional
from abc import ABC, abstractmethod
from distutils.cmd import Command
class _BuiltModule:
"""Internal type representing information about a built module."""Install with Tessl CLI
npx tessl i tessl/pypi-setuptools-rust