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

4. Guile in a Library

In the previous chapters Guile was used to write programs entirely in Scheme, and no C code was seen; but I have been claiming ad nauseam that Guile is an extension language. Here we see how that is done, and how that can be useful.

4.1 Two world views  
4.2 What is libguile  
4.3 How to get started with libguile  
4.4 More interesting programming with libguile  
4.5 Further examples  


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

4.1 Two world views

In this manual, I usually jump into examples and explain them as you type in the code; here I will digress and ramble for a few paragraphs to set some concepts straight, and then let you type (or paste) in fun examples.

In 1995, I implemented a large program, Gnudl, using Guile quite extensively. In the design phase of Gnudl, I found I had to make a choice: should the fundamental data structures be C or Scheme data structures?

Guile allows C to see its data structures (scalar types, lists, vectors, strings ...). C also allows Guile to see its data structures. As a large program designer, you have to decide which of those capabilities to use. You have two main choices:

  1. You can write your software mostly in Scheme. In this case, your C software will mostly parse the Scheme code with Guile calls, and provide some new primitive procedures to be used by Scheme. This is what Gnudl does.

  2. You can write your software mostly in C, occasionally allowing Scheme code to be parsed by Guile, either to allow the user to modify data structures, or to parse a configuration file, ...

Mixing the two approaches seems unwise: the overall layout would be confusing. But who knows? There might be problems that are best solved by a hybrid approach. Please let me know if you think of such a problem.

If you use the former approach, we will say that the master world is Scheme, and the C routines serve Scheme and access Scheme data structures. In the latter case, the master world is C, and Scheme routines serve the C code and access C data structures.

In both approaches the libguile.a library is the same, but a predominantly different set of routines will be used. When we go through examples of libguile use, we will point out which is the master world in order to clarify these two approaches.


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

4.2 What is libguile

Libguile is the library which allows C programs to start a Scheme interpreter and execute Scheme code. There are also facilities in libguile to make C data structures available to Scheme, and vice versa.

The interface provided by the libguile C library is somewhat specific to the implementation of the Scheme interpreter. This low-level libguile interface is usually referred to as the scm_ interface, since its public calls (API) all have the scm_ prefix.

There is also a higher-level libguile interface, which is usually referred to as the gh_ interface (libGuile High). Its public calls all have the gh_ prefix. The gh_ library interface is designed to hide the implementation details, thus making it easier to assimilate and portable to other underlying Scheme implementations.

People extending Guile by adding bindings to C libraries (like OpenGL or Rx) are encouraged to use the gh_ interface, so their work will be portable to other Scheme systems. The gh_ interface should be more stable, because it is simpler.

The scm_ interface is necessary if you want to poke into the innards of Scheme data structures, or do anything else that is not offered by the gh_ interface. It is not covered in this tutorial, but is covered extensively in @xref{Scheme data representation, Guile Reference Manual, guile-ref, Guile Reference Manual}.

This chapter gives a gentle introduction to the gh_ interface, presenting some hello world-style programs which I wrote while teaching myself to use libguile.

The Guile Programmer's Manual gives more examples of programs written using libguile, illustrating diverse applications. You can also consult my Gnudl documentation at http://nis-www.lanl.gov/~rosalia/mydocs/ to see a large scale project that uses C and Scheme code together.


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

4.3 How to get started with libguile

Here is an elementary first program, learn0, to get going with libguile. The program (which uses Scheme as a master world) is in a single source file, learn0.c:

 
/* test the new libgh.a (Guile High-level library) with a trivial
   program */

#include <stdio.h>

#include <guile/gh.h>

void main_prog(int argc, char *argv[]);

main(int argc, char *argv[])
{
  gh_enter(argc, argv, main_prog);
}

void main_prog(int argc, char *argv[])
{
  int done;
  char input_str[200];

  gh_eval_str("(display \"hello Guile\")");
  gh_eval_str("(newline)");

  /* for fun, evaluate some simple Scheme expressions here */
  gh_eval_str("(define (square x) (* x x))");
  gh_eval_str("(define (fact n) (if (= n 1) 1 (* n (fact (- n 1)))))");
  gh_eval_str("(square 9)");

  /* now sit in a Scheme eval loop: I input the expressions, have
     Guile evaluate them, and then get another expression. */
  done = 0;
  fputs("learn0> ", stdout);
  while (fgets(input_str, 199, stdin) != NULL) {
    gh_eval_str(input_str);
    fputs("\nlearn0> ", stdout);
  }

  exit(0);
}

If you name this program learn0.c, it can now be compiled with:
 
gcc -g -c learn0.c -o learn0.o
gcc -o learn0 learn0.o -lguile -lm

The program is simple: it creates a Scheme interpreter, passes a couple of strings to it that define new Scheme functions square and factorial, and then a couple of strings that invoke those functions.

It then goes into a read-eval-print-loop (REPL), so you could type one-line Scheme expressions to it and have them evaluated. For example:
 
<shell-prompt> ./learn0
hello Guile
learn0> (display (sin 1.3))
963.558185417193e-3
learn0> (display (fact 10))
3628800
learn0> (quit)
<shell-prompt>

You should notice the key steps involved in this learn0 program:

  1. #include <guile/gh.h>
  2. You need to invoke the initialization routine gh_enter(). This starts up a Scheme interpreter, handling many implementation-specific details.
  3. Your main() function should be almost empty: the real main program goes in a separate function main_prog() which is passed to gh_enter(). This rather arcane convention is due to the way Guile's garbage collector works: the whole program has to run in the dynamic context of gh_enter().
  4. You pass strings to the Scheme interpreter with the gh_eval_str() routine.
  5. You link your program with -lguile.


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

4.4 More interesting programming with libguile

The learn0 program shows how you can invoke Scheme commands from a C program. This is not such a great achievement: the same could have been done by opening a pipe to SCM or any other Scheme interpreter.

A true extension language must allow callbacks. Callbacks allow you to write C routines that can be invoked as Scheme procedures, thus adding new primitive procedures to Scheme. This also means that a Scheme procedure can modify a C data structure.

Guile allows you to define new Scheme procedures in C, and provides a mechanism to go back and forth between C and Scheme data types.

Here is a second program, learn1, which demonstrates these features. It is split into three source files: learn1.c, c_builtins.h and c_builtins.c. I am including the code here.

Notice that learn1 uses a Scheme master world, and the C routines in c_builtins.c are simply adding new primitives to Scheme.

4.4.1 learn1.c  
4.4.2 c_builtins.h  
4.4.3 c_builtins.c  
4.4.4 What learn1 is doing  
4.4.5 Compiling and running learn1  


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

4.4.1 learn1.c

Here is `learn1.c':
 
#include <stdio.h>

#include <guile/gh.h>

#include "c_builtins.h"

void main_prog(int argc, char *argv[]);

main(int argc, char *argv[])
{
  gh_enter(argc, argv, main_prog);
}

void main_prog(int argc, char *argv[])
{
  char input_str[200];		/* ugly hack: assume strlen(line) < 200 */
  int done;

  /* for fun, evaluate some simple Scheme expressions here */
  gh_eval_str("(define (square x) (* x x))");
  gh_eval_str("(define (fact n) (if (= n 1) 1 (* n (fact (- n 1)))))");
  gh_eval_str("(square 9)");
  gh_eval_str("(fact 100)");

  /* now try to define some new builtins, coded in C, so that they are
     available in Scheme. */
  gh_new_procedure1_0("c-factorial", c_factorial);
  gh_new_procedure1_0("c-sin", c_sin);
  gh_new_procedure1_0("v-t", vector_test);

  /* now sit in a Scheme eval loop: I input the expressions, have
     Guile evaluate them, and then get another expression.  */
  done = 0;
  fputs("learn1> ", stdout);
  while (!done) {
    if (gets(input_str) == NULL) {
      done = 1;
    } else {
      gh_eval_str(input_str);
      fputs("learn1> ", stdout);
    }
  }

  exit(0);
}


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

4.4.2 c_builtins.h

Here is `c_builtins.h':
 
/* builtin function prototypes */

#include <guile/gh.h>

SCM c_factorial(SCM n);
SCM c_sin(SCM n);
SCM vector_test(SCM s_length);


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

4.4.3 c_builtins.c

Here is `c_builtins.c':
 
#include <stdio.h>
#include <math.h>

#include <guile/gh.h>

#include "c_builtins.h"

/* this is a factorial routine in C, made to be callable by Scheme */
SCM c_factorial(SCM s_n)
{
  int i;
  unsigned long result = 1, n;

  n = gh_scm2ulong(s_n);

  gh_defer_ints();
  for (i = 1; i <= n; ++i) {
    result = result*i;
  }
  gh_allow_ints();
  return gh_ulong2scm(result);
}

/* a sin routine in C, callable from Scheme.  it is named c_sin() to
   distinguish it from the default Scheme sin function */
SCM c_sin(SCM s_x)
{
  double x = gh_scm2double(s_x);

  return gh_double2scm(sin(x));
}

/* play around with vectors in Guile: this routine creates a vector of
   the given length, initializes it all to zero except element 2 which
   is set to 1.9.  */
SCM vector_test(SCM s_length)
{
  SCM xvec;

  c_length = gh_scm2ulong(s_length);
  printf("requested length for vector: %ld\n", gh_scm2ulong(s_length));

  /* create a vector */
  xvec = gh_make_vector(s_length, gh_double2scm(0.0));
  /* set the second element in it */
  gh_vector_set_x(xvec, gh_int2scm(2), gh_double2scm(1.9));

  return xvec;
}


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

4.4.4 What learn1 is doing

If you compare learn1 to learn0, you will find that learn1 uses a new Guile construct: the function gh_new_procedure(), and its siblings:

 
  /* now try to define some new builtins, coded in C, so that they are
     available in Scheme. */
  gh_new_procedure1_0("c-factorial", c_factorial);
  gh_new_procedure1_0("c-sin", c_sin);
  gh_new_procedure1_0("v-t", vector_test);

It is clear that gh_new_procedure() adds a new builtin routine written in C which can be invoked from Scheme. We can now revise our checklist for programming with libguile, so it includes adding callbacks.

  1. #include <guile/gh.h>
  2. You need to invoke the initialization routine gh_enter(). This starts up a Scheme interpreter, handling many details.
  3. Your main() function should be almost empty: the real main program goes in a separate function main_prog() which is passed to gh_enter(). This rather arcane convention is due to the way Guile's garbage collector works: the whole program has to run in the dynamic context of gh_enter().
  4. You pass strings to the Scheme interpreter with the gh_eval_str() routine.
  5. [new] You can now define new builtin Scheme functions; i.e. define new builtin Scheme functions, with the gh_new_procedure() routine.
  6. You pass strings to the Scheme interpreter with the gh_eval_str() routine.
  7. You link your program with -lguile.

I breezed by the issue of how to write your C routines that are registered to be called from Scheme. This is non-trivial, and is discussed at length in the Guile Programmer's Manual.


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

4.4.5 Compiling and running learn1

 
gcc -g -c learn1.c -o learn1.o
gcc -g -c c_builtins.c -o c_builtins.o
gcc -o learn1 learn1.o c_builtins.o -lguile -lm

If you run learn1, it will prompt you for a one-line Scheme expression, just as learn0 did. The difference is that you can use the new C builtin procedures (c-factorial, c-sin, v-t).

 
<shell-prompt> ./learn1
welcome to Guile
hello Guile
learn1> (display (c-factorial 6))
720
learn1> (display (c-factorial 20))
2192834560
learn1> (display (c-factorial 100))
0
learn1> (display (c-sin 1.5))
0.997494986604054
learn1> (display (v-t 10))
requested length for vector: 10
#(0.0 0.0 1.9 0.0 0.0 0.0 0.0 0.0 0.0 0.0)
learn1> (display (v-t 15))
requested length for vector: 15
#(0.0 0.0 1.9 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0)
learn1> (quit)
<shell-prompt>

As you see, taking (c-factorial 100) does not use bignumbers and returns a bogus answer.


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

4.5 Further examples

Further "idealized" examples are included in the doc/examples/c distribution. They include programs to:


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

This document was generated by Ingo Ruhnke on September, 12 2002 using texi2html