Metadata-Version: 2.2
Name: llvm-nanobind
Version: 21.1.6.3
Summary: LLVM-C Python bindings with nanobind.
Project-URL: Homepage, https://github.com/LLVMParty/llvm-nanobind
Requires-Python: >=3.12
Description-Content-Type: text/markdown

# llvm-nanobind

Python bindings for the LLVM-C API using [nanobind](https://github.com/wjakob/nanobind).

This project provides a Pythonic interface to LLVM's compiler infrastructure, enabling you to build compilers, analyzers, and code transformation tools in Python.

**Current status**: Experimental but usable. The bindings target LLVM 21.1.6 and are published as `llvm-nanobind` on PyPI (import name: `llvm`). Wheels bundle LLVM and are built/tested in CI for Linux x86_64/aarch64, macOS arm64, and Windows x86_64. The API is still evolving; expect breaking changes until a stable release.

Version numbers track LLVM: `21.1.6.1` means LLVM `21.1.6` plus binding/package revision `1`.

_Note_: This project is 90%+ vibe coded. It is mostly an experiment to see what LLMs can do when you set things up properly.

## Installation

Released wheels bundle LLVM for supported platforms, so normal installation is:

```bash
pip install llvm-nanobind
python -c "import llvm; print(llvm)"
```

For source/development builds, see [Development](#development).

See [llvm-nanobind-example](https://github.com/LLVMParty/llvm-nanobind-example) for a simple example project.

## Quick Start

```python
import llvm

# Create a simple function that returns 42.
with llvm.create_context() as ctx:
    i32 = ctx.types.i32
    fn_type = ctx.types.function(i32, [])

    with ctx.create_module("example") as mod:
        fn = mod.add_function("get_answer", fn_type)
        entry = fn.append_basic_block("entry")

        with entry.create_builder() as builder:
            builder.ret(i32.constant(42))

        assert mod.verify(), mod.verification_error
        print(mod)
```

This exact snippet is available as [`examples/quick_start.py`](examples/quick_start.py).

## Examples

Runnable examples live in [`examples/`](examples/) and are covered by `tests/test_examples.py`.

```bash
uv run python examples/quick_start.py
uv run python examples/transform_replace_add.py
```

More examples worth browsing:

- [`examples/intrinsic_memcpy.py`](examples/intrinsic_memcpy.py) - call an LLVM intrinsic by name with `Builder.intrinsic(...)`
- [`examples/optimize_module.py`](examples/optimize_module.py) - optimize a module with a PassBuilder pipeline string
- [`examples/optimize_function.py`](examples/optimize_function.py) - optimize one function with a function-level PassBuilder pipeline string
- [`examples/emit_object_assembly.py`](examples/emit_object_assembly.py) - emit host object code and assembly from a module
- [`examples/jit_add.py`](examples/jit_add.py) - JIT-compile IR, call it through ctypes, and register a Python callback
- [`examples/instruction_metadata.py`](examples/instruction_metadata.py) - attach custom metadata to an instruction and print the IR
- [`examples/named_metadata.py`](examples/named_metadata.py) - create module named metadata and print the IR
- [`examples/metadata_debug_info.py`](examples/metadata_debug_info.py) - attach metadata, create debug info, and use debug-location scopes
- [`examples/transform_replace_add.py`](examples/transform_replace_add.py) - simple IR transformation using operands, RAUW, and instruction deletion
- [`examples/bc-stats.py`](examples/bc-stats.py) - print per-function instruction histograms from LLVM IR
- [`examples/bc-graphviz.py`](examples/bc-graphviz.py) - emit a GraphViz-style control-flow graph from LLVM IR
- [`examples/bc-profile.py`](examples/bc-profile.py) - instrument LLVM IR with profiling hooks

## Current capabilities

- Pythonic wrappers for contexts, modules, types, values, functions, basic blocks, builders, metadata, debug info, object files, targets, target machines, and pass builder options
- IR construction, traversal, and transformation helpers: constants, globals, PHI/control flow/memory/cast/cmp instructions, operands, predecessors, RAUW, split blocks, move/clone/erase instructions
- IR and bitcode parsing/writing, lazy bitcode modules, module cloning/linking, diagnostics, attributes, COMDATs, calling conventions, linkage/visibility/storage controls
- Metadata/debug-info APIs including named metadata views, module flag views, instruction/global metadata mappings, DIBuilder recipes, and debug-location scopes
- Target lookup, data layouts, `Module.emit_object()`, `Module.emit_assembly()`, target-machine emission, and PassBuilder pipeline execution via `Module.optimize()`, `Function.optimize()`, and `Module.run_passes()`
- Generic intrinsic calls with `Builder.intrinsic(...)` and in-process JIT execution through the LLVM-C ORC LLJIT API
- Lifetime/validity guards that turn many use-after-free, disposed-object, null-reference, and wrong-kind mistakes into Python exceptions instead of hard crashes
- Auto-generated typed `.pyi` stubs for IDEs/type checkers
- Golden-master tests, Python regression scripts, examples, and vendored `llvm-c-test` lit tests, including CI coverage against installed wheels

## Documentation

Type stubs are auto-generated and provide IDE intellisense. After building, find them at:
```
.venv/lib/python3.*/site-packages/llvm/__init__.pyi
```

For development documentation, see `devdocs/README.md`.

## Known limitations

- The API is not stable yet; method names and ownership rules may still change.
- Scope follows the LLVM-C API, not the full LLVM C++ API. JIT support is intentionally limited to what is exposed cleanly through LLVM-C ORC LLJIT.
- Docs are currently the README, examples, `devdocs/`, and the generated `.pyi` stub; there is no hosted API reference yet.
- Prebuilt wheels currently target CPython 3.12+ stable ABI on Linux x86_64/aarch64, macOS arm64/x86_64, and Windows x86_64. Other platforms require a source build.

## Development

### Setup

Source/development builds need LLVM 21.1.6 available to CMake. The LLVM archives used for packaging are published at [LLVMParty/llvm-builds v21.1.6](https://github.com/LLVMParty/llvm-builds/releases/tag/v21.1.6).

From a checkout, download the matching LLVM archive and then run `uv sync`:

```bash
# Choose the archive matching your platform:
#   llvm-21.1.6-linux-x86_64.zip
#   llvm-21.1.6-linux-aarch64.zip
#   llvm-21.1.6-macos-arm64.zip
#   llvm-21.1.6-macos-x86_64.zip
#   llvm-21.1.6-windows-x86_64.zip
python tools/ci/install_llvm.py \
  --version 21.1.6 \
  --archive llvm-21.1.6-linux-x86_64.zip \
  --dest .llvm \
  --prefix-file .llvm-prefix

uv sync --verbose
```

If you are using your own LLVM install instead, set `LLVM_ROOT` to its install prefix:

```bash
export LLVM_ROOT=/path/to/llvm
uv sync --verbose
```

If `.llvm-prefix` already points at another LLVM install, delete it first; CMake may reuse it from a previous configure.

For offline builds:

```bash
uv sync --offline --no-build-isolation --verbose
```

For Windows C++/LSP setup, see the Windows development section below.

### Testing

```bash
# Main golden-master suite:
# - runs C++ test executables from build/
# - runs paired Python scripts
# - compares Python output against stored C++ behavior
uv run run_tests.py

# Python-only regression scripts in tests/regressions/
uv run run_tests.py --regressions

# Vendored llvm-c-test lit suite against the C test binary
# Rebuilds the vendored C binary before running lit.
uv run run_llvm_c_tests.py
uv run run_llvm_c_tests.py -v

# Vendored llvm-c-test lit suite against the Python implementation
uv run run_llvm_c_tests.py --use-python

# Run the Python llvm-c-test port directly during development
uv run python -m llvm_c_test --targets-list

# Type checking (not a test suite, but commonly run in CI/dev)
uvx ty check
```

If you want the closest thing to “run everything in this repo”, use:

```bash
uv run run_tests.py
uv run run_tests.py --regressions
uv run run_llvm_c_tests.py
uv run run_llvm_c_tests.py --use-python
```

Python tests here are intended to be executable as standalone scripts
(e.g. `uv run tests/test_module.py` or `uv run tests/regressions/test_const_bytes.py`).
They are generally pytest-compatible too, but direct script execution is the
historical/default style used by `run_tests.py` and for one-off debugging.

`pytest` is still useful for targeting specific regression files or subsets, but
it is not our complete top-level test entrypoint by itself.

### Coverage

```bash
# Run with coverage
uv run coverage run run_llvm_c_tests.py --use-python
uv run coverage combine
uv run coverage report --include="llvm_c_test/*"
```

### Windows source builds and C++ IntelliSense

The wheel is the easiest path on Windows. If you need a source/development build, install Visual Studio or Visual Studio Build Tools with the C++ workload, then fetch LLVM and run `uv sync`:

```powershell
py -3.12 tools\ci\install_llvm.py `
  --version 21.1.6 `
  --archive llvm-21.1.6-windows-x86_64.zip `
  --dest .llvm `
  --prefix-file .llvm-prefix

uv sync --verbose
```

That command downloads from [LLVMParty/llvm-builds v21.1.6](https://github.com/LLVMParty/llvm-builds/releases/tag/v21.1.6), installs into `.llvm`, and writes `.llvm-prefix` for CMake.

If you are using your own LLVM install instead:

```powershell
$env:LLVM_ROOT = "C:\path\to\llvm"
uv sync --verbose
```

For C++ local development with an LSP, create a local `CMakeUserPresets.json` at the repository root. CMake gets LLVM from `.llvm-prefix` created above, or from `LLVM_ROOT` on first configure. The compiler paths below assume the usual LLVM installer location; adjust them if your `clang-cl.exe` is elsewhere:

```json
{
    "version": 3,
    "configurePresets": [
        {
            "name": "clang-cl",
            "displayName": "Ninja with clang-cl",
            "generator": "Ninja",
            "binaryDir": "${sourceDir}/build",
            "cacheVariables": {
                "CMAKE_C_COMPILER": "C:/Program Files/LLVM/bin/clang-cl.exe",
                "CMAKE_CXX_COMPILER": "C:/Program Files/LLVM/bin/clang-cl.exe",
                "CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
                "CMAKE_BUILD_TYPE": "RelWithDebInfo"
            }
        }
    ],
    "buildPresets": [
        {
            "name": "clang-cl",
            "configurePreset": "clang-cl"
        }
    ]
}
```

Then configure/build with:

```powershell
cmake --preset clang-cl
cmake --build --preset clang-cl
```

If you move or replace the LLVM install, delete or regenerate `.llvm-prefix` from any previous configure.

## License

This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.

LLVM is licensed under the Apache License v2.0 with LLVM Exceptions.

