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.
(ffi-lib path [version]) → any |
path : (or/c path-string? #f) |
version : (or/c string? (listof (or/c string? #f)) #f) = #f |
The path is not expected to contain the library suffix, which is added according to the current platform. If adding the suffix fails, several other filename variations are tried: retrying without an automatically added suffix, and using a full path of a file if it exists relative to the current directory (since the OS-level library function usually searches, unless the library name is an absolute path). An optional version string can be supplied, which is appended to the name before or after the suffix, depending on platform conventions, unless it is #f or "". If version is a list, ffi-lib will try each of them in order.
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).
Note: ffi-lib tries to look for the library file in a few places, including the Racket libraries path (see get-lib-search-dirs), a relative path, or a system search. When version is a list, different versions are tried through each route before continuing the search with other routes. However, if dlopen cannot open a library, there is no reliable way to know why it failed, so if all path combinations fail, it will raise an error with the result of dlopen on the unmodified argument name. For example, if you have a local "foo.so" library that cannot be loaded because of a missing symbol, using (ffi-lib "foo.so") will fail with all its search options, most because the library is not found, and once because of the missing symbol, and eventually produce an error message that comes from dlopen("foo.so") which will look like the file is not found. In such cases try to specify a full or relative path (containing slashes, e.g., "./foo.so").
Note! Because of the way the operating system performs dynamic binding, loaded libraries are associated with Racket or DrRacket for the duration of the process; re-evaluating ffi-lib and/or hitting the "Run" button will not force a re-load of the corresponding library.
(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 |
Keep in mind that get-ffi-obj is an unsafe procedure; see Overview for details.
If the object 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 an object 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.
(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 |
| |||||||
objname : (or/c string? bytes? symbol?) | |||||||
lib : (or/c ffi-lib? path-string? #f) | |||||||
type : ctype? |
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.
(define-c id lib-expr type-expr) |
(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 |