BiglooA ``practical Scheme compiler''User manual for version 3.1aMay 2008

24. Bigloo A ``practical Scheme compiler'' User manual for version 3.1a May 2008 -- Bigloo Libraries

main page

top: | Bigloo A ``practical Scheme compiler'' User manual for version 3.1a May 2008

Bigloo Libraries

Chapters

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 split into several files:

- one heap that describes the locations of the library.
- several host library files.
- possibly, C header files.
- possibly, an initialization file.

Let's consider, for example, a library that implements the `format` Common Lisp facility. Let's suppose we name this library `bformat` and let's suppose that the library number is `1.0`. Using a Unix machine, the Bigloo library will consist of the following files:

- `bformat.heap`: the heap file.
- `bformat.init`: the initialization file.
- `libbformat_s-1.0.a`, `libbformat_s-1.0.so`, `libbformat_u-1.0.a`, `libbformat_u-1.0.so`: the Unix library files. The file names with a `_u` are libraries compiled in unsafe and optimized mode. By convention the library using the `_s` suffix are safe libraries, `_p` are profiling libraries, `_d` debug libraries, and `_e` eval libraries.
- `bformat.h`: an include file.

### 24.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. For instance, that file may be used to specify compilation flags. The initialization file may affect any of the global parameters of the Bigloo compiler. A Bigloo user library might be needing additional system library. For instance, a Bigloo library supporting SSL connections is likely to be needing the a native library. Setting the compiler variable `*ld-port-options*` has this effect. For instance, one may define an initialization file such as:

    (cond-expand
       (bigloo-compile
        (set! *ld-post-options* (string-append "-lssl " *ld-post-options*)))
       (bigloo-eval
        #unspecified))

When a Bigloo library `lib` is used, the Bigloo linker automatically looks at 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_[s|u]-VERSION.a` or `libNAME_[s|u]-VERSION.DYNLIB-SUFFIX` in the compilation linker path when using the native back-end. It searches for a file `NAME_[s|u]-VERSION.zip` when the JVM back-end is used.
This default NAME can be overridden in the initialization file. The function `declare-library!` associates a Bigloo library name and a system name.

declare-library! ident [attributes] | library procedure

All the attributes are optional.

- `version:` the version number of the library. This defaults to the Bigloo version number.
- `basename:` the base of the filename containing the library. This default to the library name.
- `srfi:` a list of symbols denoting the SRFI 0 features implemented by this library. Registered SRFIs may be tested by the `cond-expand` form (see SRFIs). This defaults to an empty list.
- `dlopen-init:` a function to be invoked when the library is dynamically loaded using the function `dynamic-load`. This defaults to `#f`.
- `module-init:` a module to be initialized when the library is loaded. This defaults to `#f`.
- `eval-init:` a module to be initialized for binding the library exports in the interpreter. This defaults to `#f`.
- `class-init:` the JVM or .NET class name containing the module to be initialized. This defaults to `#f`.
- `eval-init:` the JVM or .NET class name containing the module to be initialized for eval. This defaults to `#f`.
- `init:` a function to be invoked when a library is loaded. This defaults to `#f`.
- `eval:` a function to be invoked when a library is loaded for the interpreter. This defaults to `#f`.

Examples:

- The following declares a library named `foo`. When loaded the Bigloo runtime system will seek file named `libfoo_s-3.1a.so`, `libfoo_u-3.1a.so`, and `libfoo_e-3.1a.so`.

      (declare-library! 'foo)

- The following declares a library named `pthread`. When loaded the Bigloo runtime system will seek file named `libbigloopth_s-1.1a.so`, `libbigloopth_u-1.1a.so`, and `libbigloopth_e-1.1a.so`. Once the library loaded, the SRFI-0 features `pthread` and `srfi-18` will be bound. When loading the library, the two modules `__pth_thread` and `__pth_makelib` will be initialized. In the JVM version these modules are compiled in the classes `"bigloo.pthread.pthread"` and `"bigloo.pthread.make-lib"`.

      (declare-library! 'pthread
                        :basename "bigloopth"
                        :version "1.1a"
                        :srfi '(pthread srfi-18)
                        :module-init '__pth_thread
                        :module-eval '__pth_makelib
                        :class-init "bigloo.pthread.pthread"
      		  :class-eval "bigloo.pthread.make-lib")

library-translation-table-add! ident name | library procedure

library-translation-table-add! ident name version | library procedure

library-translation-table-add! ident name version :dlopen-init initsym | library procedure

The function `library-translation-table-add!` is obsolete. It should no longer be used in new code. It is totally subsumed by `declare-library!`. The function `library-translation-table-add!` is still documented for enabling readers to understand old Bigloo source code.
This function register a `name` for the library `id`. An optional `version` can be specified. The optional named argument `dlopen-init` gives the base name of the initialization entry point of a library.
Imagine that we would like to name our `bformat` library `bigloobformat`. This can be achieved by adding the following expression in the initialization file.

    (library-translation-table-add! 'bformat "bigloobformat")

Using this translation, on a Unix platform, the library used during the linking will be named: `libbigloobformat_s-<BIGLOO-VERSION>.a`. In order to change the `<BIGLOO-VERSION>` to another suffix, such as `1.0`, one may use:

    (library-translation-table-add! 'bformat "bigloobformat" "1.0")

In such a case, the library searched will be named `libbigloobformat_s-1.0.a`.
Specifying a `#f` prevents the insertion of any suffix. Hence,

    (library-translation-table-add! 'bformat "bigloobformat" #f)

Instruments the compiler to look at a library named `libbigloobformat_s.a`.

### 24.2 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.

### 24.3 library and eval

The function `library-load` loads a library in the interpreter.

library-exists? ident . path | library procedure

Checks if the library `ident` exists for the current back-end.
The regular Bigloo library paths are scanned unless optional `path`s are sent to the function.

library-load ident . path | library procedure

Loads a library in the interpreter. In addition to dynamically loading the library, this function tries to the `_e` version of the library.
Libraries are searched in regular Bigloo library paths unless optional `path`s are sent to the function.
This version may be used for automatically exporting binding to the interpreter. In general, the `_e` library is a simple library that contains only one module, the module that is used to build the heap-file. For instance, let's consider an implementation of a library for SSL programming. This library is composed of a single implementation module `__ssl_ssl`. The library is build using a heap file:

    (module __ssl_makelib
       (import __ssl_ssl))

Changing this file for:

    (module __ssl_makelib
       (import __ssl_ssl)
       (eval   (export-all)))

Enables the construction of a `_e` library.
When the system loads a dynamic library, it initializes it. For that it expects to find initialization entry points in the dynamic libraries that are named after the libraries name. More precisely, for the `LIB_s` library, the loader seeks the entry point named `"LIB_s"` and for the `LIB_e`, it seeks `"LIB_e"`. The name of the initialization entry of a library can be changed using the `declare-library!` function. If that named is changed, one module of the library must contain an `option` module clause that sets the variable `*dlopen-init*` with the name of the initialization entry point.
Since Bigloo 3.1a, the runtime system supports a better way for initializing libraries. Initialization modules can be associated with a library. When loaded, these modules are automatically initialized. This new method fits harmoniously with the Bigloo initialization process and it prevents users from annotating the source code of the library.
For instance, if a library initialization file contains the following declaration:

    (declare-library! 'foo :module-init 'foo)

Then, the library must implement the `foo` module.

    (module foo
      (import ...)
      ...)

In addition if the library binds variables, functions, or classes in the interpreter then, an `eval-init` clause must be added to the class declaration:

    (declare-library! 'foo :module-init 'foo :eval-init 'foo-eval)

Then, the module `foo-eval` must be implemented in the `libfoo_e` library.

    (module foo-eval
      (import ...)
      (eval (export-all)))

The standard distribution contains examples of such construction. In particular, the multi-threading libraries `pthread` and `fthread` use this facility.

### 24.4 library and repl

It is possible to implement a "read-eval-print-loop" that is extended with the facilities implemented inside a library. In order to make the variables, functions, and classes of a library visible from the interpreter, the eval `library` module clause has to be used. (see Module Declaration) For instance, here is a module that implements a "repl" with the `format` facility available:

    (module format-repl
       (eval (library bformat))
       (library bformat))

    ;; a dummy reference to a facility of the format library
    (let ((dummy format))
       (repl)

### 24.5 Building a library

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 -heap-library <ident>`. 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 __bformat
         (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 (__bformat "bformat.scm")))

  Building it is simple:

      bigloo -unsafe -q -mkaddheap -mkaddlib -heap-library bformat \
           make-lib.scm -addheap bformat.heap

  The options `-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 option `-heap-library` instructs the compiler for the library name to be included inside the heap file. This name is used for checking versions at run-time.
- 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 libbiglooformat_s.a bformat.o
      ranlib libbiglooformat_s.a
      ld -G -o libbiglooformat_s.so bformat.o -lm -lc
      ar qcv libbiglooformat_u.a bformat_u.o
      ranlib libbiglooformat_u.a
      ld -G -o libbiglooformat_u.so bformat_u.o -lm -lc

The last step is to create an initialization file `bformat.init`:

    (declare-library! 'bformat :basename "bigloobformat" :version #f)

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.

### 24.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:
`make-lib.scm`:

    (module __make-point-lib
       (import (point "scm-point.scm"))
       (eval (export-all)))

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:

    (declare-library! 'point
                      :basename "point"
                      :srfi '(point)
                      :eval-init '__make-point-lib)

    (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)

    (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
    RELEASE		= `$(BIGLOO) -eval '(begin (print *bigloo-version*) (exit 0))'`
    BHEAPFLAGS      = -unsafe -q -mkaddheap -mkaddlib -v2 -heap-library point
    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_s-$(RELEASE).a $(SAFE_OBJECT)

    lib_u: olib_u $(UNSAFE_OBJECT)
            ar qcv libpoint_u-$(RELEASE).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_s-$(RELEASE).a libpoint_u-$(RELEASE).a

### 24.7 Library and modules

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.

This Html page has been produced by Skribe.
Last update Wed May 28 08:36:19 2008.