Emacs Lisp Foreign Function Interface
C++ Emacs Lisp Makefile
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Emacs Lisp Foreign Function Interface

This library provides an FFI for Emacs Lisp so that Emacs programs can invoke functions in native libraries. It works by driving a subprocess to do the heavy lifting, passing result values on to Emacs.


A function signature is described by a vector of type keywords. The first element is the return value and the rest are the types of the arguments. Integers, floats, strings, and pointer values obtained from previous calls are allowed as arguments.

;; srand(0) and rand()
(ffi-call nil "srand" [:void :uint32] 0)
;; => :void
(ffi-call nil "rand" [:sint32])
;; => 1102520059

;; cos(1.2)
(ffi-call "libm.so" "cos" [:double :double] 1.2)
;; => 0.362357754476674

;; time(NULL);
(ffi-call nil "time" [:uint64 :pointer] nil)
;; => 1396496875

;; getenv("DISPLAY")
(ffi-get-string (ffi-call nil "getenv" [:pointer :pointer] "DISPLAY"))
;; => ":0"

The function signatures (CIFs) and handles are cached so that they don't need to be redefined/fetched/loaded by the subprocess on each function invocation.

Getting the function signature wrong may crash the subprocess (the FFI "context"), but Emacs itself will be safe from crashes.


You'll need a C++11 compiler and libffi in order to build the native helper program. Run make before attempting to use the FFI from within Emacs.

Like the underlying libffi, there is no explicit support for calling variadic functions, but it may still sometimes work.

There's no support for parsing/handling structs, so these must be read raw. This will probably not change.

There's not yet any support for building closures, so that native functions can call back to Emacs.

Emacs will not be able to handle very large integer values, because Emacs' primitive integers are always slightly smaller than the system's word size (tagged ints). This is especially an issue with 32-bit Emacs. Pointers are stored as symbols, evading these integer limitation.


The helper subprocess is a stack machine that operates by a very simple, human-readable bytecode. The bytecode itself is primarily documented in the C++ source. Emacs pushes values onto the stack and invokes native function calls on them, leaving the result on the stack.