...
PyO3 setup Guide: setup.py
ghwangbo
2025. 5. 30. 14:53
반응형
What is setuptools-rust?
- setuptools-rust is a plugin for Python’s setuptools that enables you to build Rust extensions as part of the standard Python build process.
- It integrates Rust’s Cargo build system into Python’s setup.py workflow.
- Useful if you want to maintain a traditional Python packaging style with a setup.py script.
Step-by-Step Guide
1. Install setuptools-rust
First, install the required Python packages:
pip install setuptools setuptools-rust wheel
2. Create your Rust library project
If you don’t have one yet:
cargo new --lib my_rust_ext cd my_rust_ext
3. Configure Cargo.toml
Make sure your Cargo.toml looks like this:
[package]
name = "my_rust_ext"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
pyo3 = { version = "0.18", features = ["extension-module"] }
- The cdylib crate type is needed to build a dynamic library usable as a Python extension.
- The extension-module feature is important for Python integration.
4. Write your Rust code exposing Python functions (in src/lib.rs)
Example:
use pyo3::prelude::*;
#[pyfunction]
fn double(x: usize) -> usize {
x * 2
}
#[pymodule]
fn my_rust_ext(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(double, m)?)?;
Ok(())
}
5. Write setup.py
Create a setup.py file in the root directory (alongside Cargo.toml):
from setuptools import setup
from setuptools_rust import RustExtension
setup(
name="my_rust_ext",
version="0.1.0",
rust_extensions=[RustExtension("my_rust_ext.my_rust_ext", "Cargo.toml", binding="pyo3")],
packages=["my_rust_ext"],
# Rust extensions are not zip safe, set this to False
zip_safe=False,
)
- "my_rust_ext.my_rust_ext" refers to the Python module name you want to expose.
- binding="pyo3" tells setuptools-rust to use PyO3 binding (important!).
6. Organize your Python package files
Your directory should look like:
my_rust_ext/
├── Cargo.toml
├── src/
│ └── lib.rs
├── my_rust_ext/
│ └── __init__.py # Can be empty or contain Python code
└── setup.py
- my_rust_ext/__init__.py makes the directory a Python package.
- The Rust extension module will be built inside the package.
7. Build and install
- To build and install your Python package with the Rust extension, use the modern and recommended method
pip install .
- This command:
- Uses the modern Python build system defined by PEP 517/518.
- Ensures that your package is built in an isolated environment.
- Automatically installs any dependencies specified in your setup.py or pyproject.toml.
- Compiles the Rust code via Cargo using setuptools-rust under the hood.
- Works cleanly with virtual environments, pip, and other modern tooling.
⚠️ Legacy method: python setup.py install (Not Recommended)
python setup.py install
- This approach:
- Bypasses modern build isolation and standards.
- Does not automatically install dependencies.
- Can pollute your project directory with build artifacts (like .egg-info).
- May behave inconsistently across environments and is generally discouraged in favor of pip install ..
-
bash복사편집python setup.py install
-
bash복사편집pip install .
8. Test in Python
Run Python and test your extension:
import my_rust_ext.my_rust_ext print(my_rust_ext.my_rust_ext.double(21)) # Should print 42
9. Build distributable wheels
To build a wheel package:
python setup.py bdist_wheel
- The wheel will be inside dist/ and can be uploaded to PyPI.
Notes
- You can also integrate setuptools-rust with pyproject.toml and PEP 517, but that is optional.
- Make sure Rust is installed and in your PATH, since Cargo is called during build.
- If you want to include pure Python code alongside the Rust extension, place it inside the Python package folder (e.g., my_rust_ext/).
반응형