Building pybind11-rdp from Source with CMake: Step-by-Step Guide
Building pybind11-rdp from source with CMake requires a C++14 compiler, Python development headers, and CMake 3.15+ to compile the native _core extension module that exposes the Ramer-Douglas-Peucker algorithm to Python.
The cubao/pybind11-rdp repository provides a high-performance C++ implementation of the RDP line-simplification algorithm, wrapped for Python using pybind11. While pre-built wheels are available, compiling from source with CMake gives you control over compiler optimizations and debug symbols. This guide walks through the complete build process, from cloning submodules to importing the compiled rdp and rdp_mask functions.
Prerequisites for Building from Source
Before compiling pybind11-rdp, verify your environment meets these requirements:
- CMake 3.15 or higher (required by scikit-build-core)
- C++14 compatible compiler (GCC, Clang, or MSVC)
- Python 3.7+ with development headers (python3-dev or python-devel packages)
- Git to clone recursive submodules
The project uses scikit-build-core as its PEP 517 build backend, which automatically locates pybind11 and Eigen headers during the CMake configuration phase defined in CMakeLists.txt.
Step-by-Step CMake Build Instructions
Follow these commands to manually compile the native extension using CMake.
1. Clone the Repository with Submodules
The project depends on pybind11 and Eigen as git submodules. Clone recursively to fetch all headers required by src/main.cpp:
git clone --recursive https://github.com/cubao/pybind11-rdp.git
cd pybind11-rdp
2. Create a Build Directory
CMake recommends out-of-source builds to isolate generated files from the source tree:
mkdir build && cd build
3. Configure the Project
Run CMake to generate build files. The configuration step locates your Python interpreter, finds pybind11 headers, and prepares the VERSION_INFO definition (line 52 of CMakeLists.txt):
cmake .. -DCMAKE_BUILD_TYPE=Release
The CMakeLists.txt defines the _core target as a Python extension module linking against pybind11::headers. It also injects the package version string into the compiled binary via the VERSION_INFO preprocessor definition.
4. Compile the Extension
Build the shared object (or .pyd on Windows) containing the RDP algorithm implementation:
cmake --build . --parallel
This compiles src/main.cpp, which contains the core logic: the LineSegment helper class (for point-to-segment distance calculations), the recursive douglas_simplify function, and the iterative douglas_simplify_iter variant that fills an Eigen::VectorXi mask.
5. Install the Package
Install the compiled module into your Python environment:
cd ..
pip install .
The pip install . command triggers scikit-build-core to move the compiled _core module (located at src/pybind11_rdp/_core.so on Linux) into your site-packages. The src/pybind11_rdp/__init__.py wrapper then re-exports the compiled symbols—rdp, rdp_mask, LineSegment, mask2indexes, and select_by_mask—to the Python namespace.
Architecture of the Compiled Module
Understanding the build output helps when debugging or extending the library:
src/main.cpp: Implements the RDP algorithm using Eigen for vector operations. TheLineSegmentclass pre-computes segment lengths and providesdistance()methods for efficient point-to-line calculations. The algorithm functions accept 2-D or 3-D NumPy arrays viaEigen::Reffor zero-copy data access.CMakeLists.txt: Orchestrates compilation by finding Python development libraries, including pybind11 headers, and setting C++14 standards. It creates thepybind11_rdp/_coreshared library target.src/pybind11_rdp/__init__.py: Provides the Pythonic interface by importing functions from the compiled_coremodule and exposing them at the package level.
Alternative: Installing via pip (PEP 517)
If you prefer not to run CMake manually, the project supports modern Python packaging standards. The pyproject.toml file declares scikit-build-core as the build system, allowing pip to handle the CMake invocation automatically:
pip install git+https://github.com/cubao/pybind11-rdp.git
This single command clones the repository, runs the CMake configuration and build steps described above, and installs the resulting wheel without requiring manual intervention.
Verifying the Installation
Test your build by running the RDP algorithm on sample coordinate data:
import numpy as np
from pybind11_rdp import rdp, rdp_mask
# 3-D polyline example
points = np.array([[0, 0, 0],
[1, 0.1, 0],
[2, 0, 0],
[10, 0.2, 0]])
# Simplify with epsilon=0.5
simplified = rdp(points, epsilon=0.5)
print(f"Original: {len(points)} points, Simplified: {len(simplified)} points")
# Get boolean mask (1 = keep, 0 = discard)
mask = rdp_mask(points, epsilon=0.5)
print(f"Retention mask: {mask}")
The rdp function returns a reduced coordinate matrix, while rdp_mask returns the boolean mask used internally by the mask2indexes and select_by_mask utilities implemented in src/main.cpp.
Summary
- pybind11-rdp compiles into a native Python extension module (
_core) using CMake and scikit-build-core. - The build requires CMake 3.15+, a C++14 compiler, and Python development headers.
- Clone with
--recursiveto fetch pybind11 and Eigen submodules required bysrc/main.cpp. - Use out-of-source builds (
mkdir build) to keep the source tree clean. - The
CMakeLists.txtdefinesVERSION_INFOand links againstpybind11::headersto create the extension. - For automated builds,
pip install .triggers PEP 517 compliant compilation via scikit-build-core.
Frequently Asked Questions
What CMake version is required to build pybind11-rdp?
CMake 3.15 or higher is required. This version ensures compatibility with scikit-build-core, which drives the build process defined in pyproject.toml. Older versions may fail to locate Python components correctly or handle the pybind11::headers target properly.
Do I need to install Eigen or pybind11 separately before building?
No. Both dependencies are included as git submodules. You must clone the repository using git clone --recursive so that CMake can find the headers in the pybind11 and eigen directories. If you forget --recursive, run git submodule update --init --recursive before running CMake.
How do I build a debug version of the extension for development?
Pass -DCMAKE_BUILD_TYPE=Debug during the configuration step instead of Release. This disables compiler optimizations and includes debug symbols, allowing you to step through the douglas_simplify implementation in src/main.cpp using GDB or LLDB to inspect the LineSegment distance calculations.
Can I build pybind11-rdp against a specific Python version?
Yes. During the CMake configuration step, specify the Python executable explicitly: cmake .. -DPython_EXECUTABLE=/usr/bin/python3.9. The CMakeLists.txt uses CMake's FindPython module to locate headers and libraries matching that interpreter, ensuring the compiled _core module links against the correct Python version.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →