18.1 Compiling and linking with a library
18.2 Library and SRFI
18.3 Library and inline functions
18.4 library and repl
18.5 Building a library
18.6 A complete library example
18.7 Library and modules
Copyright
Acknowledgements
1. Table of contents
2. Overview of Bigloo
3. Modules
4. Core Language
5. Standard Library
6. Pattern Matching
7. Object System
8. Threads
9. Regular parsing
10. Lalr(1) parsing
11. Errors and Assertions
12. Eval and code interpretation
13. Macro expansion
14. Command Line Parsing
15. Explicit typing
16. The C interface
17. The Java interface
18. Bigloo Libraries
19. SRFIs
20. DSSSL support
21. Compiler description
22. User Extensions
23. Bigloo Development Environment
24. Global Index
25. Library Index
Bibliography
|
Bigloo libraries are collections of global bindings (global variables and
global functions). Bigloo libraries are build on the top of the host
operating system (e.g. Unix) libraries. Because Bigloo uses modules, a
library is not only a bundle of compiled codes and memory locations. A
Bigloo library is splited into several files:
- one heap that describes the locations of the library.
- several host library files.
- possibly, C header files.
- possibly, a compiler initialization file.
Let's consider, for example, a library that implements the format
Common Lisp facility. Let's suppose we name this library
bformat . Using a Unix machine, the Bigloo library will consist of
the following files:
bformat.heap : the heap file.
libbformat.a , libbformat.so , libbformat_u.a , libbformat_u.so :
the Unix library files. The file names with a _u are libraries compiled in
unsafe and optimized mode.
bformat.h : an include file.
18.1 Compiling and linking with a library
|
From the user stand point, using a library can be made two ways:
- Using the Bigloo
-library lib-name option where
lib-name is the name of the Bigloo library (not the name of one
of the Unix files implementing the library). The name of the library
must be lower case. For instance:
$ bigloo foo.scm -library bformat |
- Using the module clause
library . This second solution prevent from
using a special compilation option. For instance, this module will
automatically compile and link with the bformat library:
(module foo
(library bformat))
...
(format ...)
|
When a Bigloo library lib is used, Bigloo automatically searches
if a file called lib.init exists. If such a file exits, it is
loaded at compile-time. That file may specifies compilation flags.
When a Bigloo library lib is used, the Bigloo linker
automatically searches for a library to be linked against the
application. The name of the file containing the library depends on
the operating system and the back-end used. For instance, under Unix,
for a library called NAME, the Bigloo linker searches for a
file called libNAME.a or libNAME.so in the
compilation linker path when using the native back-end. It searches
for a file NAME.zip when the JVM back-end is used.
Libraries are related to Scheme SRFIs. That is, when a library is used
the SRFI implemented by the library is registered. Registered SRFIs
may be tested by the cond-expand form (see SRFIs).
18.3 Library and inline functions
|
It is illegal for libraries to include inline functions that make use of
new foreign types. By new foreign type, we mean foreign types that are
defined inside the library. A library may contains inline functions but
that inline functions must not even call function using foreign types in
their prototypes. Including inline functions making use of foreign C
type will make the compiler to fail when compiling user code. The
compiler will fail prompting type errors. A library may contains non-inline
functions that make use of new foreign types.
It is possible to implement a "read-eval-print-loop" that is extended
with the facilities implemented inside a library. Because of the Bigloo
module initialization process a module that implements an extended "repl"
must reference a least one of the binding of the library. For instance,
here is a module that implements a "repl" with the format
facility available:
(module format-repl
(library format))
;; a dummy reference to a facility of the format library
(let ((dummy format))
(repl)
|
Bigloo libraries require several steps before being completed.
- The first step is to build a library heap. This is achieved
using a special compilation mode:
-mkaddheap -mkaddlib -addheap .
That is, for your library you have to create a heap associated source file
that imports all the binding you want in your library. The heap source file
must be excluded from the source files that will be used to build
the host library.
Suppose we have a unique source file for the bformat library. The module
clause of this source file is:
(module __format
(export (format . args)
format:version
...
(eval (export format)
(export format:version)
...
|
Prior to compiling the library, we have to create the heap associated file
(let's name it make-lib.scm ). This file could be:
(module __make-lib
(import (__format "format.scm")))
|
Building it is simple:
bigloo -unsafe -q -mkaddheap -mkaddlib \
make-lib.scm -addheap format.heap |
The option -mkaddheap and -mkaddlib tell Bigloo that it
is compiling an heap associated file. The option -addheap tells
Bigloo the name of the heap file to be produced.
- The second step is to compile all the library source file. These
compilation must be done using the
-mkaddlib compilation mode.
For example:
bigloo -O3 -unsafe -mkaddlib \
-cc gcc -fsharing -q -rm \
-unsafev bformat.scm -o bformat_u.o -c
bigloo -O3 -mkaddlib -g -cg -cc gcc \
-fsharing -q -rm \
-unsafev bformat.scm -o bformat.o -c |
The first compilation produces the unsafe version the second the
produced the debugging version.
- The third step is to build the host operating system libraries. There
is no portable way to do this. This operation may looks like:
ar qcv libformat.a format.o
ranlib libformat.a
ld -G -o libformat.so format.o -lm -lc
ar qcv libformat_u.a format_u.o
ranlib libformat_u.a
ld -G -o libformat_u.so format_u.o -lm -lc |
At this time, you are ready to use your library. The Bigloo distribution
contains library exemplar. Considering these examples as a departure point
for new libraries is probably a good idea.
18.6 A complete library example
|
For the means of an example let's suppose we want to design a Bigloo
library for 2d points. That library is made of three implementation
files: two C files, point.h and point.c and one Scheme
file scm-point.scm . Here are defined the three files:
point.h : struct point_2d {
double x, y;
};
|
point.c :#include <stdio.h>
#include "point.h"
int print_point_2d( struct point_2d *pt ) {
printf( "<point-2d: %g, %g>", pt->x, pt->y );
}
|
scm-point.scm :(module point
(include "point.sch")
(extern (include "point.h"))
(export (make-point::s-point_2d* ::double ::double)
(print-point ::s-point_2d*)
(point? ::obj))
(eval (export-all)))
(define (make-point::s-point_2d* x::double y::double)
(s-point_2d* x y))
(define (print-point p::s-point_2d*)
(print_point_2d p))
(define (point? obj::obj)
(s-point_2d*? obj)
obj)
|
We want our library to be composed of the whole exported Scheme
functions. Thus the file to build the heap library could look like:
(module __make-point-lib
(import (point "scm-point.scm")))
|
Let's suppose that the point library requires the libposix
library. This means that any file linked with the point library
needs to be also linked with the posix library. Furthermore,
programs making use of the point library needs to include the
point.sch file. That Scheme file needs in turn the C file
point.h otherwise the produced C files won't compile. The need
for the libposix library and for the point.h file may be
specified inside the point.init file. For our current library,
the point.init file could look like:
(set! *ld-options*
(string-append "-L/usr/lib " *ld-options*))
(set! *bigloo-user-lib*
(cons "-lposix" *bigloo-user-lib*))
(set! *additional-include-foreign*
(cons "point.h" *additional-include-foreign*))
(define-macro (point x y)
`(make-point ,x ,y))
|
This file updates some compilation variables (*ld-options* ,
*bigloo-user-lib* , *additional-include-foreign* ) and
defines a macro: point . Because the point.init file will
be loaded each time a compilation require the point library is
spawned, user code are allowed to use the point macro. Here is an
example file making use of the point library:
(module example
(include "point.sch"))
(let ((p (point 2.9 3.5)))
(print "point?: " (point? p))
(print "point?: " (point? 4))
(print-point p)
(print (eval `(point? ,p)))
(eval `(print-point ,p))
(print "done..."))
|
To conclude that example here is the Makefile used to compile
the point library, heap file and one example.
# bigloo flags
BIGLOO = bigloo
BHEAPFLAGS = -unsafe -q -mkaddheap -mkaddlib -v2
BCOMMONFLAGGS = -mkaddlib -fsharing -q $(VERBOSE) \
-copt '$(CCOMMONFLAGS)' -cc $(CC)
BSAFEFLAGS = $(BCOMMONFLAGGS) -cg -O3 -g -cg -unsafev \
-eval '(set! *indent* 4)' -rm
BUNSAFEFLAGS = $(BCOMMONFLAGS) -O4 -unsafe
# cigloo flags
CIGLOO = cigloo
# cflags
CC = gcc
CCOMMONFLAGS = -I.
CSAFEFLAGS = $(CCOMMONFLAGS)
CUNSAFEFLAGS = $(CCOMMONFLAGS) -O2
# library objects
SAFE_OBJECT = olib/scm-point.o olib/point.o
UNSAFE_OBJECT = olib_u/scm-point.o olib_u/point.o
all: heap lib example
heap: point.heap
point.heap: point.sch scm-point.scm
$(BIGLOO) $(BHEAPFLAGS) make-lib.scm -addheap point.heap
lib: lib_u lib.a
lib.a: olib $(SAFE_OBJECT)
ar qcv libpoint.a $(SAFE_OBJECT)
lib_u: olib_u $(UNSAFE_OBJECT)
ar qcv libpoint_u.a $(UNSAFE_OBJECT)
olib:
mkdir olib
olib_u:
mkdir olib_u
olib_u/scm-point.o olib/scm-point.o: scm-point.scm
$(BIGLOO) $(BSAFEFLAGS) $(<F) -o $*.o -c
olib_u/point.o olib/point.o: point.c
$(CC) $(CSAFEFLAGS) $(<F) -o $*.o -c
point.sch: point.h point.c
cigloo $^ > point.sch
example: heap lib
$(BIGLOO) -v2 -L . -library point \
-static-bigloo example.scm -o example
clean:
-/bin/rm -f point.heap
-/bin/rm -f point.sch scm-point.c
-/bin/rm -fr olib olib_u
-/bin/rm -f example example.c example.o
-/bin/rm -f libpoint.a libpoint_u.a |
A Bigloo library may be composed of several Bigloo modules (even if in
our example only one module was used). The modules composing the library
are free to import each other. Nevertheless, someone designing a Bigloo
library should be aware that Bigloo importation creates dependences
between modules. A module mod1 that imports a module mod2
depends on mod2 because mod1 requires mod2 to be
initialized (i.e. mod1 calls to the initialization function of
mod2 ). The result is that using import clauses inside
modules composing a library may create a lot of dependencies between the
object files that are used to build the associated Unix
library. Dependencies should be avoided because they make the Unix
linkers unable to produce small stand-alone programs. Instead of
import clauses, use clauses should be
preferred. Use clauses do not create dependencies because a
module mod1 that use s a second module mod2 does not
require mod2 to be initialized. Of course, it may happen
situations where the initialization is mandatory and thus, the
import must not be replaced with a use clause. The source
code of the Bigloo library makes use of import and use
clauses. The Bigloo standard library should be studied as an example.
|