Experiments with Embedded TinyScheme

The point of the work on getting the TinyScheme shared library to build and install was to allow us to embed the TinyScheme interpreter into a C program. So, I experimented to see how that works. Basically, in your C program, you use the tinyscheme library to initialize a scheme environment, then you load any scheme file you want:

christopher@evenstar:~/Devel/embedded-ts$ cat loader.c
#include "tinyscheme/scheme.h"

int main() {
 scheme * env;
 FILE *fptr;
 // initialize the scheme invironment
 env = scheme_init_new();
 // set output to go to STDOUT by default
 scheme_set_output_port_file(env, stdout);
 // Load the init file
 fptr = fopen("/usr/lib/tinyscheme/init.scm", "r");
 scheme_load_file(env, fptr);
 fclose(fptr);
 // Load my scheme program
 fptr = fopen("myscheme.scm", "r");
 scheme_load_file(env, fptr);
 fclose(fptr);
 // de-initialize the scheme environment
 scheme_deinit(env);
 return 0;
}

This C program will load whatever Scheme program is in “myscheme.scm”, which happens to be:

christopher@evenstar:~/Devel/embedded-ts$ cat myscheme.scm 
(display "hello world!")
(newline)

So, we compile the program, and run it:

christopher@evenstar:~/Devel/embedded-ts$ gcc -o loader loader.c -ltinyscheme
christopher@evenstar:~/Devel/embedded-ts$ ./loader 
hello world!

Of course, that isn’t too exciting an example, but the point is that (in conjunction with the ffi) the user can have his own scheme code controlling behavior and calling functions in the C program, without having to recompile the C program. So, you get the power of Scheme with the portability and efficiency of C.

This was the dream of Richard Stallman. People think of the “Linux” operating system (it should be called “Gnu/Linux”) as being so awesome because it is so much like Unix. But Stallman didn’t really like Unix that much: he wanted a Lisp operating system. But Lisp operating systems required a lot of specialized hardware, whereas Unix could run on pretty much anything. So, the next best thing was to have a Unix-like operating system that at the foundation was written in C, but that code in turn was running mostly lisp code that could be very flexible and easily hacked by the user.

That dream wasn’t fully realized, unfortunately, throughout the Gnu operating system. But a great example of it is the Emacs text-editor, the core of which is written in C, but most of the action happens in elisp code. Also, Guile Scheme was designed to be embedded in C programs, and has been in a few cases, such as in the GnuCash software and LilyPond.

For libreCMC I am interested in TinyScheme rather than Guile Scheme, because Guile Scheme is too big for the embedded environment. Perhaps somebody could whittle Guile Scheme down to a much smaller core, but I didn’t see any options for that in the build system.

TinyScheme: Library Support Merged into libreCMC

As requested, I split TinyScheme in two packages: one installs the TinyScheme interpreter and the init.scm file, and the other installs the library for embedding TinyScheme in a C program. The libreCMC merge commit is here:

Commit 67c4b46aed

This is fundamentally a complete package (packages) but an area of improvement would be to reduce the size of compiled binaries, to take up less of that precious embedded flash space. I believe there are some additional compiler flags which could help with that.

TinyScheme: Fixed Problem with Building the Library Files

I fixed the problem mentioned earlier by adjusting the makefile to link using GCC instead of the linking with the ld linker directly. It seems like it should be possible to do it directly with the linker and the correct flags, but at the end of the day likely nobody cares how it builds so long as it does build.

The patch is available in my repo. The package allows you to select tinyscheme in menuconfig and select as options whether or not you want to installed the libraries. I submitted a pull request to libreCMC, but they asked if I could instead split the package into two packages, one with the libraries and one without, which will give users access to both without having to recompile. Should have that done in day or two, God willing.

Still working on TinyScheme Library

After installing the shared library from my TinyScheme package, I checked it with the ldd utility and discovered that many of the function symbols were not resolving. The cause of that was that the buildroot linker was not linking the library to libc or to libgcc_s. I patched the makefile to link to libc, which allowed most of the symbols to resolve, but I am having trouble getting buildroot to link to libgcc_s. It seems there is some bug or syntax problem where buildroot’s ld is not handling the underscore properly, and I get the error cannot find -lgcc.

Hopefully I’ll be able to get that figured out in a day or two and put the package patch into my repository.

TinyScheme Package Library

I’m still working to improve the TinyScheme package. I figured out the configuration and patches I needed to build the TinyScheme libraries, represented in this commit:

commit 797b5408dc

This patch causes libtinyscheme.so and libtinyscheme.a to be built in the build_dir directory in the libreCMC source code, but it does not actually get them included in the ipkg package. I was planning to add that in as a selectable package option.

The library is for embedding TinyScheme in another program.

TinyScheme Package in libreCMC

My TinyScheme package was accepted into libreCMC, commit 4a64056e70. Until their next build (a few months away) I’ll keep a binary package available for mips_24kc. That installs on the TPE-R1100, GL-AR150, GL-AR300M16, and GL-AR300M targets, among others.

root@pathos:~# tinyscheme 
TinyScheme 1.41
(define (fact n) 
   (do ((rem n (- rem 1))
        (acc 1 (* rem acc)))
   ((= rem 1) acc)))
ts> fact
(fact 4)
ts> 24
(map fact '(1 2 3 4 5 6 7 8 9 10 11 12 13))
ts> (1 2 6 24 120 720 5040 40320 362880 3628800 39916800 479001600 1932053504)

The 32 bit integer overflow is visible at (fact 13).