scikit-build-core - CMake Build Backend

0.12.2 · active · verified Thu Apr 09

scikit-build-core is a modern, PEP 517/660 compliant build backend for Python projects that use CMake to build native extensions. It streamlines the integration of C, C++, or Fortran code with Python packaging, handling everything from project configuration to wheel and sdist generation. The current version is 0.12.2, with a fairly active release cadence, typically releasing minor bugfix or feature updates every few weeks.

Warnings

Install

Quickstart

To use scikit-build-core, you primarily configure your project via `pyproject.toml`. This minimal example demonstrates how to set up `pyproject.toml` to declare `scikit-build-core` as the build backend, alongside a basic `CMakeLists.txt` and a dummy C++ source file. The Python `__init__.py` shows where the native library would typically be loaded. After running `python -m build`, `scikit-build-core` invokes CMake to build your native extension and then packages it into a wheel. You'll need CMake and a C++ compiler installed on your system to run this.

mkdir my_cmake_project
cd my_cmake_project

# pyproject.toml
cat <<EOF > pyproject.toml
[build-system]
requires = ["scikit-build-core>=0.12.0", "cmake>=3.15"]
build-backend = "scikit_build_core.build"

[project]
name = "my_package"
version = "0.1.0"
authors = [
  { name="Your Name", email="you@example.com" },
]
description = "A minimal example with scikit-build-core"
readme = "README.md"
requires-python = ">=3.8"
classifiers = [
    "Programming Language :: Python :: 3",
    "License :: OSI Approved :: MIT License",
    "Operating System :: OS Independent",
]

[tool.scikit-build]
cmake.minimum-version = "3.15"
EOF

# CMakeLists.txt
cat <<EOF > CMakeLists.txt
cmake_minimum_required(VERSION 3.15...3.27)
project(my_package LANGUAGES CXX)
add_library(mylib SHARED mylib.cpp)

install(TARGETS mylib DESTINATION .)
EOF

# mylib.cpp
mkdir -p src
cat <<EOF > src/mylib.cpp
#include <iostream>

extern "C" void greet() {
    std::cout << "Hello from C++!" << std::endl;
}
EOF

# my_package/__init__.py
mkdir -p my_package
cat <<EOF > my_package/__init__.py
import os
import sys
from pathlib import Path

# Find the built native library (e.g., _mylib.so, _mylib.pyd)
# This is a common pattern, but scikit-build-core can also inject helpers.
# For a proper package, you'd typically use `from . import _mylib`
# assuming the native library is packaged correctly.

def _load_native_library():
    # This simple example assumes the library is in the package root after install
    # In a real scenario, use proper packaging tools or scikit-build-core's
    # built-in module finder to locate and load.
    # For demonstration, we'll simulate direct loading.
    try:
        # On Linux/macOS, it's typically 'libmylib.so' or 'libmylib.dylib'
        # On Windows, it's 'mylib.dll' or '_mylib.pyd'
        if sys.platform == 'win32':
            _mylib = Path(__file__).parent / 'mylib.dll' # Or '_mylib.pyd'
        elif sys.platform == 'darwin':
            _mylib = Path(__file__).parent / 'libmylib.dylib'
        else:
            _mylib = Path(__file__).parent / 'libmylib.so'

        # This simple example doesn't actually load the C++ library
        # for direct python binding calls, as that requires pybind11/nanobind.
        # The greet() function below will just print a Python message.
        print(f"[my_package] Simulating loading native library: {_mylib.name}")
    except Exception as e:
        print(f"[my_package] Could not load native library: {e}")

_load_native_library()

def greet():
    print("Hello from Python via my_package!")

EOF

pip install build
python -m build
pip install dist/*.whl --force-reinstall

python -c "from my_package import greet; greet()"

view raw JSON →