# Building Wheels for pybind11-rdp Distribution: CMake and pybind11 Integration

> Learn how to build wheels for pybind11-rdp distribution using scikit-build-core CMake pybind11 integration to compile high-performance C++ Ramer-Douglas-Peucker into portable Python extension modules.

- Repository: [cubao/pybind11-rdp](https://github.com/cubao/pybind11-rdp)
- Tags: tutorial
- Published: 2026-02-28

---

**Building wheels for pybind11-rdp distribution requires scikit-build-core to orchestrate CMake and pybind11, compiling the high-performance C++ Ramer-Douglas-Peucker implementation into a portable Python extension module with proper ABI tagging.**

The cubao/pybind11-rdp repository delivers a fast line-simplification algorithm through a hybrid C++/Python architecture. Building wheels for pybind11-rdp distribution involves configuring CMake to compile the geometric engine in [`src/main.cpp`](https://github.com/cubao/pybind11-rdp/blob/main/src/main.cpp) into a Python extension named `_core`, which is then packaged alongside the Python façade in [`src/pybind11_rdp/__init__.py`](https://github.com/cubao/pybind11-rdp/blob/main/src/pybind11_rdp/__init__.py) for cross-platform distribution.

## Build System Architecture

The wheel construction relies on three integrated layers that separate geometric computation from Python packaging:

- **C++ Core Layer**: Implements the Ramer-Douglas-Peucker algorithm in [`src/main.cpp`](https://github.com/cubao/pybind11-rdp/blob/main/src/main.cpp), including the `LineSegment` class and both recursive (`douglas_simplify`) and iterative (`douglas_simplify_iter`) simplification engines.
- **pybind11 Binding Layer**: Exposes C++ functions to Python via the `PYBIND11_MODULE(_core, m)` macro in the same file, creating the compiled `_core` module that handles all heavy lifting.
- **scikit-build-core Layer**: Manages the wheel build process through [`CMakeLists.txt`](https://github.com/cubao/pybind11-rdp/blob/main/CMakeLists.txt), handling compiler flags, Python ABI detection, and platform-specific wheel metadata.

## CMake Configuration for Wheel Building

The [`CMakeLists.txt`](https://github.com/cubao/pybind11-rdp/blob/main/CMakeLists.txt) file (lines 1-56) defines the build rules that enable portable wheel generation:

```cmake

# CMake 3.15+ required for Python development artifacts

cmake_minimum_required(VERSION 3.15...3.27)
project(pybind11_rdp LANGUAGES CXX)

# Force Release builds for wheel distribution

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
  set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
endif()

find_package(Python REQUIRED COMPONENTS Interpreter Development)
find_package(pybind11 REQUIRED)

# Build the extension module with proper ABI tagging

python_add_library(_core MODULE src/main.cpp WITH_SOABI)

# Install into the Python package directory for wheel inclusion

install(TARGETS _core DESTINATION pybind11_rdp)

```

Key configuration details include the `WITH_SOABI` flag, which ensures the compiled shared library includes the Python ABI identifier in its filename. This allows wheels to work across different Python versions without naming collisions. The `Release` build type default ensures optimized binaries suitable for distribution.

## C++ Core Implementation

The geometric engine resides in [`src/main.cpp`](https://github.com/cubao/pybind11-rdp/blob/main/src/main.cpp), which compiles into the `_core` extension module:

**LineSegment Class** (lines 18-44): Stores 3-D endpoints `A` and `B`, pre-computing vector `AB`, its squared length, and inverse for efficient distance calculations. The `distance` and `distance2` methods compute point-to-segment distances using robust algebra.

**Simplification Algorithms**:

- **`douglas_simplify`**: Recursive implementation that traverses `RowVectors` and builds a boolean mask (`Eigen::VectorXi`). Uses a pivot-selection heuristic preferring the middle point when distances tie (lines 66-78).
- **`douglas_simplify_iter`**: Stack-based iterative version avoiding recursion limits for large datasets.

**Python Exposure**: The `PYBIND11_MODULE(_core, m)` block exports `rdp`, `rdp_mask`, and `LineSegment` directly to Python, enabling the public API.

## Python Package Structure

The [`src/pybind11_rdp/__init__.py`](https://github.com/cubao/pybind11-rdp/blob/main/src/pybind11_rdp/__init__.py) file provides the public API that end-users interact with after wheel installation:

```python
from ._core import rdp as _rdp, rdp_mask as _rdp_mask, LineSegment
import numpy as np

def __notify_dist_fn(dist):
    if dist is not None:
        print("Warning: custom distance functions not supported")

def rdp(points, epsilon=0.0, algo="iter", return_mask=False):
    pts = np.asarray(points, dtype=np.float64)
    if algo == "iter":
        if return_mask:
            return _rdp_mask(pts, epsilon, False)
        return _rdp(pts, epsilon, False)
    # Recursive fallback

    if return_mask:
        return _rdp_mask(pts, epsilon, True)
    return _rdp(pts, epsilon, True)

```

This façade converts inputs to `np.float64` arrays, selects between recursive and iterative algorithms via the `algo` parameter, and handles the `return_mask` option to return boolean indices instead of simplified coordinates.

## Building Wheels Locally

To build wheels for pybind11-rdp distribution on your development machine:

```bash

# Install build dependencies

pip install build scikit-build-core pybind11

# Generate wheel in the dist/ directory

python -m build --wheel

```

The `python -m build` command invokes scikit-build-core, which:

1. Configures CMake with the detected Python interpreter and development headers
2. Compiles [`src/main.cpp`](https://github.com/cubao/pybind11-rdp/blob/main/src/main.cpp) into `_core` with `Release` optimizations
3. Packages the extension alongside [`src/pybind11_rdp/__init__.py`](https://github.com/cubao/pybind11-rdp/blob/main/src/pybind11_rdp/__init__.py) into a platform-specific wheel

For editable installs during development:

```bash
pip install -e . --no-build-isolation

```

## Verifying Wheel Functionality

After building, verify the wheel contains the compiled extension and works correctly using the test suite:

```python
import numpy as np
from pybind11_rdp import rdp, LineSegment

# Test 2-D polyline simplification

points = np.array([[0, 0], [1, 0.2], [2, 0.1], [3, 0], [4, 0]])
simplified = rdp(points, epsilon=0.15)
print(simplified)

# → [[0. 0.]

#    [4. 0.]]

# Test LineSegment distance calculation

seg = LineSegment([0, 0, 0], [10, 0, 0])
dist = seg.distance([5, 3, 0])  # → 3.0

# Verify algorithm consistency between recursive and iterative

line = np.cumsum(np.random.rand(200, 2), axis=0)
for eps in np.linspace(0, 1, 5):
    assert np.allclose(rdp(line, eps, algo="iter"),
                       rdp(line, eps, algo="rec"))

```

The test files [`tests/test_basic.py`](https://github.com/cubao/pybind11-rdp/blob/main/tests/test_basic.py) and [`tests/test_rdp.py`](https://github.com/cubao/pybind11-rdp/blob/main/tests/test_rdp.py) cover edge cases, 3-D data handling, and equivalence between recursive and iterative implementations to ensure the built wheel functions correctly across platforms.

## Summary

- **scikit-build-core** orchestrates the build process, bridging CMake and Python packaging standards for building wheels for pybind11-rdp distribution.
- **[`CMakeLists.txt`](https://github.com/cubao/pybind11-rdp/blob/main/CMakeLists.txt)** configures `python_add_library(_core MODULE src/main.cpp WITH_SOABI)` to generate ABI-tagged extension modules compatible with wheel distribution.
- **[`src/main.cpp`](https://github.com/cubao/pybind11-rdp/blob/main/src/main.cpp)** contains the high-performance C++ implementation of the Ramer-Douglas-Peucker algorithm, exposed via pybind11 as the `_core` module.
- **[`src/pybind11_rdp/__init__.py`](https://github.com/cubao/pybind11-rdp/blob/main/src/pybind11_rdp/__init__.py)** wraps the compiled extension with NumPy array handling and algorithm selection utilities.
- The resulting wheel packages the `_core` shared library alongside Python source files, enabling `pip install` across platforms without requiring end-users to compile code.

## Frequently Asked Questions

### What build backend does pybind11-rdp use for wheel building?

The package uses **scikit-build-core** as its build backend, which leverages CMake to compile the C++ extensions while adhering to modern Python packaging standards (PEP 517/518). This backend automatically handles platform-specific wheel tags and ABI compatibility through the `WITH_SOABI` flag in [`CMakeLists.txt`](https://github.com/cubao/pybind11-rdp/blob/main/CMakeLists.txt).

### How does the CMakeLists.txt ensure Python ABI compatibility?

The [`CMakeLists.txt`](https://github.com/cubao/pybind11-rdp/blob/main/CMakeLists.txt) uses `python_add_library(_core MODULE src/main.cpp WITH_SOABI)`, which instructs CMake to include the Python ABI identifier in the shared library filename. This ensures that wheels built for CPython 3.10, for example, cannot be accidentally installed into a CPython 3.11 environment, preventing runtime crashes due to binary incompatibilities.

### Why is the Ramer-Douglas-Peucker algorithm implemented in C++ rather than pure Python?

The **C++ implementation** in [`src/main.cpp`](https://github.com/cubao/pybind11-rdp/blob/main/src/main.cpp) provides performance-critical geometric calculations including point-to-segment distance computations and recursive/iterative stack management. By implementing `douglas_simplify` and `douglas_simplify_iter` in C++ with Eigen for matrix operations, the package achieves significant speedups over pure Python implementations, which is essential for processing large geospatial datasets with thousands of points.

### Can I build wheels for pybind11-rdp without installing CMake or pybind11 manually?

Yes, when using `pip install .` or `python -m build`, scikit-build-core automatically pulls CMake and pybind11 as build dependencies specified in [`pyproject.toml`](https://github.com/cubao/pybind11-rdp/blob/main/pyproject.toml). However, for development builds with `pip install -e .`, you should pre-install `scikit-build-core` and `pybind11` to ensure the build environment has access to the required CMake modules and pybind11 headers.