3 Libraries and Saved Images
dxtr edited this page 2026-10-18 15:16:26 +02:00

Libraries and Saved Images

Defining a library

(ffi:define-foreign-library libfreetype
  (:darwin (:or "libfreetype.6.dylib" "libfreetype.dylib"))
  (:windows (:or "C:/path/to/native/freetype.dll" "freetype.dll"))
  (:unix (:or "libfreetype.so.6" "libfreetype.so"))
  (t (:default "libfreetype")))

Each clause is (condition spec), and the first whose condition holds says what to load.

  • A condition is t, a keyword, or (:or ...), (:and ...) and (:not ...) of them. A keyword is one of cl-ffi's platform keywords, :windows, :unix, :linux and :darwin, or a feature in *features*. :windows holds on Windows, though SBCL sets only :win32.
  • A spec is a file name the system searches for, such as "libz.so.1", or a full path; (:or spec...) to try one after the other; or (:default "name") for name.so, name.dll or name.dylib.

cl-ffi has no list of directories of its own: where a library is outside the system's search path, give its full path, or put its directory on the system's search path.

Loading

(ffi:use-foreign-library libfreetype)       ; at top level, when the file loads
(ffi:load-foreign-library 'libfreetype)     ; when called
(ffi:load-foreign-library "libicui18n.so.78")   ; a library of no name, from a spec

load-foreign-library loads a library unless it is loaded, and returns its designator and the file it was loaded from. Besides a defined name it takes a spec, for a library whose file name is known only at run time. foreign-library-loaded-p and foreign-library-pathname take either, and say whether and from which file.

A library that cannot be loaded signals a load-foreign-library-error, whose report lists each file tried with the system's reason:

Could not load the foreign library LIBMISSING.
  libmissing.so.1: Error opening shared object "libmissing.so.1": libmissing.so.1: cannot open shared object file: No such file or directory.
  libmissing.so: Error opening shared object "libmissing.so": libmissing.so: cannot open shared object file: No such file or directory.

A binding usually catches it and adds what to install. It is signalled once cl-ffi has let go of the lock it loads libraries under, so a handler, or the debugger, may load another library in its place:

(handler-case (ffi:load-foreign-library 'libfreetype)
  (ffi:load-foreign-library-error ()
    (ffi:load-foreign-library "C:/bundled/freetype.dll")))

Any thread may load libraries; one loads at a time.

Saved images

SBCL reopens the shared objects of a saved image by the paths they were loaded from, which on another machine may not exist. cl-ffi does not let it: when a saved image starts, it loads each library it loaded again, in the order it first loaded them, from its definition or spec, so a library first loaded by a developer's full path is found by name on a player's machine. Then it looks every callback's pointer up again, and runs the functions add-image-start-hook added, in the order they were added:

(ffi:add-image-start-hook 'find-functions-again)

A hook is for state about foreign code that the new process must find again, such as pointers looked up in a library by a computed name. What cannot be loaded, or a hook that fails, is reported as a warning, and the rest go on.

cl-ffi loads libraries with SBCL's :dont-save, so SBCL leaves them to cl-ffi to load again. A library a program loads through cffi beside cl-ffi is not cl-ffi's to reload.