Metadata-Version: 2.4
Name: mojo-bindgen
Version: 0.3.1
Summary: Generate Mojo FFI bindings from C headers using libclang
Project-URL: Homepage, https://github.com/MoSafi2/mojo_bindgen
Project-URL: Repository, https://github.com/MoSafi2/mojo_bindgen
Project-URL: Issues, https://github.com/MoSafi2/mojo_bindgen/issues
Project-URL: Documentation, https://github.com/MoSafi2/mojo_bindgen/blob/main/README.md
Project-URL: Changelog, https://github.com/MoSafi2/mojo_bindgen/blob/main/CHANGELOG.md
Author-email: Mohamed Mabrouk <mohamed.mabrouk@rwth-aachen.de>
License-Expression: MIT
License-File: LICENSE
Keywords: bindings,c,codegen,ffi,libclang,mojo
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: C
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Code Generators
Classifier: Typing :: Typed
Requires-Python: >=3.14
Requires-Dist: libclang<19,>=18.1.1
Requires-Dist: rich
Requires-Dist: typer
Provides-Extra: dev
Requires-Dist: build>=1.4; extra == 'dev'
Requires-Dist: pyright>=1.1.400; extra == 'dev'
Requires-Dist: pytest>=9; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Description-Content-Type: text/markdown

[![CI](https://github.com/MoSafi2/mojo_bindgen/actions/workflows/ci.yml/badge.svg)](https://github.com/MoSafi2/mojo_bindgen/actions/workflows/ci.yml)

# mojo-bindgen

> [!WARNING]
> Alpha stage: this project is under heavy development and may change quickly.

**C headers -> Mojo FFI.** `mojo-bindgen` parses real C with
[libclang](https://pypi.org/project/libclang/), and emits Mojo bindings for `external_call` or
`owned_dl_handle` workflows. this mirrors the spirit of `rust-bindgen` which follows the same approch for `Rust`

The goal is simple: make binding generation easy and faithful as possible to the
actual C surface, and fail conservatively when a declaration cannot be modeled
correctly.

## Requirements

- Python 3.14+
- a system `libclang` compatible with the `libclang` Python wheel
- a Mojo (nightly) toolchain if you want to build or run the generated bindings

## Installation

### System dependencies

Install Clang and the shared `libclang` library first:

```bash
# Ubuntu / Debian
sudo apt update && sudo apt install -y clang libclang1

# Fedora
sudo dnf install -y clang llvm-libs

# macOS (Homebrew)
brew install llvm
```

If the shared library is not on the default loader path, set `LIBCLANG_PATH`
to the directory containing `libclang.so` or `libclang.dylib`.

### Install from PyPI

```bash
pip install mojo-bindgen
```

PyPI package: [mojo-bindgen](https://pypi.org/project/mojo-bindgen/)

### Install from source

```bash
git clone https://github.com/MoSafi2/mojo_bindgen
cd mojo_bindgen
pip install -e .
```

For development setup, checks, and Pixi workflows, see
[CONTRIBUTING.md](CONTRIBUTING.md).

## Quick start

Generate bindings from a primary header:

```bash
mojo-bindgen path/to/header.h -o bindings.mojo --linking external_call|owned_dl_handle
```

Pass include paths and other Clang flags with repeated `--compile-arg`:

```bash
mojo-bindgen include/mylib.h \
  --compile-arg=-I./include \
  --compile-arg=-DMYLIB_FEATURE=1 \
  -o mylib_bindings.mojo
```

Emit declarations from additional include headers with repeated
`--include-header`. Dependency headers are still parsed for type information
and macro expansion, but are not emitted unless listed:

```bash
mojo-bindgen include/mylib.h \
  --include-header include/mylib_extra.h \
  --compile-arg=-I./include \
  -o mylib_bindings.mojo
```

By default the parser uses `-std=gnu11` when no C standard is provided. Pin a
standard explicitly if your header requires one:

```bash
mojo-bindgen include/mylib.h --compile-arg=-std=c99 -o mylib_bindings.mojo
```

## Linking modes

`mojo-bindgen` supports two output styles:

- `external_call`
  Direct FFI wrappers. Use this when the target library is linked at Mojo build
  time.
- `owned_dl_handle`
  Dynamic runtime symbol lookup via `OwnedDLHandle` for loading a
  shared library (`.so`, `.dylib`).

Examples:

```bash
# default
mojo-bindgen include/mylib.h --linking external_call -o mylib_bindings.mojo

# runtime-loaded shared library
mojo-bindgen include/mylib.h \
  --linking owned_dl_handle \
  --library-path-hint /usr/lib/libmylib.so \
  -o mylib_bindings_dl.mojo
```

## What works today?

`mojo-bindgen` is still alpha and evolves quickly, but it already supports a
useful slice of real C headers and is practical today as a starting point for
generating bindings.

Current support includes:

- **Parsing and lowering:** real C parsing through `libclang`, repeatable `--compile-arg`
  support, and a structured IR pipeline rather than text-only generation.
- **Primitive types:** scalar types, typedef chains, pointers with const-aware
  mutability, fixed arrays, incomplete-array decay cases, complex values,
  vector extension types, and representable atomics.
- **Mojo-native numeric lowering:** vector types lower to `SIMD[...]`, complex
  values lower to `ComplexSIMD[...]`, and representable atomics lower to
  `Atomic[...]`.
- **Records:** structs, anonymous members, mixed layouts that combine plain
  fields and bitfields, synthesized padding, and custom alignment emission
  where Mojo can represent the layout faithfully.
- **Bitfields:** bitfields are emitted through explicit storage fields plus
  synthesized getter and setter methods.
- **Unions:** eligible unions lower to `UnsafeUnion[...]`; unions that cannot
  be represented safely fall back to opaque `InlineArray[...]` storage with
  diagnostics to preserve layout.
- **Opaque and difficult layouts:** incomplete records, packed layouts, and
  alignment-sensitive record shapes are preserved conservatively as opaque byte
  storage when a faithful typed layout is not possible.
- **Callbacks and function pointers:** callback typedefs, function-pointer
  fields, and function-pointer parameters and returns are preserved in Mojo via
  emitted `comptime` callback declarations and synthesized aliases when needed.
- **Functions:** thin wrappers are generated for non-variadic functions under
  both `external_call` and `owned_dl_handle` link modes.
- **Globals and constants:** because Mojo does not currently expose native C
  globals directly, supported globals lower through generated `GlobalVar` /
  `GlobalConst` helper structs with synthesized `load()` / `store()` methods;
  constants and supported object-like macros lower to `comptime` declarations.
- **Macros:** integer, float, string, and char literal macros, foldable macro
  chains, supported casts, and `sizeof(type)` expressions are emitted as Mojo
  code.
- **JSON IR output:** the CLI can emit serialized parser IR for debugging,
  testing, or downstream tooling.

## Current limitations

Known gaps you may still hit in generated code. For ABI-sensitive surfaces,
verify emitted layouts and symbols against your target toolchain.

- **Macros:** function-like macros, predefined macros, and more complex
  preprocessor behavior are preserved but usually emitted as comments for
  end-user review.
- **Variadics:** variadic C functions are not wrapped as callable thin-FFI
  bindings yet and are emitted as comment stubs.
- **Non-prototype / K&R-style functions:** older C declaration styles are only
  partially modeled and should be treated with caution.
- **Records with hostile layouts:** some packed, ABI-sensitive, or otherwise
  difficult record layouts cannot be emitted as fully typed Mojo structs and
  fall back to opaque storage; layout-sensitive declarations may still require
  manual verification.
- **Anonymous members:** anonymous struct and union members are preserved
  structurally, but they are not automatically promoted into a flattened parent
  record surface.
- **Atomics:** atomic support is conservative. Representable atomic fields and
  pointer-based usage work, but atomic globals are still emitted as stubs and
  some surfaces require manual handling.
- **Linkage and compiler edge cases:** `inline`, compiler-specific linkage
  hints, and other extension-heavy cases can still require manual review and
  may lead to symbol mismatches at runtime.
- **Include-header model:** declarations are emitted from the primary header
  you pass to the tool plus any headers named with `--include-header`. Other
  headers included by those files are parsed as dependencies but not emitted.

## Real-world examples

The repository includes worked examples and smoke programs for:

- SQLite: [examples/sqlite](examples/sqlite)
- Cairo: [examples/cairo](examples/cairo)
- libpng: [examples/libpng](examples/libpng)
- zlib: [examples/zlib](examples/zlib)

These examples do more than generate bindings: their `generate.sh` scripts also
build and run small functional tests to check the usability of the generated bindings.

The test suite also has end-to-end runtime coverage for:

- by-value records and enums
- callbacks and function-pointer returns
- globals and constants
- vectors and complex values
- atomic pointer-based APIs
- opaque forward declarations
- pointer-to-array and array-decay cases
- both `external_call` and `owned_dl_handle` link modes

See [tests/e2e/README.md](tests/e2e/README.md) for the current runtime case
matrix.

## Troubleshooting

### The generated module is empty or missing declarations

`mojo-bindgen` emits declarations from the primary header you pass in and any
headers listed with `--include-header`. If a thin wrapper only includes another
header whose declarations should be emitted, pass that included header with
`--include-header` or use it as the primary header directly.

### Parsing fails on project headers

Most parser failures are missing include paths, target flags, or defines. Add
the same flags your C build uses via repeated `--compile-arg`.

### Build succeeds but symbols are missing at runtime

Double-check:

- `--library` and `--link-name`
- your Mojo link flags for `external_call`
- your `--library-path-hint` for `owned_dl_handle`
- whether the original C declaration involved tricky `inline` or exotic layout that needs manual review.

## License

Licensed under the **MIT License**. See [LICENSE](LICENSE).

---

Contributing: [CONTRIBUTING.md](CONTRIBUTING.md).
