9.4 Using the library shlib for .DLL and .so files

This section discusses the functionality of the (autoload) library shlib.pl, providing an interface to shared libraries. This library can only be used if the prolog-flag open_shared_object is enabled.

load_foreign_library(+Lib, +Entry)
Search for the given foreign library and link it to the current SWI-Prolog instance. The library may be specified with or without the extension. First, absolute_file_name/3 is used to locate the file. If this succeeds, the full path is passed to the low-level function to open the library. Otherwise, the plain library name is passed, exploiting the operating-system defined search mechanism for the shared library. The file_search_path/2 alias mechanism defines the alias foreign, which refers to the directories <plhome>/lib/<arch> and <plhome>/lib, in this order.

If the library can be loaded, the function called Entry will be called without arguments. The return value of the function is ignored.

The Entry function will normally call PL_register_foreign() to declare functions in the library as foreign predicates.

load_foreign_library(+Lib)
Equivalent to load_foreign_library/2. For the entry-point, this function first identifies the `base-name' of the library, which is defined to be the file-name with path nor extension. It will then try the entry-point install-<base>. On failure it will try to function install(). Otherwise no install function will be called.
unload_foreign_library(+Lib)
If the foreign library defines the function uninstall_<base>() or uninstall(), this function will be called without arguments and its return value is ignored. Next, abolish/2 is used to remove all known foreign predicates defined in the library. Finally the library itself is detached from the process.
current_foreign_library(-Lib, -Predicates)
Query the currently loaded foreign libraries and their predicates. Predicates is a list with elements of the form Module:Head, indicating the predicates installed with PL_register_foreign() when the entry-point of the library was called.

Figure 7 connects a Windows message-box using a foreign function. This example was tested using Windows NT and Microsoft Visual C++ 2.0.

#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()
{ PL_register_foreign("say_hello", 1, pl_say_hello, 0);
}
Figure 7 : MessageBox() example in Windows NT

9.4.1 Static Linking

Below is an outline of the files structure required for statically linking SWI-Prolog with foreign extensions. \ldots/pl refers to the SWI-Prolog home directory (see current_prolog_flag/2). <arch> refers to the architecture identifier that may be obtained using current_prolog_flag/2.

.../pl/runtime/<arch>/libpl.a SWI-Library
.../pl/include/SWI-Prolog.h Include file
.../pl/include/SWI-Stream.h Stream I/O include file
.../pl/include/SWI-Exports Export declarations (AIX only)
.../pl/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 \ldots/pl/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_install_readline();                /* delete if not required */

  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 using the plld utility described in secrefplld. 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.