SWI-Prolog 8.2.4 Reference Manual: Section 12.2

## 12.2 Linking Foreign Modules

Foreign modules may be linked to Prolog in two ways. Using static linking, the extensions, a (short) file defining main() which attaches the extension calls to Prolog, and the SWI-Prolog kernel distributed as a C library, are linked together to form a new executable. Using dynamic linking, the extensions are linked to a shared library (`.so` file on most Unix systems) or dynamic link library (`.DLL` file on Microsoft platforms) and loaded into the running Prolog process.184The system also contains code to load `.o` files directly for some operating systems, notably Unix systems using the BSD `a.out` executable format. As the number of Unix platforms supporting this quickly gets smaller and this interface is difficult to port and slow, it is no longer described in this manual. The best alternative would be to use the dld package on machines that do not have shared libraries.

### 12.2.1 What linking is provided?

The static linking schema can be used on all versions of SWI-Prolog. Whether or not dynamic linking is supported can be deduced from the Prolog flag open_shared_object (see current_prolog_flag/2). If this Prolog flag yields `true`, open_shared_object/2 and related predicates are defined. See section 12.2.3 for a suitable high-level interface to these predicates.

### 12.2.2 What kind of loading should I be using?

All described approaches have their advantages and disadvantages. Static linking is portable and allows for debugging on all platforms. It is relatively cumbersome and the libraries you need to pass to the linker may vary from system to system, though the utility program swipl-ld described in section 12.5 often hides these problems from the user.

Loading shared objects (DLL files on Windows) provides sharing and protection and is generally the best choice. If a saved state is created using qsave_program/[1,2], an initialization/1 directive may be used to load the appropriate library at startup.

Note that the definition of the foreign predicates is the same, regardless of the linking type used.

### 12.2.3 library(shlib): Utility library for loading foreign objects (DLLs, shared objects)

This section discusses the functionality of the (autoload) `library(shlib)`, providing an interface to manage shared libraries. We describe the procedure for using a foreign resource (DLL in Windows and shared object in Unix) called `mylib`.

First, one must assemble the resource and make it compatible to SWI-Prolog. The details for this vary between platforms. The swipl-`ld(1)` utility can be used to deal with this in a portable manner. The typical commandline is:

    swipl-ld -o mylib file.{c,o,cc,C} ...

Make sure that one of the files provides a global function `install_mylib()` that initialises the module using calls to PL_register_foreign(). Here is a simple example file mylib.c, which creates a Windows MessageBox:

    #include <windows.h>
    #include <SWI-Prolog.h>

    static foreign_t
    pl_say_hello(term_t to)
    { char *a;

      if ( PL_get_atom_chars(to, &a) )
      { MessageBox(NULL, a, "DLL test", MB_OK|MB_TASKMODAL);

        PL_succeed;
      }

      PL_fail;
    }

    install_t
    install_mylib()
    { PL_register_foreign("say_hello", 1, pl_say_hello, 0);
    }

Now write a file `mylib.pl`:

    :- module(mylib, [ say_hello/1 ]).
    :- use_foreign_library(foreign(mylib)).

The file `mylib.pl` can be loaded as a normal Prolog file and provides the predicate defined in C.

[det]use_foreign_library(+FileSpec)
[det]use_foreign_library(+FileSpec, +Entry:atom)
  Load and install a foreign library as load_foreign_library/1,2 and register the installation using initialization/2 with the option `now`. This is similar to using:

      :- initialization(load_foreign_library(foreign(mylib))).

  but using the initialization/1 wrapper causes the library to be loaded after loading of the file in which it appears is completed, while use_foreign_library/1 loads the library immediately. I.e. the difference is only relevant if the remainder of the file uses functionality of the C-library.

  As of SWI-Prolog 8.1.22, use_foreign_library/1,2 is in provided as a built-in predicate that, if necessary, loads `library(shlib)`. This implies that these directives can be used without explicitly loading `library(shlib)` or relying on demand loading.

[semidet,multifile]qsave:compat_arch(Arch1, Arch2)
  User definable hook to establish if Arch1 is compatible with Arch2 when running a shared object. It is used in saved states produced by qsave_program/2 to determine which shared object to load at runtime.
  See also
    `foreign` option in qsave_program/2 for more information.
[det]load_foreign_library(:FileSpec)
[det]load_foreign_library(:FileSpec, +Entry:atom)
  Load a shared object or DLL. After loading the Entry function is called without arguments. The default entry function is composed from =install_=, followed by the file base-name. E.g., the load-call below calls the function `install_mylib()`. If the platform prefixes extern functions with =_=, this prefix is added before calling.

            ...
            load_foreign_library(foreign(mylib)),
            ...

  FileSpec | is a specification for absolute_file_name/3. If searching the file fails, the plain name is passed to the OS to try the default method of the OS for locating foreign objects. The default definition of file_search_path/2 searches <prolog home>/lib/<arch> on Unix and <prolog home>/bin on Windows.

  See also
    use_foreign_library/1,2 are intended for use in directives.
[det]unload_foreign_library(+FileSpec)
[det]unload_foreign_library(+FileSpec, +Exit:atom)
  Unload a shared object or DLL. After calling the Exit function, the shared object is removed from the process. The default exit function is composed from =uninstall_=, followed by the file base-name.
current_foreign_library(?File, ?Public)
  Query currently loaded shared libraries.
reload_foreign_libraries
  Reload all foreign libraries loaded (after restore of a state created using qsave_program/2.
[det]win_add_dll_directory(+AbsDir)
  Add AbsDir to the directories where dependent DLLs are searched on Windows systems.
  Errors
    `domain_error(operating_system, windows)` if the current OS is not Windows.

### 12.2.4 Low-level operations on shared libraries

The interface defined in this section allows the user to load shared libraries (`.so` files on most Unix systems, `.dll` files on Windows). This interface is portable to Windows as well as to Unix machines providing dlopen(2) (Solaris, Linux, FreeBSD, Irix and many more) or shl_open(2) (HP/UX). It is advised to use the predicates from section 12.2.3 in your application.

open_shared_object(+File, -Handle)
  File is the name of a shared object file (DLL in MS-Windows). This file is attached to the current process, and Handle is unified with a handle to the library. Equivalent to `open_shared_object(File, Handle, [])`. See also open_shared_object/3 and load_foreign_library/1.

  On errors, an exception `shared_object(Action, Message)` is raised. Message is the return value from dlerror().

open_shared_object(+File, -Handle, +Options)
  As open_shared_object/2, but allows for additional flags to be passed. Options is a list of atoms. `now` implies the symbols are resolved immediately rather than lazy (default). `global` implies symbols of the loaded object are visible while loading other shared objects (by default they are local). Note that these flags may not be supported by your operating system. Check the documentation of dlopen() or equivalent on your operating system. Unsupported flags are silently ignored.
close_shared_object(+Handle)
  Detach the shared object identified by Handle.
call_shared_object_function(+Handle, +Function)
  Call the named function in the loaded shared library. The function is called without arguments and the return value is ignored. Normally this function installs foreign language predicates using calls to PL_register_foreign().

### 12.2.5 Static Linking

Below is an outline of the file structure required for statically linking SWI-Prolog with foreign extensions. `.../swipl` refers to the SWI-Prolog home directory (see the Prolog flag home). `<arch>` refers to the architecture identifier that may be obtained using the Prolog flag arch.

`.../swipl/runtime/<arch>/libswipl.a` | SWI-Library
`.../swipl/include/SWI-Prolog.h` | Include file
`.../swipl/include/SWI-Stream.h` | Stream I/O include file
`.../swipl/include/SWI-Exports` | Export declarations (AIX only)
`.../swipl/include/stub.c` | Extension stub

The definition of the foreign predicates is the same as for dynamic linking. Unlike with dynamic linking, however, there is no initialisation function. Instead, the file `.../swipl/include/stub.c` may be copied to your project and modified to define the foreign extensions. Below is `stub.c`, modified to link the lowercase example described later in this chapter:

    #include <stdio.h>
    #include <SWI-Prolog.h>

    extern foreign_t pl_lowercase(term, term);

    PL_extension predicates[] =
    {
    /*{ "name",      arity,  function,      PL_FA_<flags> },*/

      { "lowercase", 2       pl_lowercase,  0 },
      { NULL,        0,      NULL,          0 } /* terminating line */
    };

    int
    main(int argc, char **argv)
    { PL_register_extensions(predicates);

      if ( !PL_initialise(argc, argv) )
        PL_halt(1);

      PL_halt(PL_toplevel() ? 0 : 1);
    }

Now, a new executable may be created by compiling this file and linking it to `libpl.a` from the runtime directory and the libraries required by both the extensions and the SWI-Prolog kernel. This may be done by hand, or by using the swipl-ld utility described in section 12.5. If the linking is performed by hand, the command line option --dump-runtime-variables (see section 2.4) can be used to obtain the required paths, libraries and linking options to link the new executable.