Calling Gambit Scheme Code From C
Dec 26, 2012
4 minute read

Here’s the situation: You have some ANSI C code in the project which includes main(…) as the entry point for your executable and you have some Gambit-C scheme code that you want to call from C.

The files in this project are:

  • main.c (contains the main function)
  • test_gambit.scm (contains the function to call from main.c)

How can you make this work and what is the build process on the command line?

Firstly, let’s show the scheme code:

; Listing 1: test_gambit.scm

(c-define (test-gambit s) (char-string) void "test_gambit" ""
	(write "From the gambit: ")
	(write s))

This uses gambit’s C interface to define a scheme lambda that will be visible to C code. This form defines a function visible to C as test_gambit(char* s).

The main.c file is a little more involved because it has to do some house keeping:

/* Listing 2: main.c */

#include <stdio.h>
#include <stdlib.h>

/* Based off the code from gamb-c's distribution in misc/simple-make-project.tgz 
   by Marc Feeley
*/

/*
 * ___VERSION must match the version number of the Gambit header file.
 */
#define ___VERSION 406006
#include "gambit.h"

/*
 * the link file "prog_.c" is generated.  It contains various tables
 * (symbols, global variables, list of modules, etc) describing the
 * set of Scheme modules that are linked.  The link file is needed to
 * initialize the Scheme runtime system.
 *
 * The symbol SCHEME_LINKER must be defined as the name of the Scheme
 * link file stripped of the extension, prefixed with "____20_" and
 * the character "_" transformed to "__".  This is the name of the
 * function in the link file that initializes the Scheme modules.
 */
#define SCHEME_LINKER ____20_prog__

___BEGIN_C_LINKAGE
extern ___mod_or_lnk SCHEME_LINKER(___global_state_struct*);
___END_C_LINKAGE


/* Forward declare the function from test-gambit.scm */
void test_gambit(char* str);



int main(int argc, char *argv[])
{
	fprintf(stdout, "Starting test ...\n");

  	/*
	 * Setup the Scheme library by calling "___setup" with appropriate
	 * parameters.  The call to "___setup_params_reset" sets all
	 * parameters to their default setting.  The call to "___setup" also
	 * runs the Scheme code at toplevel.  After the call to "___setup"
	 * and before the call to "___cleanup" it is possible to call Scheme
	 * functions from C if required.
	 */
	___setup_params_struct setup_params;

	___setup_params_reset(&setup_params);

	setup_params.version = ___VERSION;
	setup_params.linker  = SCHEME_LINKER;

	___setup(&setup_params);


	/* Now call our function from test_gambit.scm */
	test_gambit("Wow, this actually worked!\n");


	/*
	 * Cleanup the Scheme runtime.
	 */
	fprintf(stdout, "\nEnding ...\n");

 	___cleanup();
	
	return 0;
}

The comments in the code mostly come from the simple-make-project.tgz file in the gambit-c distribution and largely explain the situation here.

___VERSION must be defined and must match the value in the gambit.h header file. You will need to change this if you’re not using gambit scheme v4.6.6.

SCHEME_LINKER needs to be defined to a value that’s derived from the -link file that’s generated as part of the build process. In this example, our link file is called prog_c. If you write out different file names, this define will need to get modified accordingly.

We also place the function prototype for the C version of the function we defined in test_gambit.scm.

Inside the main function, we do some work to setup the scheme state by calling ___setup() with the appropriate parameters.

Once all of this is done, it is safe to call the function that we made in test_gambit.scm.

This is all straight forward enough, but how does it compile? Under linux (Fedora 18 beta), the steps look like this:

$ gsc -cc-options "-D___LIBRARY" -c test_gambit.scm
$ gsc -cc-options "-D___LIBRARY" -link -o prog_.c test_gambit.c
$ gsc -cc-options "-D___LIBRARY" -obj main.c
$ gsc -cc-options "-D___LIBRARY" -obj prog_.c
$ gsc -cc-options "-D___LIBRARY" -obj test_gambit.c
$ gsc -cc-options "-D___LIBRARY" -ld-options "-L/usr/local/Gambit-C/lib" -exe -o test_gambit main.o test_gambit.o prog_.o

$ ls -lh
total 5.6M
-rw-rw-r--. 1 timothy timothy 2.0K Dec 26 14:28 main.c
-rw-rw-r--. 1 timothy timothy 2.2K Dec 26 14:29 main.o
-rw-rw-r--. 1 timothy timothy 438K Dec 26 14:29 prog_.c
-rw-rw-r--. 1 timothy timothy 2.7K Dec 26 14:29 prog_.o
-rwxrwxr-x. 1 timothy timothy 5.1M Dec 26 14:30 test_gambit
-rw-rw-r--. 1 timothy timothy 4.1K Dec 26 14:29 test_gambit.c
-rw-rw-r--. 1 timothy timothy 5.1K Dec 26 14:30 test_gambit.o
-rw-rw-r--. 1 timothy timothy  103 Dec 26 14:00 test_gambit.scm

$ ./test_gambit 
Starting test ...
"From the gambit: ""Wow, this actually worked!\n"
Ending ...

Only the gambit scheme compiler gsc is used, which will call the c compiler as needed. ___LIBRARY get’s defined so that gambit doesn’t make it’s own main function for the scheme code which would conflict with the main function found in main.c.

The first thing is to compile the test_gambit.scm file to c, making the test_gambit.c file. Next we do a link of the scheme code to the the scheme runtime code, creating a c file called prog_.c. After that, we have all of the c code we need, so we compile the c code to object files in the next three commands. The final gsc command builds the executable from the object files and passing in a custom ld include folder for the install location of gambit.

If you want a makefile sample of how this could work, check the misc/simple-make-project.tgz file in the gambit distribution.