TheBundle Pybind Subpackage¶
The bundle.pybind subpackage provides a modern, declarative, and extensible framework for building, configuring, and managing C++/pybind11 extension modules in Python projects. It enables seamless integration with setuptools, pyproject.toml, and system-level build tools such as CMake and pkg-config.
Key Features¶
Declarative configuration: Define all extension modules, sources, and build options in
pyproject.tomlunder[tool.pybind11].Automatic pkg-config integration: Resolve compiler and linker flags for dependencies using
pkg-config, including custom search paths.CMake support: Utilities for configuring and building CMake-based C++ projects, with platform-specific flags.
Async-first resolution: All resolution and build steps are async, enabling parallel builds and responsive CLI tools.
Plugin architecture: Easily extend or modify build and resolution logic via plugin hooks.
Rich CLI: Manage builds and inspect configuration with a modern, user-friendly CLI.
Cross-platform: Handles platform-specific quirks for Windows, Linux, and macOS.
First-class setuptools integration: Generate
Extensionobjects and custombuild_extcommands for use insetup.py.
Quickstart¶
1. Project Structure¶
your_project/
├── bindings/
│ └── python/
│ └── example_module/
│ ├── shape_bindings.cpp
│ └── geometry_bindings.cpp
├── ...
├── pyproject.toml
└── setup.py
2. pyproject.toml Example¶
[build-system]
requires = ["setuptools", "wheel", "setuptools_scm", "thebundle"]
build-backend = "setuptools.build_meta"
[project]
name = "realpkg"
# ...
[tool.setuptools.packages.find]
where = ["bindings/python"]
[tool.pybind11]
# shape submodule
[[tool.pybind11.modules]]
name = "example_module.shape"
sources = ["bindings/python/example_module/shape_bindings.cpp"]
pkgconfig = { packages = ["example_module"], extra_dirs = [] }
extra_compile_args = ["-O3"]
extra_link_args = []
# geometry submodule
[[tool.pybind11.modules]]
name = "example_module.geometry"
sources = ["bindings/python/example_module/geometry_bindings.cpp"]
pkgconfig = { packages = ["example_module"], extra_dirs = [] }
extra_compile_args = ["-O3"]
extra_link_args = []
3. setup.py Example¶
from bundle.pybind import Pybind
Pybind.setup(__file__)
How It Works¶
Declarative Specs¶
ProjectSpec: Root object, loaded from
[tool.pybind11]inpyproject.toml.ModuleSpec: Each extension module is described with its name, sources, language, compiler/linker flags, and pkg-config dependencies.
PkgConfigSpec: Describes dependencies to be resolved via
pkg-config.
Resolution Pipeline¶
Spec Loading:
Pybindloads and validates the project/module specs frompyproject.toml.Pkg-config Resolution: For each module, dependencies are resolved using
pkg-config, collecting include/library dirs and flags.Module Resolution: Combines user-specified and resolved flags, sources, and options into a
ModuleResolvedobject.Extension Generation: Each
ModuleResolvedis converted into asetuptools.Extensionfor building.Build: Extensions are built in-place using the custom
build_extcommand.
Plugin System¶
PybindPluginSpec: Apply transformations or checks to module specs before resolution.
PybindPluginResolved: Modify or inspect resolved modules before extension generation.
Register plugins via the
pluginsargument toPybindor in your own build scripts.
CLI Usage¶
The CLI is available as python -m bundle.pybind.cli or via a custom entrypoint.
Build Extensions¶
python -m bundle pybind build --path .
Builds all pybind11 extensions in-place.
Supports parallel builds with
--parallel.
Show Project Info¶
python -m bundle pybind info --path .
Prints the resolved configuration for all modules.
API Overview¶
Main Entrypoint¶
from bundle.pybind import Pybind
# In setup.py
Pybind.setup(__file__)
Programmatic usage
pyb = Pybind("pyproject.toml")
resolved = await pyb.resolve()
extensions = await pyb.get_spec_extensions()
Extension Generation¶
ExtensionSpec.from_module_resolved(module: ModuleResolved) -> ExtensionCustom
build_extcommand for per-extension temp dirs and platform safety.
CMake Utilities¶
CMakeService.configure(...): Configure a CMake project with platform-specific flags.CMakeService.build(...): Build a CMake project or target.
Pkg-config Utilities¶
PkgConfigService.resolve(spec: PkgConfigSpec): Resolve all flags for a dependency.
Advanced Features¶
Platform Awareness: Handles macOS deployment targets, Windows/Unix flags, and architecture-specific options.
Async Resolution: All resolution and build steps are async, enabling fast, parallel builds.
Reference Data: All resolved specs and build artifacts can be serialized for inspection or debugging.
Extensible: Add custom plugins to modify specs or resolved modules for advanced workflows.
Example: Adding a New Extension Module¶
Add a new module entry in pyproject.toml:
[[tool.pybind11.modules]]
name = "example_module.newfeature"
sources = ["bindings/python/example_module/newfeature_bindings.cpp"]
pkgconfig = { packages = ["example_module"], extra_dirs = [] }
extra_compile_args = ["-O3"]
extra_link_args = []
No changes to setup.py are needed—just re-run your build.
Reference¶
Specs¶
ProjectSpec: Root config, holds all modules.
ModuleSpec: Module name, sources, language, cpp_std, pkgconfig, extra_compile_args, extra_link_args.
PkgConfigSpec: packages, extra_dirs.
Services¶
PkgConfigService: Resolves compiler/linker flags via pkg-config.
CMakeService: Runs CMake configure/build commands.
Resolvers¶
PkgConfigResolver: Async resolver for pkg-config specs.
ModuleResolver: Resolves a module spec to a resolved module.
ProjectResolver: Resolves the whole project.
Plugins¶
PybindPluginSpec: Pre-resolution spec plugin interface.
PybindPluginResolved: Post-resolution plugin interface.
Best Practices¶
Keep all extension configuration in
pyproject.tomlfor reproducibility.Use pkg-config for all C++ dependencies to ensure portability.
Use plugins for custom build logic or validation.
Prefer async workflows for large projects or CI pipelines.
See Also¶
For further details, consult the inline documentation in each module and the example project in tests/pybind/example_module.