#lang scribble/doc @(require "utils.ss" (for-syntax setup/dirs)) @title{Loading Foreign Libraries} The FFI is normally used by extracting functions and other objects from @as-index{shared objects} (a.k.a. @defterm{@as-index{shared libraries}} or @defterm{@as-index{dynamically loaded libraries}}). The @scheme[ffi-lib] function loads a shared object. @defproc[(ffi-lib? [v any/c]) boolean>]{ Returns @scheme[#t] if @scheme[v] is the result of @scheme[ffi-lib], @scheme[#f] otherwise.} @; ---------------------------------------------------------------------- @section{Unsafe Library Functions} @declare-exporting[scribblings/foreign/unsafe-foreign] @defproc[(ffi-lib [path (or/c path-string? false/c)] [version (or/c string? (listof string?) false/c) #f]) any]{ Returns an foreign-library value. If @scheme[path] is a path, the result represents the foreign library, which is opened in an OS-specific way (using @cpp{LoadLibrary} under Windows, and @cpp{dlopen} under Unix and Mac OS X). 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 @scheme[version] string can be supplied, which is appended to the name after any added suffix. If you need any of a few possible versions, use a list of version strings, and @scheme[ffi-lib] will try all of them. If @scheme[path] is @scheme[#f], then the resulting foreign-library value represents all libraries loaded in the current process, including libraries previously opened with @scheme[ffi-lib]. In particular, use @scheme[#f] to access C-level functionality exported by the run-time system (as described in @|InsideMzScheme|). Note: @scheme[ffi-lib] tries to look for the library file in a few places like the PLT libraries (see @scheme[get-lib-search-dirs]), a relative path, or a system search. However, if @cpp{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 @cpp{dlopen} on the unmodified argument name. For example, if you have a local @filepath{foo.so} library that cannot be loaded because of a missing symbol, using @scheme[(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 @cpp{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., @filepath{./foo.so}).} @defproc[(get-ffi-obj [objname (or/c string? bytes? symbol?)] [lib (or/c ffi-lib? path-string? false/c)] [type ctype?] [failure-thunk (or/c (-> any) false/c) #f]) any]{ Looks for the given object name @scheme[objname] in the given @scheme[lib] library. If @scheme[lib] is not a foreign-library value produced by @scheme[ffi-lib], it is converted to one by calling @scheme[ffi-lib]. If @scheme[objname] is found in @scheme[lib], it is converted to Scheme using the given @scheme[type]. Types are described in @secref["types"]; in particular the @scheme[get-ffi-obj] procedure is most often used with function types created with @scheme[_fun]. Keep in mind that @scheme[get-ffi-obj] is an unsafe procedure; see @secref["intro"] for details. If the object is not found, and @scheme[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: @schemeblock[ (define foo (get-ffi-obj "foo" foolib (_fun _int -> _int) (lambda () (error 'foolib "installed foolib does not provide \"foo\"")))) ] The default (also when @scheme[failure-thunk] is provided as @scheme[#f]) is to raise an exception.} @defproc[(set-ffi-obj! [objname (or/c string? bytes? symbol?)] [lib (or/c ffi-lib? path-string? false/c)] [type ctype?] [new any/c]) void?]{ Looks for @scheme[objname] in @scheme[lib] similarly to @scheme[get-ffi-obj], but then it stores the given @scheme[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 Scheme callbacks.} @defproc[(make-c-parameter [objname (or/c string? bytes? symbol?)] [lib (or/c ffi-lib? path-string? false/c)] [type ctype?]) (and/c (-> any) (any/c -> void?))]{ Returns a parameter-like procedure that can either references the specified foreign value, or set it. The arguments are handled as in @scheme[get-ffi-obj]. A parameter-like function is useful in case Scheme code and library code interact through a library value. Although @scheme[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.} @defform[(define-c id lib-expr type-expr)]{ Defines @scheme[id] behave like a Scheme binding, but @scheme[id] is actually redirected through a parameter-like procedure created by @scheme[make-c-parameter]. The @scheme[id] is used both for the Scheme binding and for the foreign object's name.} @defproc[(ffi-obj-ref [objname (or/c string? bytes? symbol?)] [lib (or/c ffi-lib? path-string? false/c)] [failure-thunk (or/c (-> any) false/c) #f]) any]{ Returns a pointer object for the specified foreign object. This procedure is for rare cases where @scheme[make-c-parameter] is insufficient, because there is no type to cast the foreign object to (e.g., a vector of numbers).}