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. The LineSegment class pre-computes segment lengths and provides distance() methods for efficient point-to-line calculations. The algorithm functions accept 2-D or 3-D NumPy arrays via Eigen::Ref for zero-copy data access.
  • CMakeLists.txt: Orchestrates compilation by finding Python development libraries, including pybind11 headers, and setting C++14 standards. It creates the pybind11_rdp/_core shared library target.
  • src/pybind11_rdp/__init__.py: Provides the Pythonic interface by importing functions from the compiled _core module 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 --recursive to fetch pybind11 and Eigen submodules required by src/main.cpp.
  • Use out-of-source builds (mkdir build) to keep the source tree clean.
  • The CMakeLists.txt defines VERSION_INFO and links against pybind11::headers to 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →