On this page:
ffi-lib?
ffi-lib
get-ffi-obj
set-ffi-obj!
make-c-parameter
define-c
ffi-obj-ref

2 Loading Foreign Libraries 🔗

The FFI is normally used by extracting functions and other objects from shared objects (a.k.a. shared libraries or dynamically loaded libraries). The ffi-lib function loads a shared object.

procedure

(ffi-lib? v)  boolean?

  v : any/c
Returns #t if v is a foreign-library value, #f otherwise.

procedure

(ffi-lib path    
  [version    
  #:get-lib-dirs get-lib-dirs    
  #:fail fail    
  #:global? global?    
  #:custodian custodian])  any
  path : (or/c path-string? #f)
  version : (or/c string? (listof (or/c string? #f)) #f) = #f
  get-lib-dirs : (-> (listof path?)) = get-lib-search-dirs
  fail : (or/c #f (-> any)) = #f
  global? : any/c = (eq? 'global (system-type 'so-mode))
  custodian : (or/c 'place custodian? #f) = #f
Returns a foreign-library value or the result of fail. Normally,

A string or #f version is equivalent to a list containing just the string or #f, and an empty string (by itself or in a list) is equivalent to #f.

Beware of relying on versionless library names. On some platforms, versionless library names are provided only by development packages. At the same time, other platforms may require a versionless fallback. A list of version strings followed by #f is typically best for version.

Assuming that path is not #f, the result from ffi-lib represents the library found by the following search process:

If none of the paths succeed and fail is a function, then fail is called in tail position. If fail is #f, an error is reported from trying the first path from the second bullet above or (if version is an empty list) from the third bullet above. A library file may exist but fail to load for some reason; the eventual error message will unfortunately name the fallback from the second or third bullet, since some operating systems offer no way to determine why a given library path failed.

If path is #f, then the resulting foreign-library value represents all libraries loaded in the current process, including libraries previously opened with ffi-lib. In particular, use #f to access C-level functionality exported by the run-time system (as described in Inside: Racket C API). The version argument is ignored when path is #f.

If path is not #f, global? is true, and the operating system supports opening a library in “global” mode so that the library’s symbols are used for resolving references from libraries that are loaded later, then global mode is used to open the library. Otherwise, the library is opened in “local” mode, where the library’s symbols are not made available for future resolution. This local-versus-global choice does not affect whether the library’s symbols are available via (ffi-lib #f).

If custodian is 'place or a custodian, the library is unloaded when a custodian is shut down—either the given custodian or the place’s main custodian if custodian is 'place. When a library is unloaded, all references to the library become invalid. Supplying 'place for custodian is consistent with finalization via ffi/unsafe/alloc but will not, for example, unload the library when hitting in the Run button in DrRacket. Supplying (current-custodian) for custodian tends to unload the library for eagerly, but requires even more care to ensure that library references are not accessed after the library is unloaded.

If custodian is #f, the loaded library is associated with Racket (or DrRacket) for the duration of the process. Loading again with ffi-lib, will not force a re-load of the corresponding library.

When ffi-lib returns a reference to a library that was previously loaded within the current place, it increments a reference count on the loaded library rather than loading the library fresh. Unloading a library reference decrements the reference count and requests unloading at the operating-system level only if the reference count goes to zero.

The ffi-lib procedure logs (see Logging) on the topic 'ffi-lib. In particular, on failure it logs the paths attempted according to the rules above, but it cannot report the paths tried due to the operating system’s library search path.

Changed in version 6.1.0.5 of package base: Changed the way a version number is added with a ".dll" suffix to place it before the suffix, instead of after.
Changed in version 7.3.0.3: Added logging.
Changed in version 7.4.0.7: Added the #:custodian argument.

procedure

(get-ffi-obj objname lib type [failure-thunk])  any

  objname : (or/c string? bytes? symbol?)
  lib : (or/c ffi-lib? path-string? #f)
  type : ctype?
  failure-thunk : (or/c (-> any) #f) = #f
Looks for objname in lib library. If lib is not a foreign-library value it is converted to one by calling ffi-lib. If objname is found in lib, it is converted to Racket using the given type. Types are described in C Types; in particular the get-ffi-obj procedure is most often used with function types created with _fun.

Keep in mind that get-ffi-obj is an unsafe procedure; see Overview for details.

If the name is not found, and failure-thunk is provided, it is used to produce a return value. For example, a failure thunk can be provided to report a specific error if a name is not found:

(define foo
  (get-ffi-obj "foo" foolib (_fun _int -> _int)
    (lambda ()
      (error 'foolib
             "installed foolib does not provide \"foo\""))))

The default (also when failure-thunk is provided as #f) is to raise an exception.

procedure

(set-ffi-obj! objname lib type new)  void?

  objname : (or/c string? bytes? symbol?)
  lib : (or/c ffi-lib? path-string? #f)
  type : ctype?
  new : any/c
Looks for objname in lib similarly to get-ffi-obj, but then it stores the given new value into the library, converting it to a C value. This can be used for setting library customization variables that are part of its interface, including Racket callbacks.

procedure

(make-c-parameter objname 
  lib 
  type 
  [failure-thunk]) 
  
(case-> (-> any)
        (any/c . -> . void?))
  objname : (or/c string? bytes? symbol?)
  lib : (or/c ffi-lib? path-string? #f)
  type : ctype?
  failure-thunk : (or/c (-> any) #f) = #f
Returns a parameter-like procedure that can either references the specified foreign value, or set it. The arguments are handled as in get-ffi-obj.

A parameter-like function is useful in case Racket code and library code interact through a library value. Although make-c-parameter can be used with any time, it is not recommended to use this for foreign functions, since each reference through the parameter will construct the low-level interface before the actual call.

Changed in version 8.4.0.5 of package base: Added failure-thunk argument.

syntax

(define-c id lib-expr type-expr)

Defines id behave like a Racket binding, but id is actually redirected through a parameter-like procedure created by make-c-parameter. The id is used both for the Racket binding and for the foreign name.

procedure

(ffi-obj-ref objname lib [failure-thunk])  any

  objname : (or/c string? bytes? symbol?)
  lib : (or/c ffi-lib? path-string? #f)
  failure-thunk : (or/c (-> any) #f) = #f
Returns a pointer for the specified foreign name, calls failure-thunk if the name is not found, or raises an exception if failure-thunk is #f.

Normally, get-ffi-obj should be used, instead.