List of Examples
Everything described in the section will work verbatim on Win32
when using Cygwin or MinGW, except for one
thing - you will need to replace the run
extension in lisp.run
with the Win32 executable
extension exe
.
For historical reasons, all examples appear to assume UNIX and
use the run
file type (“extension”)
for the CLISP runtime.
This does not mean that they will not work on Win32.
External modules are a mechanism to add extensions (written in C, for example) to CLISP. Extending CLISP using an external module requires creating a module set and adding it to an existing linking set using clisp-link to prodice a new linking set which contains the extension.
A module is a piece of code (C or Lisp) which defines extra (non-core) Lisp objects, symbols and functions. Together with link.sh, which describes how to add the module to an existing CLISP, it comprises a module set.
More formally, module set is a directory containing:
In link.sh the module set directory is referred to
as $modulename/
.
A module name
must consist of the characters A
-Z
,
a
-z
, _
,
0
-9
.
The module name “clisp” is reserved.
A linking set is a collection of files (runtime, memory image &c) which allows performing two major tasks:
Running CLISP: to run a CLISP
contained in some linking set directory
, call
$
directory
/lisp.run-M
directory
/lispinit.mem
or
$
clisp-K
directory
The CLISP build directory contains three linking sets in directories boot, base, and full, and a CLISP installation normally contains two linking sets: base, and full
More formally, a linking set is a directory containing at least these files:
lisp.run
lispinit.mem
modules.h
modules.o
makevars
some /bin/sh commands, setting the variables
| the C compiler |
| flags for the C compiler, when preprocessing or compiling |
| flags for the C compiler, when compiling or linking |
| flags for the C compiler, when linking |
| libraries to use when linking (either present in the linking set directory, or system-wide) |
| additional X Window System libraries to use |
| the ranlib command |
| the list of files needed when linking |
FILES
makevars
Use clisp-link to create and install module sets and add them to linking sets.
See also Section 32.2.6, “Example”.
The following variables should be defined in link.sh.
NEW_FILES
NEW_LIBS
lisp.run
belonging to a new linking set.
NEW_MODULES
#P".c"
file in the
module set defines a module of its own. The module name is usually
derived from the file name.TO_LOAD
lispinit.mem
belonging to a new linking set.
TO_PRELOAD
(optional)the space-separated list of Lisp files to load
into an intermediate lispinit.mem
file, before building the lispinit.mem
belonging to a new linking set.
This variable is usually used to create
(or unlock) the Lisp PACKAGE
s which
must be present when the new #P".c"
files are initialized.
E.g., the FFI:DEF-CALL-IN
functions must reside in already defined packages;
see Example 32.7, “Calling Lisp from C”. You can find a live example in
modules/syscalls/preload.lisp
and modules/syscalls/link.sh.in
.
If you are unlocking a package, you must also
DELETE
it from CUSTOM:*SYSTEM-PACKAGE-LIST*
(see Section 31.2, “Saving an Image”) here
and re-add it to CUSTOM:*SYSTEM-PACKAGE-LIST*
in one of the TO_LOAD
files.
See, e.g., modules/i18n/preload.lisp
and modules/i18n/link.sh.in
.
Each module has two initialization functions:
module__name
__init_function_1
(struct module_t* module)called only once when CLISP
discovers while loading a memory image that there is a module present
in the executable (lisp.run
) which was not present at the time the
image was saved. It can be used to create Lisp objects,
e.g. functions or keywords, and is indeed used for that purpose by
modprep.
You do not have to define this function yourself; modprep and “FFI” will do that for you.
If you use “FFI”, (
will add code to this function.FFI:C-LINES
:init-once ...)
The PACKAGE
s must already exist and be unlocked,
cf. TO_PRELOAD
.
If you are using modprep and defining your
own “init-once” function, it must call the
module__
function!name
__init_function_1__modprep
module__name
__init_function_2
(struct module_t* module)called every time CLISP starts.
It can be used to bind names to foreign addresses, since the address
will be different in each invocation of CLISP, and is indeed used
for that purpose by “FFI” (e.g., by FFI:DEF-CALL-OUT
).
It can also be used to set parameters of the libraries to which the
module interfaces, e.g., the pcre
module
sets pcre_malloc
and pcre_free
.
You do not have to define this function yourself; modprep and “FFI” will do that for you.
If you use “FFI”, (
will add code to this function.FFI:C-LINES
:init-always ...)
name
is the module name.
See also Section 31.1, “Customizing CLISP Process Initialization and Termination”.
Each module has a finalization function
module__name
__fini_function
(struct module_t* module)called before exiting CLISP.
You do not have to define this function yourself; modprep and “FFI” will do that for you.
If you use “FFI”, (
will
add code to this function.FFI:C-LINES
:fini ...)
name
is the module name.
See also Section 31.1, “Customizing CLISP Process Initialization and Termination”.
EXT:MODULE-INFO
Function (
allows one to inquire
about what modules are available in the currently running image.
When called without arguments, it returns the list of module names,
starting with “clisp”. When EXT:MODULE-INFO
&OPTIONAL
name
verbose
)name
is supplied and
names a module, 3 values are returned - name
,
subr-count
,
object-count
.
When verbose
is non-NIL
, the full list of
module lisp function names written in C (Subrs) and
the full list of internal lisp objects available in C code
are additionally returned for the total of 5 values.
When name
is :FFI
, returns the list of
shared libraries opened using :LIBRARY
.
When verbose
is non-NIL
, return the
association list of DLL names and all foreign objects associated with it.
--without-dynamic-modules
.Dynamic loading does not work on all operating systems
(dlopen
or equivalent is required).
You will probably never need to call the function SYS::DYNLOAD-MODULES
explicitly (this is why it is in “SYSTEM” and not in “EXT”).
You should install your module with
$
clisp-linkinstall
name
and load it with (
REQUIRE
name
).
Function (
loads a shared object file or library containing a number of named
external CLISP modules.
SYS::DYNLOAD-MODULES
filename
({name
}+))
This facility cannot be used to
access arbitrary shared libraries. To do that, use the :LIBRARY
argument to FFI:DEF-CALL-OUT
and FFI:DEF-C-VAR
instead.
External modules for CLISP are shared objects
(dynamic libraries) that contain the
module__
variable, among others.
This serves to register external functions which operate on Lisp-level
structures with CLISP.name
__subr_tab
To use dlopen
with modules, you should add
-fPIC
to the module's compilation options.
Something like
$
cc -shared -oname
.soname
.o
may be needed to produce the shared object file.
List of Examples
Example 32.1. Create a module set with GNU libc bindings
To link in the “FFI” bindings for the GNU/Linux operating system, the following steps are needed. (Step 1 and step 2 need not be executed in this order.)
Create a new module set
$
clisp-link create linux /pathname
/bindings/linux.c
Modify the newly created
linux/link.sh
add -lm
to the libraries
replace
NEW_LIBS="$file_list"
with
NEW_LIBS="$file_list -lm"
load linux.fas
before saving the
memory image
replace
TO_LOAD=''
with
TO_LOAD='/pathname
/bindings/linux.fas'
Compile linux.lisp
, creating
linux.c
$
clisp-c
/pathname
/bindings/linux.lisp
Create a new linking set
$
clisp-link add base base+linux linux
Run and try it
$
base+linux/lisp.run-M
base+linux/lispinit.mem-x
'(linux:stat "/tmp")'
There are some tools to facilitate easy module writing.
If your module is written in C, you can pre-process your
sources with modprep in the CLISP distribution and define lisp
functions with the DEFUN
macro:
DEFUN(MY-PACKAGE:MY-FUNCTION-NAME, arg1 arg2 &KEY
FOO BAR) {
if (!boundp(STACK_0)) STACK_0 = fixnum(0); /* BAR */
if (!boundp(STACK_1)) STACK_1 = fixnum(1); /* FOO */
pushSTACK(`MY-PACKAGE::SOME-SYMBOL`); /* create a symbol in the package */
pushSTACK(`#(:THIS :IS :A :VECTOR)`); /* some vector, created once */
pushSTACK(``MY-PACKAGE::MY-FUNCTION-NAME``); /* double `` means FUNCTION */
VALUES1(listof(7)); /* cons up a new list and clean up the STACK */
}
Then (MY-PACKAGE:MY-FUNCTION-NAME 'A 12 :FOO T)
will
return (A 12 T 0 MY-PACKAGE::SOME-SYMBOL #(:THIS
:IS :A :VECTOR) #<ADD-ON-SYSTEM-FUNCTION
MY-PACKAGE:MY-FUNCTION-NAME>)
(assuming you EXPORT
ed MY-FUNCTION-NAME
from
“MY-PACKAGE”).
Note that the arguments are passed on the STACK
(last argument
being the top) which has to be cleaned up before exit.
Another useful macros are:
See modules/syscalls/calls.c
and other included modules for more examples and file modprep for full
documentation.
If you manipulate Lisp objects, you need to watch out for GC-safety.
If your module is written in C, you will probably want
to #include "clisp.h"
to access CLISP objects.
You will certainly need to read "clisp.h"
and some code in
included modules, but here are
some important hints that you will need to keep in mind:
allocate_*()
functions) - but not C
allocations (malloc
et al) - and must be saved on the STACK
using cpp
macros pushSTACK()
, popSTACK()
and skipSTACK()
.TheFoo()
macro, e.g.,
TheCons(my_cons)->Car
, but first check the
type with consp()
.STACK
, as illustrated
in the above example.Wrap your system calls in
begin_system_call()
/end_system_call()
pairs. These macros, defined in "clisp.h"
, save and restore
registers used by CLISP which could be clobbered by a system call.
If the system call could block (e.g., read
)
you need to use begin_blocking_system_call()
and
end_blocking_system_call()
instead. This will
allow other threads to run while yours is inside the system call.
This means that garbage-collection could happen while you are inside this system
call and, thus, that all objects of type object are
invalidated by the call. See also Section 35.5, “The burden of garbage-collection upon the rest of CLISP” and
Section 35.8, “Garbage Collection and Multithreading”.
If your module uses “FFI” to interface to a C library,
you might want to make your module package :CASE-SENSITIVE
and use
exporting.lisp
in the CLISP distribution to make “FFI” forms
and DEFUN
, DEFMACRO
at al export the symbols they define.
See modules/netica/
,
modules/matlab/
and
modules/bindings/
for examples.
When deciding how to write a module: whether to use “FFI” or to stick with C and modprep, one has to take into account several issues:
“FFI” has a noticeable overhead:
compare RAWSOCK:HTONS
(defined
in modules/rawsock/rawsock.c
)
with
(FFI:DEF-CALL-OUT
htons (:NAME
"htons") (:LIBRARY
:default) (:ARGUMENTS
(s ffi:short)) (:RETURN-TYPE
ffi:short) (:LANGUAGE
:stdc))
and observe that RAWSOCK:HTONS
is
almost 3 times as fast (this really does compare the “FFI”
overhead to the normal lisp function call because
htons
is computationally trivial).
This difference will matter only if you call a simple function very
many times, in which case it would make sense to put the loop itself
into C.
htonl
et al in
modules/rawsock/rawsock.c
.
:LIBRARY
argument to FFI:DEF-CALL-OUT
and
FFI:DEF-C-VAR
, you do not need to leave your CLISP session to try
out your code. This is a huge advantage for rapid prototyping.
&OPTIONAL
and
&KEY
word arguments etc), you will need to write wrappers to your
FFI:FOREIGN-FUNCTION
s, while in C you can do that directly.
The same goes for “polymorphism”: accepting different
argument types (like, e.g., POSIX:RESOLVE-HOST-IPADDR
does) would require a lisp
wrapper for FFI:FOREIGN-FUNCTION
s.
If you are comfortable with C, you might find the CLISP C module facilities (e.g., modprep) very easy to use.
CLISP “FFI”, on the other hand, is quite high-level, so, if you are more comfortable with high-level languages, you might find it easier to write “FFI” forms than C code.
FFI:DEF-CALL-OUT
form does not describe the C function's
expectations with respect to the arguments and return values
(including ALLOCATION
), you will probably learn that the hard way.
If the module is written in C, all the opportunities to shoot
oneself in the foot (and other body parts) are wide open
(although well known to most C users).
However, with C, one has to watch
for GC-safety too.
Some Linux distributions offer separate library (containing shared libraries only) and development (containing static libraries and C headers) packages.
:LIBRARY
(and avoiding FFI:DEF-C-CONST
), the
development package is not needed.
It is not a good idea to have
both foo.lisp
and foo.c
files in a module, because if you ever add an “FFI” form to the
former, COMPILE-FILE
will
overwrite the latter.
A few modules come with the source distribution of CLISP (but are not necessarily built in a particular binary distribution).
To use modules, read unix/INSTALL
and build CLISP in a directory build-dir
with,
e.g.,
$
./configure --with-module=pcre --with-module=clx/new-clx --cbc build-dir
then run it with
$
./build-dir/clisp-K
full
This will create a base linking set with modules
i18n
, regexp
and syscalls
(and maybe readline
);
and a full linking set with modules clx/new-clx
and pcre
in addition
to the 3 (or 4) base modules.
Here we list the included modules by their general theme. See Chapter 33, Extensions Implemented as Modules for individual module documentation.
The default build process includes the following modules in both base and full linking sets:
i18n
regexp
syscalls
readline
(only when both GNU readline and
“FFI” are available)The composition of the full linking set depends on the platform and on the vendor preferences.
gdbm
berkeley-db
dirkey
postgresql
oracle
libsvm
pari
matlab
netica
pcre
zlib
VECTOR
s using ZLIB.
Call Xlib functions from CLISP. Two implementations are supplied:
clx/mit-clx
, from MIT
https://www.x.org/archive/unsupported/lib/CLX/clx/new-clx
, by faster, with additional features, but not quite complete yet.
Please try it first and use clx/mit-clx
only
if clx/new-clx
does not work for you.
clx/new-clx
comes with several demos, please try them using
$
clisp-K
full-i
modules/clx/new-clx/demos/clx-demos.lisp
-x
'(clx-demos:run-all-demos)'
and follow the intructions.
This functionality is documented in the manual
https://common-lisp.net/project/cmucl/doc/clx/, also
available in the CLISP source distribution as
modules/clx/clx-manual.tar.gz
.
gtk2
Call the operating system functions from CLISP. The following platforms are supported:
queens
n
-queens
problem on a n
×n
chessboard (a toy
example for the users to explore the CLISP module system).
modules/clx/new-clx/demos/sokoban.lisp
clx/new-clx
.
asdf
These notes document CLISP version 2.49.93+ | Last modified: 2018-02-19 |