[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2. Building programs

In this chapter we describe how you can use ECL to build programs and loadable extensions that you can later on distribute to other people.

2.1 What can ECL do?  
2.2 Compiling files  
2.3 Building standalone executables  
2.4 Building libraries  
2.5 File names  
2.6 Compiler examples  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1 What can ECL do?

Some day for some reasons you will be in the need to distribute code that has been developed using ECL. In the following sections we will describe the means that ECL offers you to do so. Basically, these are the alternatives

SOURCE CODE
You distribute your programs in source code form. This is the easiest and most portable way, but not the fastest one.
STANDALONE PROGRAMS
You translate all your lisp code to C using the ECL compiler. The final object files can be linked against other C/C++ libraries to obtain a standalone executable.
YOU CAN BUILD STATICALLY AND DYNAMICALLY LINKED LIBRARIES.
You translate all your lisp code to C and combine the resulting object files into a single library with `.a' extension. You can distribute this library to other people and the final users can utilize these libraries to build standalone programs.
YOU CAN BUILD DYNAMICALLY LOADABLE FILES.
This is the most flexible way. You translate all lisp code to C and link it against possibly other C/C++ libraries to obtain a dynamically loadable library (file type `.so' under unix). This library can be loaded a startup time to add new functionality to the ECL environment.

In several of these options, we have mentioned the possibility to include C/C++ code. Even if this is possible, you cannot use ordinary C/C++ compilers and makefiles to build ECL extensions, let it be programs or libraries. Briefly, you have to organize your code as follows

  1. Organize the C code as a library, let it be static or dynamic.
  2. Build a function, say mymain(), in which the initialization phase for your library is performed.
  3. Group the code that interfaces to Lisp in separate C files, all of which should include #include <ecl.h> at the beginning.
  4. Compile your lisp source files.
  5. Let ECL build the final executable or library.
In the final step there are ways to instruct ECL to call your initialization function (mymain() in the example above). These means are explained in the following sections.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2 Compiling files

ECL supports two types of compilation. One is bytecodes compilation. This process is performed on-the-fly, as you load source files with lisp code. This leads to a series of bytes for each instruction, the so called "bytecodes". These bytecodes are interpreted in a virtual machine, which is written in C and which is reasonably fast.

The other type of compilation is the so-called "native" compilation. This process consists on translating the lisp source file to C language. The intermediate file is later compiled using a C compiler. The result is an object file which may have different purposes.

DYNAMICALLY LOADABLE FILES OR FASL (FAST LOADABLE) FILES
These are produced in a ECL built with support for dynamically loadable libraries (Feature :DLOPEN arguments are passed to compile-file. These object files typically have the `.fas' extension, and can be loaded with load. They cannot be used to build libraries nor standalone executable programs.

LINKABLE OBJECT FILES
These are produced when invoking compile-file with the keyword argument :system-p extension. It cannot be loaded with load, but it can be used to build libraries, standalone executable programs, or larger FASL files.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.3 Building standalone executables

To build an executable you need a working ECL image with the compiler. The function to build customized images is c::build-program. The description of this function is as follows.

Function: c:build-program {image-name &key

This function builds a lisp image up from the core lisp library, plus all components listed in lisp-files. Each component is either:

ld-flags is a list of strings with additional parameters to be passed to the linker. You can include here your favorite C/C++ libraries.

prologue-code and epilogue-code are used to customize the initialization process of the lisp image. In order to build the executable, c:build-program first writes down a piece of C code which initializes the lisp environment. You can customize the initialization process by suppling code to be executed before (prologue-code) or after (epilogue-code) setting up the lisp environment. Typically prologue-code defaults to an empty string, while epilogue-code invokes the classical lisp top-level.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.4 Building libraries

To build a library you proceed more or less the same way as with standalone executables. There are two different functions depending on whether you need to build static or shared libraries.

Function: c:build-static-library {library-name &key
Function: c:build-shared-library {library-name &key

This function builds a library file up from the object files listed in lisp-files. Each of the arguments to lisp-file must name a single object file produced with compile-file.

library-name is the physical pathname corresponding to the library. The value of library-name must follow some system-specific conventions. To make your program portable, library-name should be built using the output of compile-file-pathname.

prologue-code and epilogue-code are strings with C code to be executed before and after initializing the library, respectively. For dynamically linked libraries you can also provide a list of strings in ld-flags. These strings are additional parameters for the linker and their purpose is to link C/C++ extensions into the library.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.5 File names

Function: compile-file-pathname {filename-base &key

When compiling lisp files, creating libraries, etc, a number of files are produced which are of interest for the user or programmer. However, the name of these files will change from system to system. The purpose of the function compile-file-pathname is to query the compiler about the name of the different files that it can produce. Possible values of the type argument include:

:FAS (DEFAULT)
Standard compiled files that can be loaded with load.
:C, :DATA, :H
Intermediate files produced by the Lisp-to-C translator.
:O
Linkable object files.
:LIB, :STATIC-LIBRARY
A normal library produced with c:build-static-library.
:DLL, :SHARED-LIBRARY
A dynamically linked library produced with c:build-shared-library.
:PROGRAM
An executable produced with c:build-program.

The output of this function is system specific. For example, under FreeBSD
 
> (compile-file-pathname "/this/path/mylib" :type :lib)
#P"/this/path/libmylib.a"
> (compile-file-pathname "/this/path/mylib" :type :dll)
#P"/this/path/libmylib.so"
> (compile-file-pathname "/this/path/mycode")
#P"/this/path/mycode.fas"


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.6 Compiler examples


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.6.1 The `hello.lisp' file

In the following examples we will use the same lisp program. You have to create a file called `hello.lisp' which contains the following lines

 
(princ "Hello world!")
(terpri)
(quit)
If you start ECL and load this file in the Common-Lisp environment you will see the "Hello world!" message and the interpreter will be closed.
 
ECL (Embeddable Common-Lisp) 0.9d
Copyright (C) 1984 Taiichi Yuasa and Masami Hagiya
Copyright (C) 1993 Giuseppe Attardi
Copyright (C) 2000 Juan J. Garcia-Ripoll
        ECL is free software, and you are welcome to redistribute it
under certain conditions; see file 'Copyright' for details.
Type :h for Help.  Top level.
> (load "hello.lisp")
;;; Loading "hello.lisp"
Hello World!


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.6.2 Example of loadable object file

You can only perform the example in this section if your ECL image supports dynamically loading of object files. This is true if you find the keyword :dlopen in a typical FreeBSD or Linux box,
 
Type :h for Help.  Top level.
> *features*
(:IEEE-FLOATING-POINT :IBM-PC :I386 :BSD :UNIX :DLOPEN :ANSI-CL :CLOS
    :BOEHM-GC :ECL :COMMON)

In this example we build a loadable extension which prints the "Hello world!" message. First you need to create a the `hello.lisp' file. Next you have to enter the ECL environment and type (compile-file "hello.lisp"). This produces a loadable object file.

 
Type :h for Help.  Top level.
> (compile-file "hello.lisp")
;;; Loading #P"/usr/lib/ecl/cmp.fas"
;;; Loading #P"/usr/lib/ecl/sysfun.lsp"
;;; Compiling hello.lisp.
;;; End of Pass 1.  
;;; Calling the C compiler... 
;;; Invoking external command: gcc -O2 -march=i686 -pipe -fomit-frame-pointer -fPIC -fstrict-aliasing -Dlinux -O "-I/usr/lib/ecl//h" -w -c "hello.c" -o "hello.o"
;;; Invoking external command: gcc -o "hello.fas" -L"/usr/lib/ecl/" "hello.o"  -Wl,--rpath,/usr/lib/ecl/ -shared   -lecl -lgmp -lgc -ldl -lm 
;;; OPTIMIZE levels: Safety=2, Space=0, Speed=3
;;; Finished compiling hello.lisp.
#P"hello.fas"
Top level.
> (load "hello")
;;; Loading #P"hello.fas"
Hello World!


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.6.3 Example of standalone program

In this example we build a standalone program which prints the "Hello world!" message and does nothing else. First you must create the `hello.lisp' file shown above. Next you have to enter the ECL environment and type (compile-file "hello.lisp" :system-p t). This produces an object file that can be linked against the ECL core image.

 
Type :h for Help.  Top level.
> (compile-file "hello.lisp" :system-p t)
;;; Loading #P"/usr/lib/ecl/cmp.fas"
;;; Loading #P"/usr/lib/ecl/sysfun.lsp"
;;; Compiling hello.lisp.
;;; End of Pass 1.  
;;; Calling the C compiler... 
;;; Invoking external command: gcc -O2 -march=i686 -pipe -fomit-frame-pointer -fPIC -fstrict-aliasing -Dlinux -O "-I/usr/lib/ecl//h" -w -c "hello.c" -o "hello.o"
;;; OPTIMIZE levels: Safety=2, Space=0, Speed=3
;;; Finished compiling hello.lisp.
#P"hello.o"

The final step is to build the executable using the c:build-program instruction.
 
> (c:build-program "myecl" :lisp-files '("hello.o"))
;;; Invoking external command: gcc -O2 -march=i686 -pipe -fomit-frame-pointer -fPIC -fstrict-aliasing -Dlinux -O "-I/usr/lib/ecl//h" -w -c "myecl.c" -o "myecl.o"
;;; Invoking external command: gcc -o "myecl" -L"/usr/lib/ecl/" "myecl.o" "hello.o"  -Wl,--rpath,/usr/lib/ecl/  -lecl -lgmp -lgc -ldl -lm 
#P"myecl"
Top level.
Now you can execute this program from your favorite shell.

 
% ./myecl
Hello world!


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.6.4 Combining files into a larger FASL

You can only perform the example in this section if your ECL image supports dynamically loading of object files. In this example we build a loadable library which prints the "Hello world!" message and does nothing else. First you must create the `hello.lisp' file shown above. Next you have to enter the ECL environment and type (compile-file "hello.lisp" :system-p t). This produces an object file that can be linked to form a loadable library.

 
Type :h for Help.  Top level.
> (compile-file "hello.lisp" :system-p t)
;;; Loading #P"/usr/lib/ecl/cmp.fas"
;;; Loading #P"/usr/lib/ecl/sysfun.lsp"
;;; Compiling hello.lisp.
;;; End of Pass 1.  
;;; Calling the C compiler... 
;;; Invoking external command: gcc -O2 -march=i686 -pipe -fomit-frame-pointer -fPIC -fstrict-aliasing -Dlinux -O "-I/usr/lib/ecl//h" -w -c "hello.c" -o "hello.o"
;;; OPTIMIZE levels: Safety=2, Space=0, Speed=3
;;; Finished compiling hello.lisp.
#P"hello.o"

The final step is to build the library using the c:build-shared-library instruction.
 
> (c:build-shared-library "myecl" :lisp-files '("hello.o"))
;;; Invoking external command: gcc -O2 -march=i686 -pipe -fomit-frame-pointer -fPIC -fstrict-aliasing -Dlinux -O "-I/usr/lib/ecl//h" -w -c "myecl.c" -o "myecl.o"
;;; Invoking external command: gcc -o "libmyecl.so" -L"/usr/lib/ecl/" "myecl.o" "hello.o"  -Wl,--rpath,/usr/lib/ecl/ -shared   -lecl -lgmp -lgc -ldl -lm 
#P"libmyecl.so"
Now you can load this extension from any ECL image, even those you produce with c:build-program.

 
<<<<<<<< THIS EXAMPLE IS WRONG?! >>>>>>>>>
> (load "myecl")
;;; Loading myecl.fas
Hello world!
Bye.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Juan Jose Garcia Ripoll on May, 30 2005 using texi2html