• Keine Ergebnisse gefunden

Embedding SWI-Prolog in other applications

Im Dokument SWI-Prolog 5.0 (Seite 195-198)

6.6 The Foreign Include File

6.6.19 Embedding SWI-Prolog in other applications

With embedded Prolog we refer to the situation where the ‘main’ program is not the Prolog appli-cation. Prolog is sometimes embedded in C, C++, Java or other languages to provide logic based services in a larger application. Embedding loads the Prolog engine as a library to the external lan-guage. Prolog itself only provides for embedding in the C-language (compatible to C++). Embedding in Java is achieved using JPL using a C-glue between the Java and Prolog C-interfaces.

The most simple embedded program is below. The interface functionPL initialise()must be called before any of the other SWI-Prolog foreign language functions described in this chap-ter, except for PL initialise hook(), PL new atom() and PL register foreign(). PL initialise()interprets all the command-line arguments, except for the-t toplevelflag that is interpreted byPL toplevel().

int

main(int argc, char **argv) {

#ifdef READLINE /* Remove if you don’t want readline */

PL_initialise_hook(install_readline);

#endif

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

PL_halt(PL_toplevel() ? 0 : 1);

}

intPL initialise(int argc, char **argv)

Initialises the SWI-Prolog heap and stacks, restores the boot QLF file, loads the system and personal initialisation files, runs the at initialization/1 hooks and finally runs the -g goalhook.

Special consideration is required forargv[0]. On Unix, this argument passes the part of the commandline that is used to locate the executable. Prolog uses this to find the file holding the running executable. The Windows version uses this to find a module of the running executable.

If the specified module cannot be found, it tries the modulelibpl.dll, containing the Prolog runtime kernel. In all these cases, the resulting file is used for two purposes

• See whether a Prolog saved-state is appended to the file. If this is the case, this state will be loaded instead of the defaultboot.prcfile from the SWI-Prolog home directory. See alsoqsave program/[1,2]and section6.7.

• Find the Prolog home directory. This process is described in detail in section6.8.

PL initialise()returns 1 if all initialisation succeeded and 0 otherwise.6

In most cases, argc and argv will be passed from the main program. It is allowed to create your own argument vector, providedargv[0]is constructed according to the rules above. For example:

int

main(int argc, char **argv) { char *av[10];

int ac = 0;

av[ac++] = argv[0];

av[ac++] = "-x";

av[ac++] = "mystate";

av[ac] = NULL;

if ( !PL_initialise(ac, av) ) PL_halt(1);

...

}

Please note that the passed argument vector may be referred from Prolog at any time and should therefore be valid as long as the Prolog engine is used.

A good setup in Windows is to add SWI-Prolog’sbindirectory to yourPATHand either pass a module holding a saved-state, or"libpl.dll"asargv[0].

intPL is initialised(int *argc, char ***argv)

Test whether the Prolog engine is already initialised. ReturnsFALSEif Prolog is not initialised andTRUEotherwise. If the engine is initialised and argc is notNULL, the argument count used withPL initialise()is stored in argc. Same for the argument vector argv.

voidPL install readline()

Installs the GNU-readline line-editor. Embedded applications that do not use the Prolog toplevel should normally delete this line, shrinking the Prolog kernel significantly. Note that the Win-dows version does not use GNU readline.

intPL toplevel()

Runs the goal of the-t toplevelswitch (defaultprolog/0) and returns 1 if successful, 0 otherwise.

6BUG: Various fatal errors may cause PL initialise to callPL halt(1), preventing it from returning at all.

6.6. THE FOREIGN INCLUDE FILE 197

voidPL cleanup(int status)

This function performs the reverse of PL initialise(). It runs thePL on halt()and at halt/1 handlers, closes all streams (except for the ‘standard I/O’ streams which are flushed only), deallocates all memory and restores all signal handlers. The status argument is passed to the various termination hooks and indicates the exit-status.

This function allows deleting and restarting the Prolog system in the same process. Use it with care, as PL initialise() is a costly function. Unix users should consider using exec() (available as part of the clib package,).

voidPL halt(int status)

Cleanup the Prolog environment using PL cleanup()and calls exit() with the status argu-ment.

Threading, Signals and embedded Prolog

This section applies to Unix-based environments that have signals or multi-threading. The Windows version is compiled for multi-threading and Windows lacks proper signals.

We can distinguish two classes of embedded executables. There are small C/C++-programs that act as an interfacing layer around Prolog. Most of these programs can be replaced using the normal Prolog executable extended with a dynamically loaded foreign extension and in most cases this is the preferred route. In other cases, Prolog is embedded in a complex application that—like Prolog—

wants to control the process environment. A good example is Java. Embedding Prolog is generally the only way to get these environments together in one process image. Java applications however are by nature multi-threaded and appear to do signal-handling (software interrupts).

To make Prolog operate smoothly in such environments it must be told not to alter the process environment. This is partly done at build-time and partly execution time. At build-time we must specify the use of software stack-overflow rather then the default hardware checks. This is done using sh configure --disable-segv-handling

The resulting Prolog executable is about 10% slower than the normal executable, but behaves much more reliable in complicated embedded situations. In addition, as the process no longer handles segmentation violations, debugging foreign code linked to it is much easier.

At runtime, it is adviced to pass the flag-nosignals, which inhibits all default signal handling.

This has a few consequences though:

• It is no longer possible to break into the tracer using an interrupt signal (Control-C).

• SIGPIPEis normally set to be ignored. Prolog uses return-codes to diagnose broken pipes.

Depending on the situation one should take appropriate action if Prolog streams are connected to pipes.

• Fatal errors normally cause Prolog to call PL cleanup() and exit(). It is adviced to call PL cleanup()as part of the exit-procedure of your application.

Im Dokument SWI-Prolog 5.0 (Seite 195-198)