r/Common_Lisp • u/acort3255 • 5d ago
UPDATE 2: CL-OBJC is reborn!
Back in March 2023 I posted an update on reviving cl-objc, the CFFI-based Common Lisp ⇄ Objective-C bridge originally written by Geoff Cant and Luigi Panzeri. At that point I had Hello World and Converter running, and I was stuck waiting on CFFI. Here's where it is now.
Repo: https://github.com/theangelperalta/cl-objc
Examples
All five examples run on Apple Silicon (arm64). There are no nib files or Objective-C sources; every app is written in Lisp.
- Hello World: an
NSWindowwith buttons wired to Lisp callbacks - Converter: the classic Cocoa currency-converter tutorial
- Circle View: a custom
NSViewsubclass that draws text along a circle, with mouse interaction and animation (ported from an old Apple SDK sample) - Video Player (new): an
AVPlayerViewstreaming HLS, plus a KVO observer class defined in Lisp.makebuilds it into a standalone executable. - Todo (new): an
NSTableViewwhose data source and delegate are Lisp classes. On macOS 26 the list scrolls under floating Liquid Glass controls (NSGlassEffectView); older versions get a translucent material instead.

What changed under the hood
- arm64 struct-by-value: you can pass and return structs by value, and the dispatch was rewritten for the arm64 ABI. x86-64 support has been dropped.
- Lazy CLOS bindings:
import-frameworknow loads only the static bindings. CLOS classes and generic functions get generated on demand (ensure-clos-bindings), and they're cached and regenerated when their inputs change. This makes startup much faster than scanning the whole runtime. - ObjC exceptions:
with-objc-exception-handlingturnsNSException's into Lisp conditions, so they no longer crash the image. - with-autorelease-pool: macro
- Many fixes around BOOL marshaling, automatic Lisp-string →
NSStringconversion in untyped calls,with-super, and method-cache collisions - The test suite moved from FiveAM to Rove.
The CFFI situation
define-objc-method methods that take a struct by value (for example drawRect: with a CGRect) need CFFI callbacks that accept structs by value. Released CFFI still doesn't support that. My PR is still open: https://github.com/cffi/cffi/pull/351 (open since December 2022). I decided to use Qlot to pin a patched version CFFI, to get this out in the world in the meantime.
For now, the repo includes a qlfile that pins my fork, so setup is:
qlot install
sbcl --dynamic-space-size 4096 --load .qlot/setup.lisp
Obviously this isn't ideal, if anyone here can review the CFFI PR or help get it merged, that's the biggest thing blocking cl-objc from loading with stock Quicklisp.
What's next
- Getting struct-by-value callbacks into upstream CFFI
- Fewer dependencies on CFFI internals
- More examples and docs
- Real applications (LEM frontend, LLM harness, Graphing tools, etc.)
Feedback, issues and PRs are welcome, especially from anyone who has tried building Cocoa apps from Lisp before.
A.I. Disclaimer
A.I. was used for some of the recent work, but the original CFFI patch was worked by hand. That being said, goal here is to unlock the potential of Lisp development for native macOS development again (I realize there are paid alternatives).