This project demonstrates how to create a Python package with C++ extensions using:
- NixOS for reproducible development environment
- uv for Python package management
- pybind11 for Python-C++ bindings
- CMake for building C++ extensions
- Python 3.13 as the target Python version
├── src/
│ ├── cpp/
│ │ ├── main.h # C++ header with template functions
│ │ ├── main.cpp # C++ implementation
│ │ └── bindings.cpp # pybind11 bindings
│ └── python/
│ └── example_package/
│ ├── __init__.py # Python package init (imports C++ functions)
│ ├── main.py # Demo script
│ ├── nyr_cpp.pyi # Type stubs for C++ functions
│ └── nyr_cpp.so # Compiled C++ extension (generated)
├── build/ # CMake build directory (generated)
├── CMakeLists.txt # CMake configuration
├── build.sh # Build script
├── pyproject.toml # Python package configuration
├── flake.nix # Nix development environment
└── README.md # This file
The C++ module nyr provides:
hello_world(message: str)- Prints a hello messagefast_pow(base: float, exp: int)- Fast exponentiation (double precision)fast_pow_float(base: float, exp: int)- Fast exponentiation (single precision)fast_pow_long(base: float, exp: int)- Fast exponentiation with long exponent
All functions use optimized algorithms and are accessible from Python with full type hints.
nix developThis will:
- Install all required dependencies (Python 3.13, CMake, pybind11, gcc)
- Set up the Python virtual environment with uv
- Configure CMake paths
Note that uv automatically install the current project package in "editable" mode. Changes to the source code are immediately reflected without reinstalling.
bash build.shThis will:
- Create a
build/directory - Configure the project with CMake
- Compile the C++ extension
- Copy the resulting
.sofile to the Python package
python -m example_package.mainExpected output:
Hello-World from example-package!
--- Testing C++ functions from Python ---
Hello, World: from Python calling C++!
fast_pow(2.0, 10) = 1024.0
fast_pow_float(3.0, 5) = 243.0
fast_pow_long(1.5, 20) = 3325.256730079651
fast_pow(5.0, 0) = 1.0
fast_pow(2.0, -3) = 0.125
--- C++ functions tested successfully! ---
- Modify C++ code: Edit files in
src/cpp/ - Rebuild: Run
./build.sh - Test: Run
python -m example_package.main
The build script automatically copies the compiled extension to the Python package directory.
flake.nix: Defines the Nix development environment with all dependenciesCMakeLists.txt: CMake configuration for building the pybind11 modulepyproject.toml: Python package metadata and dependenciessrc/cpp/bindings.cpp: pybind11 module definitionsrc/python/example_package/nyr_cpp.pyi: Type stubs for IDE support
- Reproducible: Nix ensures consistent environment across machines
- Fast: uv provides fast Python package management
- Type-safe: Full type hints for C++ functions in Python
- Modern: Uses latest Python 3.13 and C++20 standards
- Efficient: Optimized C++ algorithms with Python convenience
To add new C++ functions:
- Add declarations to
src/cpp/main.h - Implement in
src/cpp/main.cpp - Bind in
src/cpp/bindings.cppusing pybind11 - Add type stubs to
src/python/example_package/nyr_cpp.pyi - Import in
src/python/example_package/__init__.py - Rebuild with
./build.sh