RepliBuild.jl
ABI-aware C/C++ compiler bridge for Julia. Point it at source code, get type-safe Julia bindings — correct struct layouts, enum definitions, calling conventions, and virtual dispatch — without writing a single ccall by hand.
New to RepliBuild? Read Why RepliBuild for background on what problem it solves and how it compares to CxxWrap.jl, Clang.jl, and manual ccall.
Overview
RepliBuild compiles your C/C++ source with Clang, then combines multiple information sources to generate bindings that are correct by construction:
- DWARF debug metadata — struct member offsets, sizes, function signatures, vtable layout, bitfield positions. This is the compiler's own record of what it produced — always accurate for the target platform.
- Symbol tables (
nm) — mangled C++ names and function addresses. The authoritative linking identity. - Clang.jl AST — enums the compiler optimized away, function pointer typedefs, macro definitions. Fills gaps where DWARF is incomplete.
- Cross-verification — DWARF struct size is checked against Julia's alignment calculation. If they disagree, the struct is packed and gets routed to an MLIR thunk instead of
ccall(which would silently misalign fields).
Functions are automatically routed to one of three calling tiers — Base.llvmcall with LTO bitcode, MLIR AOT thunks, or ccall — based on ABI complexity.
Three-tier dispatch
| Tier | Mechanism | When selected |
|---|---|---|
| 1 | Base.llvmcall | POD args, scalar/pointer return, LTO bitcode available |
| 2 | MLIR AOT thunks (libJLCS.so) | Packed structs, unions, large struct return, C++ virtual dispatch |
| 3 | ccall | Fallback when bitcode is unavailable |
Tier selection is automatic — the wrapper generator analyses each function signature against DWARF metadata and emits the appropriate calling convention.
Quick start
using RepliBuild
# Scan a C/C++ project, generate replibuild.toml, compile, and wrap
RepliBuild.discover("path/to/project", build=true, wrap=true)
# Load the generated module
include("path/to/project/julia/MyProject.jl")
using .MyProjectOr step by step:
toml = RepliBuild.discover("path/to/project") # generates replibuild.toml
RepliBuild.build(toml) # Clang → LLVM IR → .so + DWARF metadata
RepliBuild.wrap(toml) # DWARF → Julia module in julia/Package registry
RepliBuild.register("path/to/project/replibuild.toml") # one-time registration
Lua = RepliBuild.use("lua") # build + wrap + load, cached
Lua.luaL_newstate()What gets wrapped
- Structs with correct field order, alignment padding, and topological sort for circular references
- Enums via
@enumwith correct underlying types (Clang.jl AST walker) - Unions as
NTuple{N,UInt8}with typed getter/setter accessors - Bitfields with bit-level extraction
- Function pointers with DWARF signature parsing to
@cfunction-compatible types - Variadic functions with typed overloads via
[wrap.varargs]config - Macros with auto-generated typed shims via
[wrap.macros]config - Multi-level pointers / references —
T**→Ptr{Ptr{T}},T&→Ref{T} - C++ virtual methods via MLIR JIT thunks or static AOT thunks
- Idiomatic wrappers — factory/destructor pairs →
mutable structwith GC finalizers - Global variables via
cglobalaccessors - Templates — declare in
[types].templates; RepliBuild forces DWARF emission
Example: wrapping a git dependency
# replibuild.toml
[dependencies.cjson]
type = "git"
url = "https://github.com/DaveGamble/cJSON"
tag = "v1.7.18"
exclude = ["test", "fuzzing"]RepliBuild.build("replibuild.toml")
RepliBuild.wrap("replibuild.toml")
include("julia/MyCjsonWrapper.jl")
using .MyCjsonWrapper
obj = cJSON_CreateObject()
cJSON_AddStringToObject(obj, "key", "value")Configuration
The replibuild.toml file controls the entire build. Generated by discover(), hand-editable:
[project]
name = "MyEngine"
[compile]
flags = ["-O3", "-std=c++17", "-fPIC"]
parallel = true
[link]
enable_lto = false # true → emit _lto.bc for Base.llvmcall (Tier 1)
optimization_level = "3"
[wrap]
language = "cpp" # "c" | "cpp" (auto-detected by discover())
use_clang_jl = true
aot_thunks = false # true → pre-compile MLIR thunks (Tier 2)
[types]
strictness = "warn"
templates = ["std::vector<int>"]
template_headers = ["<vector>"]
[dependencies.mylib]
type = "git"
url = "https://github.com/example/mylib"
tag = "v1.0.0"See the Configuration Reference for all available options.
Documentation
- Why RepliBuild — What problem it solves, how it combines DWARF + symbols + AST, comparison to alternatives
- How It Works — Two JITs, one IR: how Julia and C++ converge at the LLVM level
- Architecture — Full system architecture, pipeline stages, tier dispatch, design decisions
- User Guide — Workflows, dependencies, LTO, AOT thunks, templates, registry
- Configuration Reference — Complete
replibuild.tomloption reference - API Reference — Public API documentation
- MLIR / JLCS Dialect — Custom MLIR dialect, type system, operations, JIT manager
- Introspection Tools — Binary analysis, IR inspection, benchmarking
- Benchmarks — Zero-copy benchmark data
- Internals — Module architecture for contributors