next up previous index
Next: User Initialisation Up: External Language Interface Previous: Argument Mapping

Adding Externals

To create an external predicate, the source file with its definition has to be compiled yielding an object file, the object file must be loaded into the ECLiPSe system, and the function must then be explicitly linked to a Prolog predicate definition. The source file with the external predicate definition must always include the line

#include "external.h"
which contains the macros for Prolog interface. The location of the file depends on the particular installation, normally it is in the include subdirectory of the ECLiPSe

library directory. If the ECLiPSe include files are in /usr/local/eclipse/include, use

cc -c -I/usr/local/eclipse/include file.c
to compile the source file and create the object file file.o.  

A C object file may be loaded dynamically into the ECLiPSe system by the use of the predicate load/1gif. The goal

load(File)
will   load the object file File in this manner. File is a file specification of a file in the machine environment, given as either an atom or a string. It may also contain options to the dynamic loader. For example to load the file functions.o specifying use of the mathematical library:
load("functions.o -lm")
Note that when a debugger like dbx   is to be used on the external predicate, the flag
"-lg"
must be specified in load/1, and dbx has to be started only after loading has been finished using the process number pid of the ECLiPSe process. In this case it is also necessary to specify the file with the new symbol table, which is always of the form /tmp/eclipse.pid.N, e.g.  
dbx /tmp/eclipse.3562.0 3562
where N starts with zero and is incremented for each dynamic loading executed in this session. If set, the environment variable ECLIPSELOADER specifies the loader   to be used to dynamically load the object files. The environment variable ECLIPSETMP may specify the directory   to be used instead of /tmp to store the symbol tables.

On newer UNIX platforms with shared library support, the dynamic loading feature is built on top of them. On these systems, the C source has to be compiled into a shared object, e.g. using

cc -G -c -I/usr/local/eclipse/include -o file.so file.c
and then be loaded with
load("functions.so")
In this case, the load/1 built-in does not accept nor need any options.

The compiler flags that are necessary for producing shared object files vary for different machines and C compilers. As a guideline, refer to the Makefile in the corresponding machine-specific subdirectory of the boot-subdirectory of the ECLiPSe installation directory.

On UNIX systems that do not support dynamic loading of object files it is necessary to link the object file with the supplied file sepia.o, which is normally in the boot subdirectory of the installed ECLiPSe system. The result of the loading is then an executable program which contains the ECLiPSe system together with the external predicates. This is achieved e.g. by the command

cc -I/usr/local/eclipse/include ext_file.c
                    /usr/local/eclipse/boot/sepia.o -o myeclipse
or (which is easier) by modifying the Makefile in the boot subdirectory of the ECLiPSe installation directory which will also boot the system and create a user executable binary. When booting, the environment variable ECLIPSEDIR has to be set   to the ECLiPSe installation directory in the same way as when installing ECLiPSe from the delivery tape.

Once the object file containing the C function has been loaded, one of the predicates external/2 and b_external/2 (backtracking external) is used       to link it with a predicate definition. If the function implements a deterministic procedure, the predicate external/2 is used. If the function implements a non deterministic procedure, the predicate b_external/2 is used. Both take the same form of arguments. A call to external/2 takes the form

external(Name/Arity, CName)
Name is the name of the Prolog predicate which is to be associated with the function. Arity is the arity of this predicate; this will be numerically half of the arity of the C function, for the reason explained earlier. CName is the name of the C function. The system will prefix the underscore character to this name in order to find the name of the object code function loaded by load/1. Thus to link the C function p_long which is held in the object file bam.o to a non deterministic predicate long/2 we use
load("bam.o"), b_external(long/2, "p_long")

Since deterministic externals use a different calling convention than Prolog predicates, it is necessary to inform the compiler before it compiles the first call to a deterministic external. Otherwise the system will issue an "inconsistent redefinition" error. Usually this is no problem since the external/2 declaration is given initially. If this is not wanted, it is at least necessary to submit the appropriate forward declaration ( external/1 or b_external/1) before the first occurrence of the predicate as a subgoal. Which calling convention the system assumes for a given predicate can be checked by looking at the call_type flag (using get_flag/3 or pred/1). The possible values are prolog, external and b_external.

On all machines the file sepia.o is supplied in the boot subdirectory of the ECLiPSe installation directory, and this file can be used to obtain an executable ECLiPSe with statically linked     external files. To link the executable ECLiPSe , the file libsepia.a is also necessary. To make a ECLiPSe with KEGI, it is also necessary to link one of the files tkegi.o for an ECLiPSe

that works only with kegitool or xkegi.o for the X11 version of KEGI. All these files are also available in the boot directory. Thus, to make a ECLiPSe version with external file ext_file.c and X11 KEGI, use the command

cc -I/usr/local/eclipse/include ext_file.c \
    /usr/local/eclipse/boot/sepia.o /usr/local/eclipse/boot/xkegi.o \
    /usr/local/eclipse/boot/libsepia.a -o myeclipse
Such an executable myeclipse is not booted, and so when it is started, it will try to read boot files from the boot directory. To start an unbooted ECLiPSe , the environment variable ECLIPSEDIR   must be set to the ECLiPSe installation directory, usually /usr/local/eclipse. Normally, after booting, a saved state is produced either with the -s option or with the save/1 or save_program/1 predicate.





next up previous index
Next: User Initialisation Up: External Language Interface Previous: Argument Mapping



Micha Meier
Mon Mar 4 12:11:45 MET 1996