Extending JuliaLibWrapping
This page is for target implementers and contributors. Library authors do not need the descriptor machinery to use standard_build, build_library, or JLWInterop.@api.
ABI data model
juliac assigns each type an integer id. ABIInfo contains an ordered dictionary of descriptors and a list of exported methods. Descriptors include primitive types, structures whose fields refer to other ids, pointers, and arrays; method arguments and results use the same ids. Together they form a type-dependency graph.
parse_abi_info imports the JSON representation. sort_declarations! orders definitions so an emitter can satisfy C-style declaration-before-use rules. It finds strongly connected components, removes pointer edges that permit forward declarations, topologically sorts the remaining graph, and records types needing forward declarations.
Adding a target
A target is a configuration subtype of AbstractTarget with a corresponding method:
struct MyTarget <: AbstractTarget
outdir::String
end
function JuliaLibWrapping.write_wrapper(target::MyTarget, info::ABIInfo)
# Walk the ordered descriptors and methods, then write target files.
endUse a target instance directly with write_wrapper, or include it in the target vector passed to build_library.
The built-in emitters sanitize and uniquify foreign identifiers independently; do not assume Julia type spellings are valid or unique in another language. Pointer types may also need inline treatment rather than standalone aliases.
Recognizing carriers
JuliaLibWrapping recognizes JLWInterop carriers from names and field layouts in ABI metadata rather than requiring Julia type objects at generation time. The recognizers in src/recognizers.jl cover CArray, CString, CStrArray, CDict, COpt, JLWStatus, JLWResult, raw primitive pointers, and release entrypoints. New targets can reuse these helpers so ownership and shape validation remain consistent with the built-in Python target.
Treat a failed recognition as an ordinary unrecognized struct. A target should not infer ownership from a similar-looking but invalid layout.
API sidecar metadata
read_api_metadata reads the optional sidecar generated from @api declarations, and check_metadata_consistency validates it against ABI metadata. Sidecar entries are keyed by exported C symbol. They add public names, argument/keyword descriptions, defaults, documentation, and enums to the mechanical ABI.
A target must still handle symbols absent from the sidecar: hand-written @ccallable entrypoints intentionally have no declaration metadata.
JuliaLibWrapping.read_api_metadata — Function
read_api_metadata(path::AbstractString) -> NamedTuple{(:exports, :enums)}Read the <lib>.jlw.json API metadata sidecar written by JLWInterop.write_metadata and return (; exports, enums):
exports— symbol =>{"name", "args", "kwargs", "arg_enums"?, "return_enum"?, "doc"}, asJSON.parsefilereturns it, aJSON.Object{String,Any}that behaves as anAbstractDict{String,Any}.enums— name =>{"basetype", "members"}(seeJLWInterop.write_metadata), or an emptyDict{String,Any}when the sidecar is version 1, which has noenumstable.
Throws an ErrorException when the file's jlw_metadata_version is neither 1 nor 2, the versions this reader understands.
JuliaLibWrapping.check_metadata_consistency — Function
check_metadata_consistency(abi_info::ABIInfo, meta::AbstractDict, enums::AbstractDict = Dict{String,Any}()) -> NothingValidate an API metadata sidecar (as returned by read_api_metadata: meta is its exports map, enums its enums table) against the ABI JSON produced for the same build. Throws an ErrorException on:
- a sidecar entry whose symbol has no matching entrypoint in the ABI;
- an argument-count mismatch:
length(args) + length(kwargs)vs. the ABI entrypoint's argument count; - an argument-name mismatch:
[args…; kwarg names…]against the ABI entrypoint's argument names, elementwise. Targets associate the lists positionally, so a difference in either name or order would mislabel arguments. - an
arg_enumskey that does not name a declared argument or keyword of that export; - an
arg_enumsorreturn_enumvalue that names no entry inenums; - an
enumsentry whose"basetype"is not in_ENUM_BASETYPES; - an
arg_enums-annotated argument whose ABI type is not a primitive named exactly like its enum's"basetype".
JuliaLibWrapping.sanitize_for_c — Function
sanitize_for_c(str) -> StringReturn str with all non-alphanumeric (non-underscore) characters replaced by _, leading/trailing underscores stripped, and runs of underscores collapsed. Used to coerce Julia identifiers and type names into valid C tokens. Two distinct inputs may collide; callers that need uniqueness (e.g. mangle_c!) suffix the result with a numeric disambiguator.
JuliaLibWrapping._ENUM_BASETYPES — Constant
JuliaLibWrapping._ENUM_BASETYPES :: Set{String}Julia scalar type names a sidecar enum's "basetype" may legally name: the Integer subtypes of JLWInterop._API_SCALARS (a Base.Enum's type parameter must be an Integer, which excludes Float32/Float64 from that set regardless of this constant).