Renaming tools, adding -c option to automatically compile with chibi-ffi.

This commit is contained in:
Alex Shinn 2011-04-07 23:48:46 +09:00
parent 2cd95a04d3
commit 13cf6d24d5
5 changed files with 68 additions and 564 deletions

View file

@ -1,6 +1,6 @@
# -*- makefile-gmake -*- # -*- makefile-gmake -*-
.PHONY: all libs doc dist clean cleaner dist-clean install uninstall test checkdefs .PHONY: all libs dist clean cleaner dist-clean install uninstall test checkdefs
.PRECIOUS: %.c .PRECIOUS: %.c
# install configuration # install configuration
@ -17,8 +17,8 @@ MANDIR ?= $(PREFIX)/share/man/man1
DESTDIR ?= DESTDIR ?=
GENSTUBS ?= ./tools/genstubs.scm GENSTUBS ?= ./tools/chibi-ffi
GENSTATIC ?= ./tools/genstatic.scm GENSTATIC ?= ./tools/chibi-genstatic
######################################################################## ########################################################################
# system configuration - if not using GNU make, set PLATFORM and the # system configuration - if not using GNU make, set PLATFORM and the
@ -165,7 +165,7 @@ lib/chibi/ast$(SO): lib/chibi/ast.c $(INCLUDES)
lib/%$(SO): lib/%.c $(INCLUDES) lib/%$(SO): lib/%.c $(INCLUDES)
-$(CC) $(CLIBFLAGS) $(XCPPFLAGS) $(XCFLAGS) -o $@ $< -L. -lchibi-scheme -$(CC) $(CLIBFLAGS) $(XCPPFLAGS) $(XCFLAGS) -o $@ $< -L. -lchibi-scheme
%.html: %.scrbl tools/chibi-doc %.html: %.scrbl tools/chibi-doc chibi-scheme$(EXE)
$(CHIBI) tools/chibi-doc $< > $@ $(CHIBI) tools/chibi-doc $< > $@
doc: doc/chibi.html doc: doc/chibi.html
@ -240,7 +240,8 @@ test: chibi-scheme$(EXE)
install: chibi-scheme$(EXE) install: chibi-scheme$(EXE)
mkdir -p $(DESTDIR)$(BINDIR) mkdir -p $(DESTDIR)$(BINDIR)
cp chibi-scheme$(EXE) $(DESTDIR)$(BINDIR)/ cp chibi-scheme$(EXE) $(DESTDIR)$(BINDIR)/
cp tools/genstubs.scm $(DESTDIR)$(BINDIR)/ cp tools/chibi-ffi $(DESTDIR)$(BINDIR)/
cp tools/chibi-doc $(DESTDIR)$(BINDIR)/
mkdir -p $(DESTDIR)$(MODDIR) mkdir -p $(DESTDIR)$(MODDIR)
cp -r lib/* $(DESTDIR)$(MODDIR)/ cp -r lib/* $(DESTDIR)$(MODDIR)/
mkdir -p $(DESTDIR)$(INCDIR) mkdir -p $(DESTDIR)$(INCDIR)

449
README
View file

@ -6,435 +6,20 @@
http://synthcode.com/wiki/chibi-scheme/ http://synthcode.com/wiki/chibi-scheme/
Chibi-Scheme is a very small library intended for use as an extension
Chibi-Scheme is a very small but mostly complete R5RS Scheme and scripting language in C programs. In addition to support for
implementation using a reasonably fast custom VM. Chibi-Scheme tries lightweight VM-based threads, each VM itself runs in an isolated heap
as much as possible not to trade its small size by cutting corners, allowing multiple VMs to run simultaneously in different OS threads.
and provides full continuations, both low and high-level hygienic
macros based on syntactic-closures, string ports and exceptions. The default language is R5RS Scheme with support for additional
Chibi-Scheme is written in highly portable C and supports multiple languages such as JavaScript to be provided in future releases.
simultaneous VM instances to run. Scheme is chosen as a substrate because its first class continuations
and guaranteed tail-call optimization makes implementing other
------------------------------------------------------------------------ languages easy.
INSTALLING
To build on most platforms just run "make". This will provide a
To build, just run "make". This will provide a shared library shared library "libchibi-scheme", as well as a sample "chibi-scheme"
"libchibi-scheme", as well as a sample "chibi-scheme" command-line command-line repl.
repl. The "chibi-scheme-static" make target builds an equivalent
static executable. For more detailed documentation, run "make doc" and see the generated
"doc/chibi.html".
You can edit the file chibi/features.h for a number of settings,
mostly disabling features to make the executable smaller. You can
specify standard options directly as arguments to make, for example
make CFLAGS=-Os CPPFLAGS=-DSEXP_USE_NO_FEATURES=1
to optimize for size, or
make LDFLAGS=-L/usr/local/lib CPPFLAGS=-I/usr/local/include
to compile against a library installed in /usr/local.
By default Chibi uses a custom, precise, non-moving GC. You can link
against the Boehm conservative GC by editing the features.h file, or
directly from make with:
make SEXP_USE_BOEHM=1
To compile a static executable, use
make chibi-scheme-static SEXP_USE_DL=0
To compile a static executable with all C libraries statically
included, first you need to create a clibs.c file, which can be done
with:
make clibs.c
or edited manually. Be sure to run this with a non-static
chibi-scheme. Then you can make the static executable with:
make cleaner
make chibi-scheme-static SEXP_USE_DL=0 CPPFLAGS=-DSEXP_USE_STATIC_LIBS
------------------------------------------------------------------------
CHIBI-SCHEME LANGUAGE
The default language is mostly compatible with the R5RS, with all
differences made by design, not through difficulty of implementation.
The following procedures are omitted:
transcript-on and transcript-off (because they're silly)
rationalize (pending the addition of rational numbers)
Apart from this, chibi-scheme is case-sensitive, unlike the R5RS.
The default configuration includes fixnums, flonums and bignums
but no exact rationals or complex numbers.
Full continuations are supported, but currently continuations don't
take C code into account. The only higher-order C functions in the
standard environment are LOAD and EVAL.
LOAD is extended to accept an optional environment argument, like
EVAL. You can also LOAD shared libraries in addition to Scheme source
files - in this case the function sexp_init_library is automatically
called with the following signature:
sexp_init_library(sexp context, sexp environment)
SYNTAX-RULES macros are provided by default, with the extensions from
SRFI-46. In addition, low-level hygienic macros are provided with
a syntactic-closures interface, including SC-MACRO-TRANSFORMER,
RSC-MACRO-TRANSFORMER, and ER-MACRO-TRANSFORMER. A good introduction
to syntactic-closures can be found at:
http://community.schemewiki.org/?syntactic-closures
IDENTIFIER?, IDENTIFIER->SYMBOL, IDENTIFIER=?, and
MAKE-SYNTACTIC-CLOSURE and STRIP-SYNTACTIC-CLOSURES are provided.
SRFI-0's COND-EXPAND is provided, with the feature `chibi'.
STRING-CONCATENATE concatenates a list of strings.
------------------------------------------------------------------------
TYPES
You can define new data types with SRFI-9. This is just syntactic
sugar for the following more primitive type constructors:
(register-simple-type <name-string> <num-fields>)
=> <type-id> ; a fixnum
(make-type-predicate <opcode-name-string> <type-id>)
=> <opcode> ; takes 1 arg, returns #t iff that arg is of the type
(make-constructor <constructor-name-string> <type-id>)
=> <opcode> ; takes 0 args, returns a newly allocated instance of type
(make-getter <getter-name-string> <type-id> <field-index>)
=> <opcode> ; takes 1 args, retrieves the field located at the index
(make-setter <setter-name-string> <type-id> <field-index>)
=> <opcode> ; takes 2 args, sets the field located at the index
------------------------------------------------------------------------
MODULE SYSTEM
A configurable module system, in the style of the Scheme48 module
system, is provided by default.
Modules names are hierarchical lists of symbols or numbers. The
definition of the module (foo bar baz) is searched for in the file
foo/bar/baz.module. This file should contain an expression of the
form:
(define-module (foo bar baz)
<module-declarations> ...)
where <module-declarations> can be any of
(export <id> ...) - specify an export list
(import <import-spec> ...) - specify one or more imports
(import-immutable <import-spec> ...) - specify an immutable import
(body <expr> ...) - inline Scheme code
(include <file> ...) - load one or more files
(include-shared <file> ...) - dynamic load a library
<import-spec> can either be a module name or any of
(only <import-spec> <id> ...)
(except <import-spec> <id> ...)
(rename <import-spec> (<from-id> <to-id>) ...)
(prefix <prefix-id> <import-spec>)
The can be composed and perform basic selection and renaming of
individual identifiers from the given module.
Files are loaded relative to the .module file, and are written with
their extension (so you can use whatever suffix you prefer - .scm,
.ss, .sls, etc.).
Shared modules, on the other hand, should be specified _without_ the
extension - the correct suffix will be added portably (e.g. .so for
Unix and .dylib for OS X).
You may also use COND-EXPAND and arbitrary macro expansions in a
module definition to generate <module-declarations>.
------------------------------------------------------------------------
MODULES
The default environment is (scheme) - you almost always want to import
this.
Currently you can load the following SRFIs with (import (srfi N)):
(srfi 0) - cond-expand
(srfi 1) - list library
(srfi 2) - and-let*
(srfi 6) - basic string ports
(srfi 8) - receive
(srfi 9) - define-record-type
(srfi 11) - let-values/let*-values
(srfi 16) - case-lambda
(srfi 22) - running scheme scripts on Unix
(srfi 23) - error reporting mechanism
(srfi 26) - cut/cute partial application
(srfi 27) - sources of random bits
(srfi 33) - bitwise operators
(srfi 39) - prameter objects
(srfi 46) - basic syntax-rules extensions
(srfi 62) - s-expression comments
(srfi 69) - basic hash tables
(srfi 95) - sorting and merging
(srfi 98) - environment access
although 0, 22, 23, 46 and 62 are built into the default environment
so there's no need to import them.
Included non-standard modules are put in the (chibi) module namespace.
The following additional modules are available:
(chibi net) - networking interface
(chibi filesystem) - local filesystem and file descriptor interface
(chibi process) - processes and signals
(chibi system) - host system and user information
(chibi time) - time and date library
(chibi match) - pattern-matching library
(chibi loop) - extensible loop syntax
(chibi pathname) - pathname manipulation utilities
(chibi uri) - URI parsing and construction utilities
(chibi macroexpand) - macro expansion utility
(chibi ast) - interface to the internal Abstract Syntax Tree
(chibi disasm) - disassembly utility for the chibi VM
(chibi heap-stats) - debugging tool to analyze or dump the heap
------------------------------------------------------------------------
C INTERFACE
See the file main.c for an example of using chibi-scheme as a library.
The basic usage involves creating a context for evaluation and loading
or evaluating Scheme source with it. Begin by including the eval.h
header file:
#include <chibi/eval.h>
then call
sexp_scheme_init();
with no parameters to initialize any globals (this actually does
nothing in the standard configuration but is a good idea to call
anyway).
Then you can use the following to create and manipulate contexts:
sexp_make_eval_context(context, stack, environment, heap_size)
Creates a new context with the given stack and environment.
If context is non-NULL, this will be the "parent" context and
the two contexts will share a heap. Otherwise, a new heap
will be allocated with heap_size, or a default size if heap_size
is zero. stack and environment may both also be NULL (and _must_
be NULL if context is NULL) and will be given standard defaults.
Thus to create your first context you generally call:
sexp_make_eval_context(NULL, NULL, NULL, 0)
You can create as many contexts as you want, and other than those
sharing a heap they are all independent and thread-safe.
sexp_load_standard_env(context, env, version)
Loads the init.scm file in the environment env. Version refers
to the RnRS version number and should always be SEXP_FIVE. The
environment created with sexp_make_eval_context only contains
core syntactic forms and C primitives (thus for example it has
CAR but not CADR or LIST), so to get a full featured
environment, plus a module system with which to load additional
modules, you want to use this.
sexp_destroy_context(context)
Signals that you no longer need context, or any other context
sharing the heap. It will thus free() the context and heap and
all associated memory. Does nothing if using the Boehm GC.
Environments can be handled with the following:
sexp_context_env(context)
A macro returning the default environment associated with context.
sexp_env_define(context, env, symbol, value)
Define a variable in an environment.
sexp_env_ref(env, symbol, dflt)
Fetch the binding for symbol from the environment env,
returning the default dflt if the symbol is unbound.
You can evaluate code with the following utility:
sexp_eval(context, expr, env)
Evaluates an s-expression in an environment.
env can be NULL to use the context's default env.
sexp_eval_string(context, str, env)
Reads an s-expression from str and evaluates it in env.
sexp_load(context, file, env)
Read and eval all top-level forms from file in environment env.
As described in LOAD above, file may be a shared library.
To define new primitive functions from C, use sexp_define_foreign,
which takes a Scheme environment, a name, a number of arguments the C
function takes (not counting the context argument), and a C function.
/* sexp_define_foreign(context, env, name, num_args, f) */
sexp add (sexp context, sexp x, sexp y) {
return sexp_fx_add(x, y);
}
sexp_define_foreign(context, env, "add", 2, add);
You can also define functions with a single optional argument:
sexp_define_foreign_opt(context, env, "add", 2, add, sexp_make_fixnum(1));
See the SRFI-69 implementation for more detailed examples of this.
------------------------------------------------------------------------
FFI
Simple C FFI. "genstubs.scm file.stub" will read in the C function
FFI definitions from file.stub and output the appropriate C
wrappers into file.c. You can then compile that file with:
cc -fPIC -shared file.c -lchibi-scheme
(or using whatever flags are appropriate to generate shared libs on
your platform) and then the generated .so file can be loaded
directly with LOAD, or portably using (include-shared "file") in a
module definition (note that include-shared uses no suffix).
The goal of this interface is to make access to C types and
functions easy, without requiring the user to write any C code.
That means the stubber needs to be intelligent about various C
calling conventions and idioms, such as return values passed in
actual parameters. Writing C by hand is still possible, and
several of the core modules provide C interfaces directly without
using the stubber.
================================
Struct Interface
(define-c-struct struct-name
[predicate: predicate-name]
[constructor: constructor-name]
[finalizer: c_finalizer_name]
(type c_field_name getter-name setter-name) ...)
================================
Function Interface
(define-c return-type name-spec (arg-type ...))
where name-space is either a symbol name, or a list of
(scheme-name c_name). If just a symbol, the C name is taken
to be the same with -'s replaced by _'s.
arg-type is a type suitable for input validation and conversion.
================================
Types
Types
Basic Types
void
boolean
char
sexp (no conversions)
Integer Types:
signed-char short int long
unsigned-char unsigned-short unsigned-int unsigned-long size_t pid_t
time_t (in seconds, but using the chibi epoch of 2010/01/01)
errno (as a return type returns #f on error)
Float Types:
float double long-double
String Types:
string - a null-terminated char*
env-string - a VAR=VALUE string represented as a (VAR . VALUE) pair inScheme
in addition you can use (array char) as a string
Port Types:
input-port output-port
Struct Types:
Struct types are by default just referred to by the bare
struct-name from define-c-struct, and it is assumed you want a
pointer to that type. To refer to the full struct, use the struct
modifier, as in (struct struct-name).
Type modifiers
Any type may also be written as a list of modifiers followed by the
type itself. The supported modifiers are:
const: prepends the "const" C type modifier
* as a return or result parameter, makes non-immediates immutable
free: it's Scheme's responsibility to "free" this resource
* as a return or result parameter, registers the freep flag
this causes the type finalizer to be run when GCed
maybe-null: this pointer type may be NULL
* as a result parameter, NULL is translated to #f
normally this would just return a wrapped NULL pointer
* as an input parameter, #f is translated to NULL
normally this would be a type error
pointer: create a pointer to this type
* as a return parameter, wraps the result in a vanilla cpointer
* as a result parameter, boxes then unboxes the value
struct: treat this struct type as a struct, not a pointer
* as an input parameter, dereferences the pointer
* as a type field, indicates a nested struct
link: add a gc link
* as a field getter, link to the parent object, so the
parent won't be GCed so long as we have a reference
to the child. this behavior is automatic for nested
structs.
result: return a result in this parameter
* if there are multiple results (including the return type),
they are all returned in a list
* if there are any result parameters, a return type
of errno returns #f on failure, and as eliminated
from the list of results otherwise
(value <expr>): specify a fixed value
* as an input parameter, this parameter is not provided
in the Scheme API but always passed as <expr>
(default <expr>): specify a default value
* as the final input parameter, makes the Scheme parameter
optional, defaulting to <expr>
(array <type> [<length>]) an array type
* length must be specified for return and result parameters
* if specified, length can be any of
** an integer, for a fixed size
** the symbol null, indicating a NULL-terminated array

View file

@ -1 +1 @@
0.3 0.4

View file

@ -3,7 +3,7 @@
;; Note: this evolved as a throw-away script to provide certain core ;; Note: this evolved as a throw-away script to provide certain core
;; modules, and so is a mess. Tread carefully. ;; modules, and so is a mess. Tread carefully.
;; Simple C FFI. "genstubs.scm file.stub" will read in the C function ;; Simple C FFI. "chibi-ffi file.stub" will read in the C function
;; FFI definitions from file.stub and output the appropriate C ;; FFI definitions from file.stub and output the appropriate C
;; wrappers into file.c. You can then compile that file with: ;; wrappers into file.c. You can then compile that file with:
;; ;;
@ -13,6 +13,9 @@
;; your platform) and then the generated .so file can be loaded ;; your platform) and then the generated .so file can be loaded
;; directly with load, or portably using (include-shared "file") in a ;; directly with load, or portably using (include-shared "file") in a
;; module definition (note that include-shared uses no suffix). ;; module definition (note that include-shared uses no suffix).
;;
;; Passing the -c/--compile option will attempt to compile the .so
;; file in a single step.
;; The goal of this interface is to make access to C types and ;; The goal of this interface is to make access to C types and
;; functions easy, without requiring the user to write any C code. ;; functions easy, without requiring the user to write any C code.
@ -22,119 +25,6 @@
;; several of the core modules provide C interfaces directly without ;; several of the core modules provide C interfaces directly without
;; using the stubber. ;; using the stubber.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Struct Interface
;;
;; (define-c-struct struct-name
;; [predicate: predicate-name]
;; [constructor: constructor-name]
;; [finalizer: c_finalizer_name]
;; (type c_field_name getter-name setter-name) ...)
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Function Interface
;;
;; (define-c return-type name-spec (arg-type ...))
;;
;; where name-space is either a symbol name, or a list of
;; (scheme-name c_name). If just a symbol, the C name is taken
;; to be the same with -'s replaced by _'s.
;;
;; arg-type is a type suitable for input validation and conversion.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Types
;;
;; Types
;;
;; Basic Types
;; void
;; boolean
;; char
;; sexp (no conversions)
;;
;; Integer Types:
;; signed-char short int long
;; unsigned-char unsigned-short unsigned-int unsigned-long size_t pid_t
;; time_t (in seconds, but using the chibi epoch of 2010/01/01)
;; errno (as a return type returns #f on error)
;;
;; Float Types:
;; float double long-double
;;
;; String Types:
;; string - a null-terminated char*
;; env-string - a VAR=VALUE string represented as a (VAR . VALUE) pair inScheme
;; in addition you can use (array char) as a string
;;
;; Port Types:
;; input-port output-port
;; port-or-fd - an fd-backed port or a fixnum
;;
;; Struct Types:
;;
;; Struct types are by default just referred to by the bare
;; struct-name from define-c-struct, and it is assumed you want a
;; pointer to that type. To refer to the full struct, use the struct
;; modifier, as in (struct struct-name).
;; Type modifiers
;;
;; Any type may also be written as a list of modifiers followed by the
;; type itself. The supported modifiers are:
;;
;; const: prepends the "const" C type modifier
;; * as a return or result parameter, makes non-immediates immutable
;;
;; free: it's Scheme's responsibility to "free" this resource
;; * as a return or result parameter, registers the freep flag
;; this causes the type finalizer to be run when GCed
;;
;; maybe-null: this pointer type may be NULL
;; * as a result parameter, NULL is translated to #f
;; normally this would just return a wrapped NULL pointer
;; * as an input parameter, #f is translated to NULL
;; normally this would be a type error
;;
;; pointer: create a pointer to this type
;; * as a return parameter, wraps the result in a vanilla cpointer
;; * as a result parameter, boxes then unboxes the value
;;
;; struct: treat this struct type as a struct, not a pointer
;; * as an input parameter, dereferences the pointer
;; * as a type field, indicates a nested struct
;;
;; link: add a gc link
;; * as a field getter, link to the parent object, so the
;; parent won't be GCed so long as we have a reference
;; to the child. this behavior is automatic for nested
;; structs.
;;
;; result: return a result in this parameter
;; * if there are multiple results (including the return type),
;; they are all returned in a list
;; * if there are any result parameters, a return type
;; of errno returns #f on failure, and as eliminated
;; from the list of results otherwise
;;
;; (value <expr>): specify a fixed value
;; * as an input parameter, this parameter is not provided
;; in the Scheme API but always passed as <expr>
;;
;; (default <expr>): specify a default value
;; * as the final input parameter, makes the Scheme parameter
;; optional, defaulting to <expr>
;;
;; (array <type> [<length>]) an array type
;; * length must be specified for return and result parameters
;; * if specified, length can be any of
;; ** an integer, for a fixed size
;; ** the symbol null, indicating a NULL-terminated array
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; globals ;; globals
@ -336,10 +226,20 @@
((eqv? c (string-ref str i)) (lp (+ i 1) (+ i 1) (cons r (collect)))) ((eqv? c (string-ref str i)) (lp (+ i 1) (+ i 1) (cons r (collect))))
(else (lp from (+ i 1) res)))))) (else (lp from (+ i 1) res))))))
(define (string-split str c . o)
(let ((start (if (pair? o) (car o) 0))
(end (string-length str)))
(let lp ((from start) (i start) (res '()))
(define (collect) (if (= i from) res (cons (substring str from i) res)))
(cond
((>= i end) (reverse (collect)))
((eqv? c (string-ref str i)) (lp (+ i 1) (+ i 1) (collect)))
(else (lp from (+ i 1) res))))))
(define (string-scan c str . o) (define (string-scan c str . o)
(let ((limit (string-length str))) (let ((end (string-length str)))
(let lp ((i (if (pair? o) (car o) 0))) (let lp ((i (if (pair? o) (car o) 0)))
(cond ((>= i limit) #f) (cond ((>= i end) #f)
((eqv? c (string-ref str i)) i) ((eqv? c (string-ref str i)) i)
(else (lp (+ i 1))))))) (else (lp (+ i 1)))))))
@ -1288,13 +1188,31 @@
;; main ;; main
(define (main args) (define (main args)
(case (length args) (let* ((compile? (and (pair? args) (member (car args) '("-c" "--compile"))))
((1) (args (if compile? (cdr args) args))
(with-output-to-file (string-append (strip-extension (car args)) ".c") (cflags (if (and (pair? args) (member (car args) '("-f" "--flags")))
(lambda () (generate (car args))))) (string-split (cadr args) " ")
((2) #f))
(if (equal? "-" (cadr args)) (args (if cflags (cddr args) args))
(generate (car args)) (src (car args))
(with-output-to-file (cadr args) (lambda () (generate (car args)))))) (dest
(else (case (length args)
(error "usage: genstubs <file.stub> [<output.c>]")))) ((1) (string-append (strip-extension src) ".c"))
((2) (cadr args))
(else (error "usage: chibi-ffi [-c] <file.stub> [<output.c>]")))))
(if (equal? "-" dest)
(generate src)
(with-output-to-file dest (lambda () (generate src))))
(cond
((and compile? (not (equal? "-" dest)))
;; This has to use `eval' for bootstrapping, since we need
;; chibi-ffi to compile to (chibi process) module.
(let* ((so (string-append (strip-extension src) *shared-object-extension*))
(system (begin (eval '(import (chibi process)))
(eval 'system)))
(base-args (append (or cflags '())
`("-o" ,so ,dest "-lchibi-scheme")))
(args (cond-expand
(macosx (append '("-dynamiclib" "-Oz") base-args))
(else (append '("-fPIC" "-shared" "-Os") base-args)))))
(apply system "cc" args))))))