- Documentation
- Reference manual
- Foreign Language Interface
- The Foreign Include File
- Argument Passing and Control
- Atoms and functors
- Analysing Terms via the Foreign Interface
- Constructing Terms
- Unifying data
- Convenient functions to generate Prolog exceptions
- Foreign language wrapper support functions
- Serializing and deserializing Prolog terms
- BLOBS: Using atoms to store arbitrary binary data
- Exchanging GMP numbers
- Calling Prolog from C
- Discarding Data
- String buffering
- Foreign Code and Modules
- Prolog exceptions in foreign code
- Catching Signals (Software Interrupts)
- Miscellaneous
- Errors and warnings
- Environment Control from Foreign Code
- Querying Prolog
- Registering Foreign Predicates
- Foreign Code Hooks
- Storing foreign data
- Embedding SWI-Prolog in other applications
- The Foreign Include File
- Foreign Language Interface
- Packages
- Reference manual
NULL
. During normal
execution it may return the content of a newly allocated blob that
reuses the released handle.
PL_BLOB_NOCOPY
flag set and a release() function. It causes
the release() function to be called, after which the data and size are
set to 0. The related atom remains existent and accessing it as a blob
returns NULL
for the data and 0 for the size.
12.4.10.3 Considerations for non-C code
The blob API assumes that Prolog will take care of memory management, using the release(c)allback to handle any cleanup.
Other programming languages have their own memory management, which might not fit nicely with the Prolog memory management. For more details on blobs written with C++, see C++ interface to SWI-Prolog (Version 2).
12.4.11 Exchanging GMP numbers
If SWI-Prolog is linked with the GNU Multiple Precision Arithmetic
Library (GMP, used by default), the foreign interface provides functions
for exchanging numeric values to GMP types. To access these functions
the header <gmp.h>
must be included before
<SWI-Prolog.h>
. Foreign code using GMP linked to
SWI-Prolog asks for some considerations.
- SWI-Prolog normally rebinds the GMP allocation functions using
mp_set_memory_functions(). This means SWI-Prolog must be initialised
before the foreign code touches any GMP function. You can call
PL_action(PL_GMP_SET_ALLOC_FUNCTIONS, TRUE)
to force Prolog's GMP initialization without doing the rest of the Prolog initialization. If you do not want Prolog rebinding the GMP allocation, callPL_action(PL_GMP_SET_ALLOC_FUNCTIONS, FALSE)
before initializing Prolog. - On Windows, each DLL has its own memory pool. To make exchange of GMP numbers between Prolog and foreign code possible you must either let Prolog rebind the allocation functions (default) or you must recompile SWI-Prolog to link to a DLL version of the GMP library.
Here is an example exploiting the function mpz_nextprime():
#include <gmp.h> #include <SWI-Prolog.h> static foreign_t next_prime(term_t n, term_t prime) { mpz_t mpz; int rc; mpz_init(mpz); if ( PL_get_mpz(n, mpz) ) { mpz_nextprime(mpz, mpz); rc = PL_unify_mpz(prime, mpz); } else rc = FALSE; mpz_clear(mpz); return rc; } install_t install() { PL_register_foreign("next_prime", 2, next_prime, 0); }
- int PL_get_mpz(term_t t, mpz_t mpz)
- If t represents an integer, mpz is filled with the
value and the function returns
TRUE
. Otherwise mpz is untouched and the function returnsFALSE
. Note that mpz must have been initialised before calling this function and must be cleared using mpz_clear() to reclaim any storage associated with it. - int PL_get_mpq(term_t t, mpq_t mpq)
- If t is an integer or rational number (term
rdiv/2
), mpq is filled with the normalised rational number and the function returnsTRUE
. Otherwise mpq is untouched and the function returnsFALSE
. Note that mpq must have been initialised before calling this function and must be cleared using mpq_clear() to reclaim any storage associated with it. - int PL_unify_mpz(term_t t, mpz_t mpz)
- Unify t with the integer value represented by mpz
and return
TRUE
on success. The mpz argument is not changed. - int PL_unify_mpq(term_t t, mpq_t mpq)
- Unify t with a rational number represented by mpq
and return
TRUE
on success. Note that t is unified with an integer if the denominator is 1. The mpq argument is not changed.
12.4.12 Calling Prolog from C
The Prolog engine can be called from C. There are two interfaces for this. For the first, a term is created that could be used as an argument to call/1, and then PL_call() is used to call Prolog. This system is simple, but does not allow to inspect the different answers to a non-deterministic goal and is relatively slow as the runtime system needs to find the predicate. The other interface is based on PL_open_query(), PL_next_solution(), and PL_cut_query() or PL_close_query(). This mechanism is more powerful, but also more complicated to use.
12.4.12.1 Predicate references
This section discusses the functions used to communicate about
predicates. Though a Prolog predicate may be defined or not, redefined,
etc., a Prolog predicate has a handle that is neither destroyed nor
moved. This handle is known by the type predicate_t
.
- predicate_t PL_pred(functor_t f, module_t m)
- Return a handle to a predicate for the specified name/arity in the given
module. If the module argument m is
NULL
, the current context module is used. If the target predicate does not exist a handle to a new undefined predicate is returned. The predicate may fail, returning(predicate_t)0
after setting a resource exception, if the target module has a limit on theprogram_space
, see set_module/1. Currently aborts the process with a fatal error when out of memory. Future versions may raise a resource exception and return(predicate_t)0
. - predicate_t PL_predicate(const char *name, int arity, const char* module)
- Same as PL_pred(),
but provides a more convenient interface to the C programmer. If the
module argument module is
NULL
, the current context module is used. Thepredicate_t
handle may be stored as global data and reused for future queries225PL_predicate() involves 5 hash lookups (two to get the atoms, one to get the module, one to get the functor and the final one to get the predicate associated with the functor in the module) as illustrated below.static predicate_t p = 0; ... if ( !p ) p = PL_predicate("is_a", 2, "database");
Note that PL_cleanup() invalidates the predicate handle. Foreign libraries that use the above mechanism must implement the module uninstall() function to clear the
predicate_t
global variable. - int PL_predicate_info(predicate_t p, atom_t *n, size_t *a, module_t *m)
- Return information on the predicate p. The name is stored
over
n, the arity over a, while m receives
the definition module. Note that the latter need not be the same as
specified with
PL_predicate().
If the predicate is imported into the module given to
PL_predicate(),
this function will return the module where the predicate is defined. Any
of the arguments n, a and m can be
NULL
. Currently always returnsTRUE
.
12.4.12.2 Initiating a query from C
This section discusses the functions for creating and manipulating queries from C. Note that a foreign context can have at most one active query. This implies that it is allowed to make strictly nested calls between C and Prolog (Prolog calls C, calls Prolog, calls C, etc.), but it is not allowed to open multiple queries and start generating solutions for each of them by calling PL_next_solution(). Be sure to call PL_cut_query() or PL_close_query() on any query you opened before opening the next or returning control back to Prolog. Failure to do so results in "undefined behavior" (typically, a crash).
- qid_t PL_open_query(module_t ctx, int flags, predicate_t p, term_t +t0)
-
Opens a query and returns an identifier for it. ctx is the context module of the goal. When
NULL
, the context module of the calling context will be used, oruser
if there is no calling context (as may happen in embedded systems). Note that the context module only matters for meta-predicates. See meta_predicate/1, context_module/1 and module_transparent/1. The term reference t0 is the first of a vector of term references as returned by PL_new_term_refs(n). Raise a resource exception and returns(qid_t)0
on failure.Every use of PL_open_query() must have a corresponding call to PL_cut_query() or PL_close_query() before the foreign predicate returns either
TRUE
orFALSE
.The flags arguments provides some additional options concerning debugging and exception handling. It is a bitwise or of the following values below. Note that exception propagation is defined by the flags
PL_Q_NORMAL
,PL_Q_CATCH_EXCEPTION
andPL_Q_PASS_EXCEPTION
. Exactly one of these flags must be specified (if none of them is specified, the behavior is as ifPL_Q_NODEBUG
is specified)..PL_Q_NORMAL
- Normal operation. It is named "normal" because it makes a call to Prolog behave as it did before exceptions were implemented, i.e., an error (now uncaught exception) triggers the debugger. See also the Prolog flag debug_on_error. This mode is still useful when calling Prolog from C if the C code is not willing to handle exceptions.
PL_Q_NODEBUG
- Switch off the debugger while executing the goal. This option is used by
many calls to hook-predicates to avoid tracing the hooks. An example is print/1
calling portray/1
from foreign code. This is the default if flags is
0
. PL_Q_CATCH_EXCEPTION
- If an exception is raised while executing the goal, make it available by
calling
PL_exception(qid)
, whereqid
is theqid_t
returned by PL_open_query(). The exception is implicitly cleared from the environment when the query is closed and the exception term returned fromPL_exception(qid)
becomes invalid. UsePL_Q_PASS_EXCEPTION
if you wish to propagate the exception. PL_Q_PASS_EXCEPTION
- As
PL_Q_CATCH_EXCEPTION
, making the exception on the inner environment available usingPL_exception(0)
in the parent environment. If PL_next_solution() returnsFALSE
, you must call PL_cut_query() or PL_close_query(). After that you may verify whether failure was due to logical failure of the called predicate or an exception by callingPL_exception(0)
. If the predicate failed due to an exception you should return withFALSE
from the foreign predicate or call PL_clear_exception() to clear it. If you wish to process the exception in C, it is advised to usePL_Q_CATCH_EXCEPTION
instead, but only if you have no need to raise an exception or re-raise the caught exception.Note that
PL_Q_PASS_EXCEPTION
is used by the debugger to decide whether the exception is caught. If there is no matching catch/3 call in the current query and the query was started usingPL_Q_PASS_EXCEPTION
the debugger searches the parent queries until it either finds a matching catch/3, a query withPL_Q_CATCH_EXCEPTION
(in which case it considers the exception handled by C) or the top of the query stack (in which case it considers the exception uncaught). Uncaught exceptions use thelibrary(library(prolog_stack))
to add a backtrace to the exception and start the debugger as soon as possible if the Prolog flag debug_on_error istrue
. PL_Q_ALLOW_YIELD
- Support the
I_YIELD
instruction for engine-based coroutining. See $engine_yield/2 inboot/init.pl
for details. PL_Q_EXT_STATUS
- Make PL_next_solution()
return extended status. Instead of only
TRUE
orFALSE
extended status as illustrated in the following table:Extended Normal PL_S_EXCEPTION FALSE Exception available through PL_exception() PL_S_FALSE FALSE Query failed PL_S_TRUE TRUE Query succeeded with choicepoint PL_S_LAST TRUE Query succeeded without choicepoint
PL_open_query() can return the query identifier
0
if there is not enough space on the environment stack (and makes the exception available throughPL_exception(0)
). This function succeeds, even if the referenced predicate is not defined. In this case, running the query using PL_next_solution() may return an existence_error. See PL_exception().The example below opens a query to the predicate is_a/2 to find the ancestor of‘me'. The reference to the predicate is valid for the duration of the process or until PL_cleanup() is called (see PL_predicate() for details) and may be cached by the client.
char * ancestor(const char *me) { term_t a0 = PL_new_term_refs(2); static predicate_t p; if ( !p ) p = PL_predicate("is_a", 2, "database"); PL_put_atom_chars(a0, me); PL_open_query(NULL, PL_Q_PASS_EXCEPTION, p, a0); ... }
- int PL_next_solution(qid_t qid)
- Generate the first (next) solution for the given query. The return value
is
TRUE
if a solution was found, orFALSE
to indicate the query could not be proven. This function may be called repeatedly until it fails to generate all solutions to the query. The return valuePL_S_NOT_INNER
is returned if qid is not the innermost query.If the