All Manuals > Foreign Language Interface User Guide and Reference Manual > 7 Function, Macro and Variable Reference

register-module Function

Summary

Informs LispWorks of the presence of a dynamic library.

Package

fli

Signature

register-module name &key connection-style lifetime real-name file-name dlopen-flags => name

Arguments
name
A symbol or string specifying the Lisp name the module will be registered under.
connection-style
A keyword determining when the connection to the dynamic library is made. One of :automatic , :manual or :immediate. The default value is :automatic.
lifetime
A keyword specifying the lifetime of the connection. One of :indefinite or :session. The default value is :indefinite.
real-name
Deprecated. Use file-name instead.
file-name
A pathname designator or nil.
dlopen-flags
Controls use of dlopen on non-Windows platforms. One of t (the default), nil, :local-now, :global-now, :global-lazy, :local-lazy, or a fixnum.
Values
name
A symbol or string specifying the Lisp name the module will be registered under.
Description

The function register-module explicitly informs LispWorks of the presence of a DLL or shared object file, referred to here as a dynamic library. Functions such as make-pointer and define-foreign-function have a module keyword which can be used to specify which module the function refers to.

The main use of modules is to overcome ambiguities that can arise when two different dynamic libraries have functions with the same name.

If an application is delivered after calling register-module, then the application attempts to reload the module on startup but does not report any errors. Therefore it is strongly recommended that you call register-module during initialization of your application, rather than at compile time or build time. Loading the module at run time allows you to:

You should compute and supply the appropriate full path if possible.

name is used for explicit look up from the :module keyword of functions such as define-foreign-function. If name is a symbol, then file-name should also be supplied to provide a filename. file-name defaults to the deprecated argument real-name, which defauls to nil. If file-name is nil then name must be a string that specifies the actual name of the dynamic library to connect to.

The naming convention for the module name can contain the full pathname for the dynamic library. For example, a pathname such as:

#P"C:/MYPRODUCT/LIBS/MYLIBRARY.DLL"

is specified as:

"C:\\MYPRODUCT\\LIBS\\MYLIBRARY.DLL"

On Windows, if the module is declared without an extension, ".DLL" is automatically appended to the name. To declare a name without an extension it must end with the period character ("."). On other platforms, you should provide the extension, since there is more than one library format. Typical would be .so on Linux, x86/x64 Solaris or FreeBSD and .dylib on macOS.

If a full pathname is not specified for the module, then it is searched for.

On Windows the following directories (in the given order) are searched:

  1. The directory of the executable.
  2. The Windows system directory (as specified by GetSystemDirectory).
  3. The 16-bit system directory.
  4. The Windows directory (as specified by GetWindowsDirectory).
  5. The current directory. This step can be made to happen earlier, though this is considered less safe as described in the Microsoft documentation.
  6. Directories specified by the PATH environment variable.

The simplest approach is usually to place the DLL in the same directory as the LispWorks executable or application. However if you really need different directories then be sure to call register-module at run time with the appropriate pathname.

On Linux, FreeBSD and Solaris the search is conducted in this order:

  1. Directories on the user's LD_LIBRARY_PATH environment variable.
  2. The list of libraries known to the operating system (for example, in /etc/ld.so.cache on Linux).
  3. /usr/lib, followed by /lib.

On macOS, the search is conducted in this order:

  1. Directories on the user's LD_LIBRARY_PATH environment variable.
  2. Directories on the user's DYLD_LIBRARY_PATH environment variable.
  3. ~/lib
  4. /usr/local/lib
  5. /usr/lib

If connection-style is :automatic then the system automatically connects to a dynamic library when it needs to resolve currently undefined foreign symbols.

If connection-style is :manual then the system only connects to the dynamic library if the symbol to resolve is explicitly marked as coming from this module via the :module keyword of functions such as define-foreign-function.

If connection-style is :immediate then the connection to the dynamic library is made immediately. This checks that the library can actually be loaded before its symbols are actually needed: an error is signalled if loading fails.

If lifetime is :session then the module is disconnected when Lisp starts up.

You should load only libraries of the correct architecture into LispWorks. You will need to obtain a 32-bit dynamic library for use with 32-bit LispWorks and similarly you need a 64-bit dynamic library for use with 64-bit LispWorks. (If you build the dynamic library, pass -m32 or -m64 as appropriate to cc.) You can conditionalize the argument to register-module as in the example below.

Note: On Linux, you may see a spurious "No such file or directory" error message when loading a dynamic library of the wrong architecture. The spurious message might be localized.

Note: static libraries are not supported. For example, on Linux evaluating this form:

(fli:register-module "libc.a"
                     :real-name "/usr/lib/libc.a"
                     :connection-style :immediate)

would result in an error like this:

Could not register handle for external module "libc"
/usr/lib/libc.a : invalid ELF header

The problem is that libc.a is a static library. Instead, do:

(fli:register-module "libc.so"
                     :real-name "libc.so.6"
                     :connection-style :immediate)

Note that :real-name is given a relative path in this case, because libc is a standard library on Linux and it is best to let the operating system locate it.

dlopen-flags has an effect only on non-Windows platforms. It controls the value that is passed to dlopen as second argument when the module is connected.

The keyword values of dlopen-flags correspond to combinations of RTLD_* constants (see /usr/include/dlfcn.h). The values t and nil mean the same as :local-lazy.

A fixnum value means pass this value dlopen-flags to dlopen without checking. It is the responsibility of the caller to get it right in this case.

Compatibility note:

In LispWorks 7.1 and earlier versions, dlopen-flags defaults to nil on macOS, which caused it to use the older interfaces instead of dlopen. Since LispWorks 8.0, this is no longer supported.

Notes
  1. It is strongly recommended that you call register-module during initialization of your application, rather than at compile time or build time.
  2. When developing with foreign code in LispWorks, the utilities provided in the Editor are useful - see 9.4.2 Compiling and Loading Foreign Code with the Editor.
Examples

In the following example on Windows, the user32 DLL is registered, and then a foreign function called set-cursor-pos is defined to explicitly reference the SetCursorPos function in the user32 DLL.

(fli:register-module :user-dll :real-name "user32")
(fli:define-foreign-function (set-cursor-pos 
                              "SetCursorPos")
    ((x :long)
     (y :long)) 
  :module :user-dll)

This example on Linux loads the shared library even though its symbols are not yet needed. An error is signalled if loading fails:

(fli:register-module "libX11.so"
                     :connection-style :immediate)

This example loads a module from the same directory as the Lisp executable, by executing this code at run time:

(fli:register-module
 modulename
 :file-name
 (merge-pathnames "modulefilename.dylib"
                  (lisp-image-name)))

In this last example a program which runs in both 32-bit LispWorks and 64-bit LispWorks loads the correct library for each architecture:

(fli:register-module #+:lispworks-32bit "mylib32"
                     #+:lispworks-64bit "mylib64")
See also

5.6 Incorporating a foreign module into a LispWorks image
connected-module-pathname
define-foreign-function
make-pointer
module-unresolved-symbols
print-foreign-modules


Foreign Language Interface User Guide and Reference Manual - 01 Dec 2021 19:34:58