[gambit-list] Re: How to create small standalone executable with Gambit-C?

Marc Feeley feeley at iro.umontreal.ca
Tue Aug 18 01:48:30 EDT 2009


On 17-Aug-09, at 11:32 PM, peter lo wrote:

> The above partition of the modules is only a random suggestion, but  
> you get the idea. With such a system, only the relevant parts get  
> into the final program, so we pay for only when we need.

Here's an idea that is based on

https://webmail.iro.umontreal.ca/pipermail/gambit-list/2008-October/002725.html

It involves rewriting the Scheme library, which is not as complex as  
one might think, for example the BIT system contains a R4RS library  
written in Scheme that could be reused with only a few changes.

You need to first create a minimal Gambit library that only contains  
the kernel:

% ./configure
% make
% make bootstrap
% ... now edit lib/makefile.in to only include _kernel in the library...
% diff lib/makefile.in lib/makefile.in-orig
78,83c78,89
< MODULES = _kernel
< MODULES_SCM = _kernel.scm
< MODULES_C = _kernel.c
< MODULES_O = _kernel at obj@
< MODULES_O_PLUS = +_kernel at obj@
< MODULES_O_COMMA = _kernel at obj@
---
 > MODULES = _kernel _system _num _std \
 > _eval _io _nonstd _thread _repl
 > MODULES_SCM = _kernel.scm _system.scm _num.scm _std.scm \
 > _eval.scm _io.scm _nonstd.scm _thread.scm _repl.scm
 > MODULES_C = _kernel.c _system.c _num.c _std.c \
 > _eval.c _io.c _nonstd.c _thread.c _repl.c
 > MODULES_O = _kernel at obj@ _system at obj@ _num at obj@ _std at obj@ \
 > _eval at obj@ _io at obj@ _nonstd at obj@ _thread at obj@ _repl at obj@
 > MODULES_O_PLUS = +_kernel at obj@ +_system at obj@ +_num at obj@ +_std at obj@ \
 > +_eval at obj@ +_io at obj@ +_nonstd at obj@ +_thread at obj@ +_repl at obj@
 > MODULES_O_COMMA = _kernel at obj@,_system at obj@,_num at obj@,_std at obj@,\
 > +_eval at obj@,_io at obj@,_nonstd at obj@,_thread at obj@,_repl at obj@
87c93,94
< MODULES_O_IN_COMPILE_ORDER = _kernel at obj@
---
 > MODULES_O_IN_COMPILE_ORDER = _io at obj@ _num at obj@ _std at obj@ \
 > _kernel at obj@ _nonstd at obj@ _repl at obj@ _eval at obj@ _thread at obj@  
_system at obj@
% cd lib
% make clean
% make
% cd ..
% ./gsc-comp -:=. -exe test.scm
% strip test
% ls -l test
-rwxr-xr-x  1 feeley  feeley  308672 Aug 18 01:35 test
% ./test
10946

The file test.scm is attached below.  As you can see I obtained a  
300kB executable for this program.

The program could have included all of the Scheme library.  Note that  
the definitions of the library procedures are in a "let" so the Gambit  
compiler can eliminate all of the definitions that are not needed.  It  
is in effect a whole-program compilation.

What would be really nice is if this could be done with the current  
Gambit runtime library.  This would require some changes to the  
structure of the library.  If anyone is interested in doing this,  
please let me know!

Marc


;; File: "test.scm"

(declare
  (standard-bindings)
  (extended-bindings)
  (not inline-primitives)
  (inlining-limit 0)
  (not safe)
  (fixnum)
  (block)
)

(c-declare "#include <stdio.h>") ;; to access puts

(let ()

   (define puts (c-lambda (char-string) int "puts"))

   (define (make-string k #!optional (f #\space))
     (##make-string k f))

   (define (substring-move! src-str src-start src-end dst-str dst-start)
     ;; Copy direction must be selected in case src-str and
     ;; dst-str are the same string.
     (if (fx< src-start dst-start)
         (let loop1 ((i (fx- src-end 1))
                     (j (fx- (fx+ dst-start (fx- src-end src-start))  
1)))
           (if (fx< i src-start)
               dst-str
               (begin
                 (string-set! dst-str j (string-ref src-str i))
                 (loop1 (fx- i 1)
                        (fx- j 1)))))
         (let loop2 ((i src-start)
                     (j dst-start))
           (if (fx< i src-end)
               (begin
                 (string-set! dst-str j (string-ref src-str i))
                 (loop2 (fx+ i 1)
                        (fx+ j 1)))
               dst-str))))

   (define (substring str start end)
     (substring-move!
      str
      start
      end
      (make-string (fxmax (fx- end start) 0))
      0))

   (define (append-strings lst)
     (let loop1 ((n 0)
                 (lst1 lst)
                 (lst2 '()))
       (if (pair? lst1)
           (let ((str (car lst1)))
             (loop1 (fx+ n (string-length str))
                    (cdr lst1)
                    (cons str lst2)))
           (let ((result (make-string n)))
             (let loop2 ((n n)
                         (lst2 lst2))
               (if (pair? lst2)
                   (let* ((str (car lst2))
                          (len (string-length str))
                          (new-n (fx- n len)))
                     (substring-move! str 0 len result new-n)
                     (loop2 new-n (cdr lst2)))
                   result))))))

   (define (string-append . lst)
     (append-strings lst))

   (define (append x y)
     (if (pair? x)
         (cons (car x) (append (cdr x) y))
         y))

   (define (fold kons knil lst)
     (let loop ((lst lst) (ans knil))
       (if (pair? lst)
           (loop (cdr lst) (kons (car lst) ans))
           ans)))

   (define (number->string n #!optional (b 10))
     (if (fx< n b)
         (substring "0123456789abcdef" n (fx+ n 1))
         (string-append
          (number->string (fxquotient n b) b)
          (number->string (fxmodulo n b) b))))

   (define (display obj)
     (cond ((string? obj)
            (puts obj))
           ((fixnum? obj)
            (puts (number->string obj)))
           (else
            (puts "<unknown object>"))))

   ;; ... put rest of Scheme library here ...
   ;; possibly a (include "scheme-lib.scm") for the whole thing

   ;; main program:

   (define (fib n)
     (if (fx< n 2)
         1
         (fx+ (fib (fx- n 1))
              (fib (fx- n 2)))))

   (display (fib 20))
)




More information about the Gambit-list mailing list