askill
clojure-coffi

clojure-coffiSafety 90Repository

Coffi FFI library for calling native C code from Clojure via Panama FFM API (JDK 22+). Use when: wrapping native C libraries, calling native functions, working with off-heap memory and arenas, etc.

0 stars
1.2k downloads
Updated 2/8/2026

Package Files

Loading files...
SKILL.md

Coffi FFI Library

Coffi wraps the Panama Foreign Function & Memory API for calling native C code from Clojure.

Setup

Add to deps.edn:

;; use gh cli to check latest commit with `gh browse  -c -n IGJoshua/coffi`
io.github.IGJoshua/coffi                  {:git/sha "ae3e38a449c88b998db98b0d4bffa9908dea1c79"}

JVM argument required:

--enable-native-access=ALL-UNNAMED

Or in deps.edn alias:

{:aliases {:dev {:jvm-opts ["--enable-native-access=ALL-UNNAMED"]}}}

Prep deps

clojure -Xdeps prep :aliases '[:dev :test]'

Quick Start

(require '[coffi.ffi :as ffi :refer [defcfn]]
         '[coffi.mem :as mem])

;; Wrap a native function
(defcfn strlen
  strlen [::mem/c-string] ::mem/long)

(strlen "hello") ;; => 5

;; Load a library
(ffi/load-system-library "z")        ;; System library
(ffi/load-library "path/to/lib.so")  ;; From path

Core Pattern: defcfn

(defcfn var-name
  "docstring"
  native_symbol_name [arg-types...] return-type)

;; With wrapper logic
(defcfn var-name
  "native_symbol" [arg-types...] return-type
  native-fn        ;; Binds the raw native function
  [clj-args...]    ;; Clojure argument list
  (body...))       ;; Wrapper body that calls native-fn

Type Quick Reference

Coffi TypeC TypeNotes
::mem/byteint8_t
::mem/shortint16_t
::mem/intint32_t
::mem/longint64_t
::mem/floatfloat
::mem/doubledouble
::mem/pointervoid*
::mem/c-stringchar*Null-terminated
::mem/voidvoidReturn only
[::mem/struct [...]]structSee below
[::mem/array type n]type[n]Fixed size
[::ffi/fn [args] ret]function ptrCallbacks

For complete type reference: references/types.md

Struct Definition

(require '[coffi.layout :as layout])

;; Always use layout/with-c-layout for FFI structs
(mem/defalias ::my-struct
  (layout/with-c-layout
    [::mem/struct
     [[:name ::mem/c-string]
      [:count ::mem/int]
      [:value ::mem/double]]]))

;; Use in function
(defcfn process-data
  process_data [::my-struct] ::mem/int)

(process-data {:name "test" :count 5 :value 3.14})

Memory Arenas

Always use confined-arena with with-open for temporary allocations:

(with-open [arena (mem/confined-arena)]
  (let [ptr (mem/serialize data type arena)]
    (native-fn ptr)))
;; Memory freed automatically

Arena types:

  • confined-arena - Thread-local, freed on close (most common)
  • shared-arena - Multi-thread, freed on close
  • auto-arena - GC-managed
  • global-arena - Never freed

For details: references/memory.md

Common Patterns

Output pointer parameter

(defcfn open-resource
  "open_resource" [::mem/c-string ::mem/pointer] ::mem/int
  native-open
  [name]
  (with-open [arena (mem/confined-arena)]
    (let [out-ptr (mem/alloc-instance ::mem/pointer arena)
          code (native-open name out-ptr)]
      (if (zero? code)
        (mem/deserialize-from out-ptr ::mem/pointer)
        (throw (ex-info "Failed" {:code code}))))))

String with explicit length

(defcfn bind-text
  "bind_text" [::mem/pointer ::mem/c-string ::mem/int] ::mem/int
  native-bind
  [handle text]
  (let [bytes (.getBytes text "UTF-8")]
    (native-bind handle text (count bytes))))

Array serialization

;; Serialize array
(mem/serialize [1 2 3 4] [::mem/array ::mem/int 4] arena)

;; For raw Java arrays (better performance)
(mem/serialize (int-array [1 2 3 4]) [::mem/array ::mem/int 4 :raw? true] arena)

Callback to native code

(defcfn set-callback
  set_callback [[::ffi/fn [::mem/int] ::mem/int]] ::mem/void)

(set-callback (fn [x] (* x 2)))

For more examples: references/examples.md

Reference Files

Read these references depending on what you are doing. You should read at least one of the now, if not all of them

  • types.md - Complete type system (primitives, structs, arrays, enums, unions, custom types)
  • memory.md - Memory management (arenas, allocation, serialization, pointer ops)
  • examples.md - Real-world patterns from sqlite4clj and coffi tests

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

95/100Analyzed 2/12/2026

A comprehensive guide to using the clojure-coffi library for FFI in Clojure. It covers setup, basic function wrapping, type mapping, struct definitions, memory management with arenas, and common patterns like output pointers and callbacks.

90
95
95
90
95

Metadata

Licenseunknown
Version-
Updated2/8/2026
PublisherRamblurr

Tags

apigithubtesting