On this page:
Lib
Lib.load
Lib.find
Lib.handle
Lib.from_  handle
0.45+9.2.0.4

2.1 Foreign Libraries🔗ℹ

class

class Lib()

Represents a foreign library. Create a Lib instance with Lib.load, and access exports of a loaded library using Lib.find.

function

fun Lib.load(

  path :: PathString || False,

  version :: String || List.of(String || False) || False = #false,

  ~get_lib_dirs: get_lib_dirs :: () -> (Listable.to_list && List.of(Path))

                   = #{get-lib-search-dirs},

  ~fail: fail :: maybe(() -> maybe(Lib)) = #false,

  ~as_global: as_global :: Any.to_boolean = #false,

  ~custodian: cust :: maybe(Custodian || Any.of(#'place)) = #false

) :: maybe(Lib)

If path is #false, then the resulting foreign-library value represents all libraries loaded in the current process, including libraries previously opened with Lib.load. The version argument is ignored when path is #false.

Otherwise, path and version will be combined as follows:

  • path: A path string that typically does not have a version or suffix (i.e., without ".dll", ".so", or ".dylib").

  • version: A list, usually, of versions to try in order with #false (i.e., no version) as the last element of the list; for example, ["2", #false] indicates version 2 with a fallback to a versionless library. A string or #false version is equivalent to a list containing just the string or #false, and an empty string (by itself or in a list) is equivalent to #false.

    When the library suffix as reported by system.so_suffix is ".dylib", then a version is added to path after a "." and before the ".dylib" suffix. When the library suffix is ".dll", then a version is added to path after a "-" and before the ".dll" suffix. For any other suffix, the version number is added after the suffix plus ".".

    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 #false is typically best for version.

Assuming that path is not #false, the result from Lib.load represents the library found by the following search process:

  • If path is not an absolute path, look in each directory reported by get_lib_dirs; the default list is the result of #{get-lib-search-dirs}(). In each directory, try path with the first version in version, adding a suitable suffix if path does not already end in the suffix, then try the second version in version, etc. (If version is an empty list, no paths are tried in this step.)

  • Try the same filenames again, but without converting the path to an absolute path, which allows the operating system to use its own search paths. (If version is an empty list, no paths are tried in this step.)

  • Try path without adding any version or suffix, and without converting to an absolute path.

  • Try the version-adjusted filenames again, but relative to the current directory. (If version is an empty list, no paths are tried in this step.)

  • Try path without adding any version or suffix, but converted to an absolute path relative to the current directory.

If none of the paths succeed and fail is a function, then fail is called to get a result for Lib.load. If fail is #false, an exception is thrown as if trying just 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 not #false, as_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 Lib.load(#false).

If custodian is a Custodian, the library is unloaded when custodian is shut down. When a library is unloaded, all references to the library become invalid. Supplying Custodian.current() 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 #'place, it is equivalent to the main custodian of the current place, which is consistent with finalization via ffi/finalize. If custodian is #false, the loaded library is associated with Rhombus (or DrRacket) for the duration of the process; in that case, loading again with Lib.load, will not force a re-load of the corresponding library.

When Lib.load 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 Lib.load function logs 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.

method

method (lib :: Lib).find(

  name :: String || Bytes || Symbol,

  ~fail: fail :: maybe(() -> maybe(ptr_t)) = #false

) :: maybe(ptr_t)

Looks for the byte-string form of name as an export from lib. If name is found in lib, its address is returned as a pointer object.

If name is not found and fail is a function, it is called to get the result for Lib.find. For example, a failure thunk can be provided to report a specific error if a name is not found:

def foo:

  Lib.find(foolib,

           "foo",

           fun ():

             error("installed foolib does not export \"foo\""))

If name is not found and fail is #false, an exception is thrown.

property

property (lib :: Lib).handle :: Any

 

function

fun Lib.from_handle(lib :: Any) :: Lib

Converts to and from a representation of a foreign library that is compatible with Racket’s libraries.