JuliaLibWrapping

JuliaLibWrapping turns ordinary Julia functions into a shared library with a C header and an installable Python ctypes package. ABI export requires Julia 1.13 or later.

For most libraries, the complete interface starts with a declaration like this:

scale(a::Vector{Float64}; factor::Float64 = 2.0) = factor .* a
@api scale(a::Vector{Float64}; factor::Float64 = 2.0)::Vector{Float64}

@api creates the C-ABI entrypoint, converts arguments and results, transports Julia exceptions safely, and records enough metadata to generate an idiomatic Python function. Start with Your first wrapper to build and call a small library end to end.

Choose an authoring path

Declare an API with @api when you control the foreign interface. This is the default path: write ordinary Julia functions and declare the signatures to expose. Arrays, strings, string vectors, dictionaries, optional scalars, enums, and primitive values have built-in mappings. See Declaring an API with @api and Supported Julia types.

Write ABI entrypoints by hand when an existing C header fixes the exact signature, when the caller must provide output buffers, or when you deliberately want a custom result struct and Python façade. See Hand-written ABI entrypoints and the custom OLS tutorial. The two styles can coexist in one library.

What the package produces

JuliaC.jl compiles the shared library and emits ABI metadata. JuliaLibWrapping consumes that metadata and emits a C header or Python package. standard_build drives the complete process for a conventional project; build_library provides detailed control.

The Python output separates regenerated mechanical bindings from an author-editable public façade. A bundled package can carry its own Julia runtime, so its users do not need Julia installed. See Generated Python bindings and Building and distributing a library.

Find a topic