18. Bigloo -- Bigloo Libraries

Browsing
Home: | Bigloo A ``practical Scheme compiler'' User manual for version 2.6b December 2003
Previous chapter: | The Java interface
Next chapter: | Extending the Runtime System
Bigloo Libraries
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
Chapters
| 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. | Extending the Runtime System
20. | SRFIs
21. | DSSSL support
22. | Compiler description
23. | User Extensions
24. | Bigloo Development Environment
25. | Global Index
26. | 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.

  18.2 Library and SRFI

  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.

  18.4 library and repl

  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)

  18.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`. 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

  18.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 Scribe page has been generated by `scribeinfo`.
  Last update Tue Dec 16 13:46:41 2003