Skip to content

C ABI

Oxiland tip 0.13.0 ships a source-compatible Redland-shaped C library (oxiland-capi, version 0.13.0, publish = false) with a frozen allowlist. Use this surface for world → storage → model → parse/serialize → ASK/SELECT workflows against Oxiland. Milestone 0.11 demonstrated a Redland-compatible shared library name (librdf.0 / librdf.so.0) for binary ABI interchange; tip 0.13 retains that packaging and the optimized C paths. Remaining behavioral gaps are listed in the limitations guide.

Verified matrix

Milestone 0.11 closed the source corpus and librdf-compat packaging gates on the frozen targets/profiles; tip 0.13 retains that evidence. Read C ABI limitations for remaining behavioral gaps (factories, iostream tagging, log surface). Interchange evidence lives under compatibility/downstream/ and compatibility/qualification/.

Prerequisites

  • Rust 1.87+ (edition and MSRV used by the workspace)
  • A C compiler (cc / Clang / GCC)
  • A clone of this repositoryoxiland-capi has publish = false and is not on crates.io

Build the library

From the repository root:

cargo build -p oxiland-capi --release

The default build enables Fjall. To compile an optional durable backend into the C library, pass its matching feature, for example --features storage-sqlite or --features storage-lmdb.

Artifacts (paths relative to the repo root):

Artifact Path
Static library target/release/liboxiland_capi.a
Shared library (macOS) target/release/liboxiland_capi.dylib
Shared library (ELF) target/release/liboxiland_capi.so
Compat shared library (macOS) target/release/compat/librdf.0.dylib (+ librdf.dylib)
Compat shared library (ELF) target/release/compat/librdf.so.0 (+ librdf.so)
Header crates/oxiland-capi/include/librdf.h
pkg-config template crates/oxiland-capi/oxiland.pc.in
Drop-in Redland pkg-config crates/oxiland-capi/librdf-compat.pc.in
Symbol version script (ELF) crates/oxiland-capi/symbols.version (OXILAND_0.11 + LIBRDF_1.0.17)

Debug builds place the same libraries under target/debug/.

Redland-compatible packaging (0.11)

cargo build -p oxiland-capi --release
scripts/package-librdf-compat.sh

On macOS the script sets @rpath/librdf.0.dylib via install_name_tool. On Linux it sets soname librdf.so.0 with patchelf when available. Point DYLD_LIBRARY_PATH / LD_LIBRARY_PATH (or pkg-config) at target/release/compat for load-without-rebuild checks:

compatibility/downstream/abi/run-abi-swap.sh
compatibility/downstream/corpus/run-corpus.sh

Canonical one-liner from the repository root (debug build + example):

cargo build -p oxiland-capi
cc -I crates/oxiland-capi/include -L target/debug \
  crates/oxiland-capi/examples/preview_workflow.c \
  -loxiland_capi -Wl,-rpath,$PWD/target/debug \
  -o preview_workflow

Release variant:

cargo build -p oxiland-capi --release
cc -I crates/oxiland-capi/include -L target/release \
  crates/oxiland-capi/examples/preview_workflow.c \
  -loxiland_capi -Wl,-rpath,$PWD/target/release \
  -o preview_workflow

-Wl,-rpath,$PWD/target/debug (or .../release) is the usual macOS pattern so the dynamic loader finds liboxiland_capi.dylib without installing it. On Linux you may use -Wl,-rpath,$PWD/target/debug the same way, or set LD_LIBRARY_PATH.

Link with -loxiland_capi (the cdylib / staticlib name is liboxiland_capi).

pkg-config

  1. Copy crates/oxiland-capi/oxiland.pc.in to a writable location (for example ./oxiland.pc).
  2. Substitute @PREFIX@ and @VERSION@ (use 0.13.0 for the C API crate).
  3. Put that directory on PKG_CONFIG_PATH and query flags:
sed 's|@PREFIX@|'"$PWD"'/stage|g; s|@VERSION@|0.13.0|g' \
  crates/oxiland-capi/oxiland.pc.in > ./oxiland.pc
export PKG_CONFIG_PATH="$PWD:${PKG_CONFIG_PATH:-}"
pkg-config --cflags --libs oxiland

The template ships Name: oxiland and links -loxiland_capi.

For a Redland drop-in name (-lrdf), use librdf-compat.pc.in (or the redland.pc written by scripts/package-librdf-compat.sh under target/release/compat/).

Frozen development snapshot

Only the symbols declared in the shipped header are exported. Unsupported Redland APIs are omitted rather than stubbed.

Area Symbols
World construction, logging, and logger callbacks
Storage construction, open, discovery, and sync
Model CRUD, streams, sync, string export, SPARQL Update, and queries
Terms URI, node, and statement construction, accessors, mutation, and string forms
I/O parser/serializer names plus string, counted-string, and file variants
Query ASK, SELECT, CONSTRUCT/DESCRIBE graph streams, and result iteration
Utilities MD5/SHA digests, UTF-8/Latin-1 conversion, basename, and allocator release

Handle ownership

Opaque handles follow the contract in design/0.8-cabi.md (handle matrix, allocator, panic containment):

  • Free handles only with the matching librdf_free_*.
  • Free library-returned strings only with librdf_free_memory.
  • NULL free is a no-op; every extern "C" entry contains panics via catch_unwind.

Storage names

librdf_new_storage accepts "memory", "fjall", and any optional backend compiled into oxiland-capi ("redb", "rocksdb", "sqlite", or "lmdb"; durable names use name as their path). Known optional backends that are not compiled fail with an explicit unsupported message distinct from unknown names—the same registry as Rust StorageBackend::from_name.

Evidence

Compatibility claims for this surface are scoped in the 0.9 report, the 0.10 qualification report, and the parity ledger.