Skip to main content
Browse guides

How CSSL calls other code

Connecting a CSSL program to functions supplied by another compiled library.

FFI means foreign function interface. It is the boundary that lets code written in one programming language call a function written in another. You only need the remaining details on this page when building or reviewing CSSL code.

The contract

CSSL keeps this boundary narrow. A source file declares the function it expects with extern "C" fn name(args) -> T ; and the auto-default-link mechanism in csslc resolves the symbol against either cssl-rt (allocator + panic + exit) or one of the host-side staticlibs (loa-host and the per-system cssl-host-* crates).

Minimal extern declaration
extern "C" fn __cssl_engine_run() -> i32 ;
fn main() -> i32 {
let exit_code: i32 = __cssl_engine_run() ;
exit_code
}

Pointer + length convention

CSSL stage-0 does not yet pass Vec<T> across the FFI boundary. When a host symbol needs to expose a buffer, the convention is two adjacent arguments — one raw pointer and one length — both passed as primitive integers. This matches the C ABI exactly and works on every target Cranelift emits today.

Reading a host-side buffer
// Host signature in Rust:
// #[no_mangle]
// pub extern "C" fn __cssl_audit_read(out_ptr: *mut u8, out_len: u32) -> u32
extern "C" fn __cssl_audit_read(out_ptr: u64, out_len: u32) -> u32 ;
fn read_audit(buf_ptr: u64, buf_cap: u32) -> u32 {
let written: u32 = __cssl_audit_read(buf_ptr, buf_cap) ;
written // 0 on no-data · ≤ buf_cap on success
}
Note
Pointers as u64
Stage-0 CSSL types pointers as u64 at the FFI boundary on 64-bit targets. This is verbose but unambiguous. A typed *mut T / *const T surface lands once the type system gains aliasing rules — see the language overview.

u32 status-code pattern

Almost every host symbol returns a u32 status. Zero is success; non-zero is a structured error code that the caller can route to a typed error. This avoids exceptions, avoids Result-shaped FFI marshalling, and keeps the audit-trail emission cheap (one u32 to log per call).

CodeConvention
0OK · no error · result valid
1..127Domain-specific error · stable per host crate
128..255Permission error in the current internal convention
256..Internal error that should be recorded for diagnosis

Real example · scene FFI surface

From scenes/city_central_hub.csl: a complete scene surface with eleven extern symbols, all returning u32 status, all dispatched against loa-host wired-fn glue.

Eleven extern symbols · one scene
extern "C" fn scene_open(player_id: u64, world_seed: u128, city_id: u32) -> u32 ;
extern "C" fn scene_close(handle: u32) -> u32 ;
extern "C" fn scene_procgen_grid(handle: u32, biome_affinity: u32) -> u32 ;
extern "C" fn scene_procgen_buildings(handle: u32, density_tier: u32) -> u32 ;
extern "C" fn scene_procgen_interiors(handle: u32, enterable_pct: u32) -> u32 ;
extern "C" fn scene_procgen_npc_population(handle: u32, target_count: u32) -> u32 ;
extern "C" fn scene_kan_classify_template(handle: u32, hist_hash: u64, zone: u32, bias: u64) -> u32 ;
extern "C" fn scene_query_npc_count(handle: u32) -> u32 ;
extern "C" fn scene_apply_lod(handle: u32, player_x: i32, player_y: i32, player_z: i32) -> u32 ;
extern "C" fn scene_audit_emit(handle: u32, event_kind: u32, payload_hash: u64) -> u32 ;
extern "C" fn scene_tick(handle: u32, dt_micros: u32) -> u32 ;

The auto-default-link mechanism

When csslc emits an object file, the linker invocation automatically prepends the canonical staticlibs found in compiler-rs/target/release/:

  • libcssl_rt.a · provides __cssl_alloc, __cssl_panic, __cssl_exit, etc.
  • libloa_host.a · provides __cssl_engine_run, scene fns, render fns, MCP server
Planned
Per-system staticlib auto-link
Planned work would extend automatic linking to discover cssl-host-combat-sim, cssl-host-craft-graph, cssl-host-procgen-city, etc., so the sibling-module FFI surfaces resolve without manual --link flags.

Symbol-name conventions

  • __cssl_* — runtime + engine symbols (cssl-rt, loa-host)
  • scene_* — scene-orchestration symbols
  • render.* — MCP-tool route names (dotted, with router lookup)
  • system tick fns are __cssl_<system>_tick_<phase>