Skip to main content

Scaffold and build Python C extensions with CMake and just-buildit.

Project description

just-makeit

CI Docs

Python C extensions the easy way.

just-makeit new generates a complete, working C99 extension project in one command: core C library, thin Python binding, CMake build system, and full test coverage — all passing before you write a single line of code.


Installation

pip install just-makeit

Quickstart

just-makeit new my_project --component engine --state gain:double:1.0
cd my_project && make && make test

What you get:

my_project/
├── native/
│   ├── benchmarks/
│   │   └── bench_engine_core.c     # C-level benchmark
│   ├── inc/
│   │   ├── clib_common.h           # common C99 types
│   │   ├── pyex_common.h           # Python extension includes
│   │   ├── my_project.h            # umbrella header (includes all components)
│   │   ├── jm_perf.h               # JM_FORCEINLINE / JM_HOT macros  (added by 'just-makeit perf')
│   │   ├── jm_simd.h               # width-portable SIMD helpers      (added by 'just-makeit perf')
│   │   └── engine/
│   │       └── engine_core.h       # component API
│   ├── src/
│   │   └── engine/
│   │       ├── CMakeLists.txt
│   │       ├── engine_core.c       # core logic — your algorithm goes here
│   │       └── engine_ext.c        # thin Python binding
│   └── tests/
│       └── test_engine_core.c      # CTest
├── cmake/
│   └── my-project.pc.in            # pkg-config template
├── src/my_project/
│   ├── __init__.py
│   ├── engine.pyi                  # type stub
│   ├── benchmarks/
│   │   ├── __init__.py
│   │   └── bench_engine.py         # Python benchmark
│   └── tests/
│       └── test_engine.py          # pytest / unittest
├── CMakeLists.txt
├── Makefile
├── pyproject.toml
└── just-makeit.toml

Commands

just-makeit provides a CLI with several commands run with

just-makeit COMMAND
COMMAND Description
new <project> Create a new project
new <project> --component name [--state ...] [--arg-type T] [--return-type T] Project with component and optional state
init <component> [--state ...] [--arg-type T] [--return-type T] Add a component to existing project
add --state name:type[:default] [...] Add state variables to a component
perf Upgrade an existing project with performance annotations
config [key value] Show or edit project configuration
build [dir] Configure + build C, and package dist
test Build and run CTest + pytest
dry-run Preview what would be compiled

See State Variable Types for supported types, defaults, and C/Python mappings.


C conventions

Generated code follows a consistent lifecycle pattern:

// Constructor — parameters match your --state declarations
engine_state_t *engine_create(double gain);

// Destructor
void engine_destroy(engine_state_t *state);

// Reset — restores every variable to its declared default
void engine_reset(engine_state_t *state);

// Single sample (inlined, pass-through stub — implement your algorithm here)
static inline float complex
engine_step(const engine_state_t *state, float complex x);

// Block processor
void engine_steps(
    engine_state_t *state,
    const float complex *input,
    float complex       *output,
    size_t               n);

// Getter / setter for each --state variable
double engine_get_gain(const engine_state_t *state);
void   engine_set_gain(engine_state_t *state, double gain);

Python API

from my_project import Engine
import numpy as np

obj = Engine(gain=1.0)   # explicit
obj = Engine()           # uses declared defaults

# single sample
y: complex = obj.step(1.0 + 0.5j)

# block processing
x = np.ones(1024, dtype=np.complex64)
y = obj.steps(x)   # returns complex64 ndarray

# getters / setters
obj.get_gain()
obj.set_gain(2.0)

# reset restores declared defaults
obj.reset()

# context manager
with Engine() as e:
    y = e.steps(x)

Multiple state variables

just-makeit new my_project \
    --component engine \
    --state center_freq:double:1000.0 \
    --state bandwidth:double:200.0 \
    --state order:int:4

Each --state name:type:default becomes a struct field, a constructor parameter (optional in Python, required in C), getter/setter pair, and reset target — in both C and Python.


Integrations

  • CMakePython3_add_library with WITH_SOABI; .so lands in src/ for zero-install dev workflow
  • GNU Make — convenience wrapper with build, test, and just-build targets
  • NumPy buffer protocolsteps() accepts and returns typed ndarrays matching your declared state types
  • pytest — tests generated covering create, step, steps, getters/setters, reset, context manager, and destroy
  • CTest — C-level test for the core lifecycle
  • just-buildit — PEP 517 backend; pip install . and pip install -e . work out of the box

Packaging

The generated project uses just-buildit as its PEP 517 build backend.

# Build and install
pip install .

# Development install (no rebuild needed after editing Python files)
pip install -e .

# Build a wheel manually
just-makeit build

Examples

The examples/ directory contains step-by-step walkthroughs:

  • running_stats/ — Welford's online mean & variance (introductory walkthrough)
  • fir_filter/ — 16-tap FIR filter processing complex I/Q signals, with perf annotations
  • sliding_correlator/ — sliding window cross-correlation against a fixed reference sequence
  • sliding_power/ — sliding window instantaneous signal power estimator
  • dsp_toolkit/ — two-component library (Gain + Ema); demonstrates multi-component workflow and __init__.py auto-splice

Design principles

Separation of concerns. Core C logic goes in *_core.c / *_core.h. The Python extension in *_ext.c is a thin adapter — argument parsing, array wrapping, and nothing more. This keeps the C library independently testable and usable from Rust, C++, or any other language.

Full test coverage by default. Every generated project has C tests (CTest) and Python tests (pytest) from day one.

just-buildit for packaging. The generated pyproject.toml uses just-buildit as the PEP 517 build backend, so pip install . just works.


Requirements

  • Python 3.11+
  • CMake ≥ 3.16
  • A C99 compiler (GCC, Clang, MSVC/MinGW)
  • NumPy (runtime, for generated projects)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

just_makeit-0.6.8-py3-none-any.whl (42.3 kB view details)

Uploaded Python 3

File details

Details for the file just_makeit-0.6.8-py3-none-any.whl.

File metadata

  • Download URL: just_makeit-0.6.8-py3-none-any.whl
  • Upload date:
  • Size: 42.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for just_makeit-0.6.8-py3-none-any.whl
Algorithm Hash digest
SHA256 9df1cfb088178c5d6f9eadf96251de4017fa677bdd19891c37cfd0d82d593edd
MD5 b6ca2959725eb6f1a83c24ce951c8ab7
BLAKE2b-256 800a2ce010b6f393438df076e77d45281325186df428c5b29284b982284ff208

See more details on using hashes here.

Provenance

The following attestation bundles were made for just_makeit-0.6.8-py3-none-any.whl:

Publisher: release.yml on just-buildit/just-makeit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page