FAQ
From ecls
Contents |
Frequently asked questions (FAQ)
This page contains questions which have been asked quite often in the mailing list, or topics which are crucial but one normally misses when reading the manual.
1. General issues
1.1 What is ECL?
ECL stands for Embeddable Common-Lisp and it is a full implementation of the Common-Lisp language as defined by the ANSI Standard.
1.2 Is ECL really complete?
Yes, we strive for ANSI compliance, and any feature listed in the specification which is missing should be reported as a bug.
1.3 Why another lisp implementation?
Well, you must be joking. Compared to other worlds, such as the Scheme area, the number of implementations of Common-Lisp is rather small. In any case, ECL has several nice features which make it extremely valuable:
- It is small. The library is about 1Mb and makes extensive use of the capabilities of your C/C++ environment, thereby reusing a lot of code.
- It is extremely portable. It does not rely on knowledge of binary file formats and other things which make maintainance very complicated.
- It interacts very well with the C/C++ world. ECL can be embedded as an extension language in C/C++ applications. Furthermore, it provides a lisp-to-C/C++ translator, and you can inline C/C++ code in your lisp code.
- It provides efficient interpreted code. ECL features a rather small, but rather fast bytecodes compiler and interpreter.
1.4 But is it not the same as GCL?
Not really. Even though GCL and ECL share a common root -- they both come from the Kyoto Common-Lisp implementation -- they have parted. GCL has strived for Cltl2 compliance and is now running for ANSI compliance. In ECL this was the goal from the very beginning.
ECL was also born out of frustration when I (Juanjo) tried to compile GCL in a (then) rather new HP workstation. The binary file format had changed and GCL would not link, because the build process of GCL relied on loading object files and dumping a memory image. I thus took the Ecolisp implementation, which had been formerly used as an embedded library and which, at that time had a much cleaner code base, and redesigned it to produce a statically linked executable. The code of Ecolisp was heavily refactored, separating functions for dealing with lisp data from control functions (catch points, etc), and I wrote the first bytecodes interpreter. Finally, support for dynamically loading shared libraries came in. In the process many things changed, such as the C/C++ calling and output conventions, to make it easier to interface with external libraries (Indeed, all functions from the ANSI Common-Lisp standard are available as C functions that can be called from your program!)
1.5 What about the license?
The license in ECL is the LGPL (Lesser GPL), which, briefly summarized, states that
- You can link your application against any version of the ECL environment.
- Your application has to be distributed with the source code of the ECL environment you linked it against, together with means for relinking your code with newer versions of the library. The code for your application need not be disclosed.
- If you modify the code base of ECL (for instance improving the garbage collector), you have to distribute the source code of these changes as well.
- Writing programs in Common-Lisp to be run in ECL or, when embedding ECL, exposing the functions of the embedding application to the Common-Lisp world is not considered extending ECL. This is not explicitely mentioned in the LGPL but it is the intent of the authors.
2. Embedding
2.1 What does this "embedding" stuff mean?
ECL is a full fledge implementation of the Common-Lisp language. However, due to the way it is implemented, the implementation can be used as an extensibility language for your own application, much like Guile works for the Scheme language. By a rather simple set of functions, you can parse, compile and execute Common-Lisp forms, and using the Foreign Function Interface (FFI), you can add new functions to Common-Lisp which suit your Domain-Specific Language.
2.2 How do I embed ECL into my application?
You have to use the ECL library, which is called libecl.so, libecl.dyld or ecl.dll, depending on your operating system (Unix, Mac OSX or Windows). The program ecl-config will provide you with the flags you have to pass to the C/C++ compiler and to the linker, using either ecl-config --cflags or ecl-config --ldflags, respectively.
Regarding your program, apart from linking against the ECL library, you have to call the proper initialization routine, cl_boot(), so that ECL sets up the appropiate internal structures. After calling this routine, you will be able to run lisp code and create or manipulate lisp data.
2.3 The embedded ECL breaks when printing data
This is typically a mysterious break that happens in the Windows port. The reason is that ECL expects to be able to write to the standard input, standard output and error output streams/files. In C/C++ parlance, these are stdin, stdout and stderr. However, for some applications Windows does not set up all of these files and when ECL tries to print some informative message (for instance, when an error happens), it breaks.
The solution is that you redirect the Lisp standard input/output (*terminal-io*) and the error output (*error-output*) to some null devices, as in the following C/C++ code:
const char *lisp_code = " (progn (defvar *old-terminal-io* *terminal-io*) (defvar *old-error-output* *error-output*) (setf *error-output* (make-broadcast-stream)) (setf *terminal-io* (make-two-way-stream (make-string-input-stream "") (make-broadcast-stream))) ) " si_safe_eval(3,c_string_to_object(lisp_code), Cnil, OBJNULL);
This solution is quite dramatic. In general it is preferred to use Gray Streams to redefine the standard output and input streams and to redirect them to custom streams for your applications. This is done, for instance, in Julian Stecklina's XChatLisp
2.4 How do I run lisp code?
A very simple example is shown in Sect. 2.3. The idea is that you first must build a list containing the code and then evaluate it. Alternatively, you can load source files or FASL (i.e. compiled) files. Each solution has its pros and cons.
I personally prefer the two step process: 1) create the list from a text representation and 2) evaluate it using si_safe_eval. This solution has the advantage that si_safe_eval sets up a trivial error handler that intercepts all errors and exceptions (including escaping THROW, unmatched RETURN, etc) and returns the error value that the user supplies when the errors are caught. For instance, in the example from Sect. 2.3, OBJNULL is returned when any of the statements in the lisp form fails.
3. Compatibility
3.1 Is ECL ANSI-compliant?
We strive to achieve it. Currently ECL passes most of the tests in Paul Dietz's test suite. Any lack of compliance is considered a bug and you are welcome to report it or, even better, to fix it.
3.2 What about the MOP?
The MOP (Meta-Object Protocol) is an specification of how the guts of the object system in a Common-Lisp implementation should work. It was drop out of the ANSI Standard but it can be found in the book "The Art of the Metaobject Protocol". Due to the usefulness of having a MOP, most implementations provide it in some way or another, typically by using the PCL library. Opposite to this trend, ECL is shipped with an ANSI Compatible implementation of the CLOS object system, and is evolving slowly to implement most of the MOP.
4. Building and installing
4.1 Can I test ECL before installing it?
ECL is made of two pieces: the core library and the executable itself. Under Linux and similar systems, they are called "ecl" and "libecl.so". The executable itself is very small, and its only role is to load the ECL library and invoke toplevel command processor, that reads lisp forms and executes them. By using this splitting it is possible to have many different applications that make use of the ECL library, such as programs built by the user, FASL modules, etc.
For things to work properly programs, modules and anything that uses the library must know where to find it. Under Windows this is done with the PATH environment variable. Under Linux, Mac OSX and similar systems the location of the library is hardcoded in the programs. This is done for security reasons and also because it is very convenient.
The only problem arises when you build a new version of ECL in a machine in which ECL has been already installed. If you want to test the newly built version before installing it you have to tell the executable files where to find the library (libecl.so) and other system files. You do this by invoking ECL in the following way
$ cd build/ $ LD_LIBRARY_PATH=`pwd` ./bin/ecl -dir `pwd`
The first definition (LD_LIBRARY_PATH) tells the system where to look for the new version of the library, while the command line argument (-dir) tells ECL where to find the modules (ASDF, sockets, etc) and other system files.
4.2 How do I build ECL with a different C compiler?
In the ECL source distribution, the src/aclocal.m4 file contains M4 macro definitions that select the appropriate C compiler flags for your platform. The PICFLAG variable contains the C compiler flag that generates "position-independent" code (P - I - C). On many platforms, it is necessary to use this flag in order to build shared object files, so that ECL can load compiled Lisp code at runtime. Three other relevant variables are SHARED_LDFLAGS, BUNDLE_LDFLAGS, and SHAREDEXT (the filename extension for shared libraries -- e.g., "so" on GNU/Linux, "dylib" on Mac OS X).
aclocal.m4 has a Bourne shell script fragment which selects configuration variable values based on the host's operating system:
case "${host_os}" in
linux*)
...
;;
freebsd*)
...
;;
... # various other operating systems
esac
This would be a good place to add OS-specific defaults for compilers and compiler flags. A good model is the entry in the above case statement for "darwin*" (which represents MacOS X). OS-specific defaults are useful for the following reasons:
- GCC may not be available on certain platforms (e.g. various Cray systems, as of 7 May 2007 -- see the GCC website.)
- On other platforms, it may be desirable for performance or compatibility reasons to choose another compiler as the default.
In other cases, the user may wish to override the the OS-specific defaults. This can be done by setting the appropriate environment variables (CC, PICFLAG, etc.) when running the configure script.
