|
- (provide 'cload.scm)
-
- ;;; --------------------------------------------------------------------------------
- ;;; automatically link a C function into s7 (there are a bunch of examples below)
- ;;; (c-define '(double j0 (double)) "m" "math.h")
- ;;; means link the name m:j0 to the math library function j0 passing a double arg and getting a double result (reals in s7)
- ;;;
- ;;; (c-define c-info prefix headers cflags ldflags)
- ;;; prefix is some arbitrary prefix (it can be "") that you want prepended to various names.
- ;;; headers is a list of headers (as strings) that the c-info relies on, (("math.h") for example).
- ;;; cflags are any special C compiler flags that are needed ("-I." in particular).
- ;;; ldflags is the similar case for the loader.
- ;;; c-info is a list that describes the C entities that you want to tie into s7.
- ;;; it can be either one list describing one entity, or a list of such lists.
- ;;; Each description has the form: (return-type entity-name-in-C (argument-type...))
- ;;; where each entry is a symbol, and C names are used throughout. So, in the j0
- ;;; example above, (double j0 (double)) says we want access to j0, it returns
- ;;; a C double, and takes one argument, also a C double. s7 tries to figure out
- ;;; what the corresponding s7 type is, but in tricky cases, you should tell it
- ;;; by replacing the bare type name with a list: (C-type underlying-C-type). For example,
- ;;; the Snd function set_graph_style takes an (enum) argument of type graph_style_t.
- ;;; This is actually an int, so we use (graph_style_t int) as the type:
- ;;; (void set_graph_style ((graph_style_t int)))
- ;;; If the C entity is a constant, then the descriptor list has just two entries,
- ;;; the C-type and the entity name: (int F_OK) for example. The entity name can also be a list
- ;;; (an enum listing for example).
- ;;; If the C type has a space ("struct tm*" for example), use (symbol "struct tm*")
- ;;; to construct the corresponding symbol.
- ;;; The entity is placed in the current s7 environment under the name (string-append prefix ":" name)
- ;;; where the ":" is omitted if the prefix is null. So in the j0 example, we get in s7 the function m:j0.
- ;;;
- ;;; some examples:
- ;;;
- ;;; (c-define '((double j0 (double))
- ;;; (double j1 (double))
- ;;; (double erf (double))
- ;;; (double erfc (double))
- ;;; (double lgamma (double)))
- ;;; "m" "math.h")
- ;;;
- ;;;
- ;;; (c-define '(char* getenv (char*)))
- ;;; (c-define '(int setenv (char* char* int)))
- ;;; (define get-environment-variable (let () (c-define '(char* getenv (char*))) getenv))
- ;;;
- ;;; (define file-exists? (let () (c-define '((int F_OK) (int access (char* int))) "" "unistd.h") (lambda (arg) (= (access arg F_OK) 0))))
- ;;; (define delete-file (let () (c-define '(int unlink (char*)) "" "unistd.h") (lambda (file) (= (unlink file) 0)))) ; 0=success, -1=failure
- ;;;
- ;;;
- ;;; these pick up Snd stuff:
- ;;; (c-define '(char* version_info ()) "" "snd.h" "-I.")
- ;;; (c-define '(mus_float_t mus_degrees_to_radians (mus_float_t)) "" "snd.h" "-I.")
- ;;;
- ;;; (c-define '(snd_info* any_selected_sound ()) "" "snd.h" "-I.")
- ;;; (c-define '(void select_channel (snd_info* int)) "" "snd.h" "-I.")
- ;;; (c-define '(((graph_style_t int) (GRAPH_LINES GRAPH_DOTS GRAPH_FILLED GRAPH_DOTS_AND_LINES GRAPH_LOLLIPOPS))
- ;;; (void set_graph_style ((graph_style_t int))))
- ;;; "" "snd.h" "-I.")
- ;;;
- ;;;
- ;;; (c-define '(char* getcwd (char* size_t)) "" "unistd.h")
- ;;; :(let ((str (make-string 32))) (getcwd str 32) str)
- ;;; "/home/bil/cl\x00 "
- ;;; so it works in a sense -- there is a memory leak here
- ;;;
- ;;;
- ;;; (c-define (list '(void* calloc (size_t size_t))
- ;;; '(void* malloc (size_t))
- ;;; '(void free (void*))
- ;;; '(void* realloc(void* size_t))
- ;;; '(void time (time_t*)) ; ignore returned value
- ;;; (list (symbol "struct tm*") 'localtime '(time_t*))
- ;;; (list 'size_t 'strftime (list 'char* 'size_t 'char* (symbol "struct tm*"))))
- ;;; "" "time.h")
- ;;; > (let ((p (calloc 1 8)) (str (make-string 32))) (time p) (strftime str 32 "%a %d-%b-%Y %H:%M %Z" (localtime p)) (free p) str)
- ;;; "Sat 11-Aug-2012 08:55 PDT\x00 "
- ;;;
- ;;;
- ;;; (c-define '((int closedir (DIR*))
- ;;; (DIR* opendir (char*))
- ;;; (in-C "static char *read_dir(DIR *p) \
- ;;; { \
- ;;; struct dirent *dirp; \
- ;;; dirp = readdir(p); \
- ;;; if (!dirp) return(NULL); \
- ;;; else return(dirp->d_name); \
- ;;; }")
- ;;; (char* read_dir (DIR*)))
- ;;; "" '("sys/types.h" "dirent.h"))
- ;;;
- ;;; (let ((dir (opendir "/home/bil/gtk-snd")))
- ;;; (do ((p (read_dir dir) (read_dir dir)))
- ;;; ((= (length p) 0))
- ;;; (format *stderr* "~A " p))
- ;;; (closedir dir))
- ;;;
- ;;; (define (memory-usage)
- ;;; (with-let *libc*
- ;;; (let ((v (rusage.make)))
- ;;; (getrusage RUSAGE_SELF v)
- ;;; (let ((mem (rusage.ru_maxrss v)))
- ;;; (free v)
- ;;; (* 1024 mem)))))
- ;;; --------------------------------------------------------------------------------
-
- (define *cload-cflags* "")
- (define *cload-ldflags* "")
- (if (not (defined? '*cload-directory*))
- (define *cload-directory* ""))
-
-
- (define-macro (defvar name value)
- `(if (not (defined? ',name))
- (define ,name ,value)))
-
- (defvar c-define-output-file-counter 0) ; ugly, but I can't find a way around this (dlopen/dlsym stupidity)
-
-
- ;;; to place the new function in the caller's current environment, we need to pass the environment in explicitly:
- (define-macro (c-define . args)
- `(c-define-1 (curlet) ,@args))
-
-
- (define* (c-define-1 cur-env function-info (prefix "") (headers ()) (cflags "") (ldflags "") output-name)
- ;; write a C shared library module that links in the functions in function-info
- ;; function info is either a list: (return-type c-name arg-type) or a list thereof
- ;; the new functions are placed in cur-env
-
- (define handlers (list '(integer s7_is_integer s7_integer s7_make_integer s7_int)
- '(boolean s7_is_boolean s7_boolean s7_make_boolean bool)
- '(real s7_is_real s7_number_to_real s7_make_real s7_double)
-
- ;; '(complex s7_is_complex #f s7_make_complex s7_Complex)
- ;; the typedef is around line 6116 in s7.c, but we also need s7_complex which requires the s7_Complex type
- ;; xen.h uses (s7_real_part(a) + s7_imag_part(a) * _Complex_I) instead since c++ won't let use define s7_Complex in s7.h
-
- '(string s7_is_string s7_string s7_make_string char*)
- (list 'character 's7_is_character 's7_character 's7_make_character (symbol "unsigned char"))
- '(c_pointer s7_is_c_pointer s7_c_pointer s7_make_c_pointer void*)
- '(s7_pointer #f #f #f s7_pointer)
- ))
-
- (define (C-type->s7-type type)
-
- (if (pair? type) ; in case the type name does not make its C type obvious: (graph_style_t int)
- (C-type->s7-type (cadr type))
- (let ((type-name (symbol->string type)))
- (cond ((string-position "**" type-name) ; any complicated C pointer is uninterpreted
- 'c_pointer)
-
- ((string=? "s7_pointer" type-name)
- 's7_pointer)
-
- ((string-position "char*" type-name) ; but not char** (caught above)
- 'string)
-
- ((or (string-position "*" type-name) ; float* etc
- (string-position "pointer" type-name))
- 'c_pointer)
-
- ((assoc type-name '(("char" . character)
- ("bool" . boolean)) string-position)
- => cdr)
-
- ;; ((string-position "complex" type-name)
- ;; 'complex) ; double complex or complex double (mus_edot_product in clm.c uses the latter)
-
- ((or (string-position "float" type-name)
- (string-position "double" type-name))
- 'real)
-
- ((or (string-position "int" type-name)
- (string-position "long" type-name) ; assuming not "long double" here so we need to look for it first (above)
- (string-position "short" type-name)
- (string-position "size" type-name)
- (string-position "byte" type-name))
- 'integer)
-
- (#t #t)))))
-
- (define (find-handler type choice)
- (cond ((assq (C-type->s7-type type) handlers) => choice) (else #t)))
-
- (define (C->s7-cast type)
- (find-handler type (lambda (p) (list-ref p 4))))
-
- (define (C->s7 type)
- (find-handler type cadddr))
-
- (define (s7->C type)
- (find-handler type caddr))
-
- (define (checker type)
- (find-handler type cadr))
-
- (define* (cload->signature type rtn)
- (case (C-type->s7-type type)
- ((real) (if rtn 'float? 'real?))
- ((integer) 'integer?)
- ((string) 'string?)
- ((boolean) 'boolean?)
- ((character) 'char?)
- ((c_pointer) 'c-pointer?)
- (else #t)))
-
- (define (signature->pl type)
- (case type
- ((integer?) #\i)
- ((boolean?) #\b)
- ((real?) #\r)
- ((float?) #\d)
- ((char?) #\c)
- ((string?) #\s)
- ((c-pointer?) #\x)
- (else #\t)))
-
- (set! c-define-output-file-counter (+ c-define-output-file-counter 1))
-
- (let ((file-name (string-append *cload-directory* (or output-name (format #f "temp-s7-output-~D" c-define-output-file-counter)))))
- (let ((c-file-name (string-append file-name ".c"))
- (o-file-name (string-append file-name ".o"))
- (so-file-name (string-append file-name ".so"))
- (init-name (if (string? output-name)
- (string-append output-name "_init")
- (string-append "init_" (number->string c-define-output-file-counter))))
- (functions ())
- (constants ())
- (macros ()) ; these are protected by #ifdef ... #endif
- (inits ()) ; C code (a string in s7) inserted in the library initialization function
- (p #f)
- (if-funcs ()) ; if-functions (guaranteed to return int, so we can optimize away make-integer etc)
- (rf-funcs ()) ; rf-functions
- (sig-symbols (list (cons 'integer? 0) (cons 'boolean? 0) (cons 'real? 0) (cons 'float? 0)
- (cons 'char? 0) (cons 'string? 0) (cons 'c-pointer? 0) (cons 't 0)))
- (signatures (make-hash-table)))
-
- (define (make-signature rtn args)
-
- (define (compress sig)
- (if (and (pair? sig)
- (pair? (cdr sig))
- (eq? (car sig) (cadr sig)))
- (compress (cdr sig))
- sig))
-
- (let ((sig (list (cload->signature rtn #t)))
- (cyclic #f))
- (for-each
- (lambda (arg)
- (set! sig (cons (cload->signature arg) sig)))
- args)
- (let ((len (length sig)))
- (set! sig (compress sig))
- (set! cyclic (not (= len (length sig)))))
- (set! sig (reverse sig))
- (unless (signatures sig) ; it's not in our collection yet
- (let ((pl (make-string (+ (if cyclic 4 3) (length sig))))
- (loc (if cyclic 4 3)))
- (set! (pl 0) #\p)
- (if cyclic
- (begin (set! (pl 1) #\c) (set! (pl 2) #\l) (set! (pl 3) #\_))
- (begin (set! (pl 1) #\l) (set! (pl 2) #\_)))
- (for-each
- (lambda (typer)
- (set! (pl loc) (signature->pl typer))
- (let ((count (or (assq typer sig-symbols)
- (assq 't sig-symbols))))
- (set-cdr! count (+ (cdr count) 1)))
- (set! loc (+ loc 1)))
- sig)
- (set! (signatures sig) pl)))
- sig))
-
- (define (initialize-c-file)
- ;; C header stuff
- (set! p (open-output-file c-file-name))
- (format p "#include <stdlib.h>~%")
- (format p "#include <stdio.h>~%")
- (format p "#include <string.h>~%")
- (if (string? headers)
- (format p "#include <~A>~%" headers)
- (for-each
- (lambda (header)
- (format p "#include <~A>~%" header))
- headers))
- (format p "#include \"s7.h\"~%~%"))
-
- (define collides?
- (let ((all-names ()))
- (lambda (name)
- (if (memq name all-names)
- (format *stderr* "~A twice?~%" name)
- (set! all-names (cons name all-names)))
- name)))
-
- (define* (add-one-function return-type name arg-types doc)
- ;; (format *stderr* "~A ~A ~A~%" return-type name arg-types): double j0 (double) for example
- ;; C function -> scheme
- (let ((func-name (symbol->string (collides? name))))
- (let ((num-args (length arg-types))
- (base-name (string-append (if (> (length prefix) 0) prefix "s7_dl") "_" func-name)) ; not "g" -- collides with glib
- (scheme-name (string-append prefix (if (> (length prefix) 0) ":" "") func-name)))
-
- (if (and (= num-args 1)
- (eq? (car arg-types) 'void))
- (set! num-args 0))
- (format p "~%/* -------- ~A -------- */~%" func-name)
- (format p "static s7_pointer ~A(s7_scheme *sc, s7_pointer args)~%" base-name)
- (format p "{~%")
-
- ;; get the Scheme args, check their types, assign to local C variables
- (when (positive? num-args)
- (format p " s7_pointer arg;~%")
- (do ((i 0 (+ i 1))
- (type arg-types (cdr type)))
- ((= i num-args))
- (format p " ~A ~A_~D;~%" ((if (pair? (car type)) caar car) type) base-name i))
- (format p " arg = args;~%")
- (do ((i 0 (+ i 1))
- (type arg-types (cdr type)))
- ((= i num-args))
-
- (let* ((nominal-type ((if (pair? (car type)) caar car) type)) ; double in the example
- (true-type ((if (pair? (car type)) cadar car) type))
- (s7-type (C-type->s7-type true-type))) ; real
- (if (eq? true-type 's7_pointer)
- (format p " ~A_~D = s7_car(arg);~%" base-name i)
- (begin
- (format p " if (~A(s7_car(arg)))~%" (checker true-type))
- (format p " ~A_~D = (~A)~A(~As7_car(arg));~%"
- base-name i
- nominal-type
- (s7->C true-type) ; s7_number_to_real which requires
- (if (memq s7-type '(boolean real)) ; the extra sc arg
- "sc, " ""))
- (format p " else return(s7_wrong_type_arg_error(sc, ~S, ~D, s7_car(arg), ~S));~%"
- func-name
- (if (= num-args 1) 0 (+ i 1))
- (if (symbol? s7-type)
- (symbol->string s7-type)
- (error 'bad-arg (format #f "in ~S, ~S is not a symbol~%" name s7-type))))))
- (if (< i (- num-args 1))
- (format p " arg = s7_cdr(arg);~%")))))
-
- ;; return C value to Scheme
- (if (pair? return-type)
- (set! return-type (cadr return-type)))
- (let ((return-translator (C->s7 return-type)))
- (format p " ")
- (if (not (eq? return-translator #t))
- (format p "return("))
- (if (symbol? return-translator)
- (format p "~A(sc, (~A)" return-translator (C->s7-cast return-type)))
- (format p "~A(" func-name)
- (do ((i 0 (+ i 1)))
- ((>= i (- num-args 1)))
- (format p "~A_~D, " base-name i))
- (if (positive? num-args)
- (format p "~A_~D" base-name (- num-args 1)))
- (format p ")")
- (if (symbol? return-translator)
- (format p ")"))
- (format p (if (not (eq? return-translator #t))
- ");~%"
- ";~% return(s7_unspecified(sc));~%"))
- (format p "}~%"))
-
- ;; add optimizer connection
- (when (and (eq? return-type 'double) ; double (f double) -- s7_rf_t: double f(s7, s7_pointer **p)
- (eq? (car arg-types) 'double)
- (or (= num-args 1)
- (and (= num-args 2) ; double (f double double)
- (eq? (cadr arg-types) 'double))))
- (set! rf-funcs (cons (cons func-name scheme-name) rf-funcs))
- (format p (if (= num-args 1)
- "static s7_double ~A_rf_r(s7_scheme *sc, s7_pointer **p)~
- {s7_rf_t f; s7_double x; f = (s7_rf_t)(**p); (*p)++; x = f(sc, p); return(~A(x));}~%"
- "static s7_double ~A_rf_r(s7_scheme *sc, s7_pointer **p)~% ~
- {s7_rf_t f; s7_double x, y; f = (s7_rf_t)(**p); (*p)++; x = f(sc, p); f = (s7_rf_t)(**p); (*p)++; y = f(sc, p); return(~A(x, y));}~%")
- func-name func-name)
- (format p "static s7_rf_t ~A_rf(s7_scheme *sc, s7_pointer expr) ~
- {if (s7_arg_to_rf(sc, s7_cadr(expr))) return(~A_rf_r); return(NULL);}~%"
- func-name func-name))
-
- (when (and (eq? return-type 'int) ; int (f int|double|void)
- (memq (car arg-types) '(int double void))
- (<= num-args 1))
- (set! if-funcs (cons (cons func-name scheme-name) if-funcs))
- (case (car arg-types)
- ((double)
- (format p "static s7_int ~A_if_r(s7_scheme *sc, s7_pointer **p)~
- {s7_rf_t f; s7_double x; f = (s7_rf_t)(**p); (*p)++; x = f(sc, p); return(~A(x));}~%"
- func-name func-name)
- (format p "static s7_if_t ~A_if(s7_scheme *sc, s7_pointer expr) ~
- {if (s7_arg_to_if(sc, s7_cadr(expr))) return(~A_if_r); return(NULL);}~%"
- func-name func-name))
- ((int)
- (format p "static s7_int ~A_if_i(s7_scheme *sc, s7_pointer **p)~
- {s7_if_t f; s7_int x; f = (s7_if_t)(**p); (*p)++; x = f(sc, p); return(~A(x));}~%"
- func-name (if (string=? func-name "abs") "llabs" func-name))
- (format p "static s7_if_t ~A_if(s7_scheme *sc, s7_pointer expr) ~
- {if (s7_arg_to_if(sc, s7_cadr(expr))) return(~A_if_i); return(NULL);}~%"
- func-name func-name))
- ((void)
- (format p "static s7_int ~A_if_i(s7_scheme *sc, s7_pointer **p) {return(~A());}~%" func-name func-name)
- (format p "static s7_if_t ~A_if(s7_scheme *sc, s7_pointer expr) {return(~A_if_i);}~%" func-name func-name))))
-
- (format p "~%")
- (set! functions (cons (list scheme-name base-name
- (if (and (string? doc)
- (> (length doc) 0))
- doc
- (format #f "~A ~A~A" return-type func-name arg-types))
- num-args 0
- (make-signature return-type arg-types))
- functions)))))
-
- (define (end-c-file)
- ;; now the init function
- ;; the new scheme variables and functions are placed in the current environment
-
- (format p "void ~A(s7_scheme *sc);~%" init-name)
- (format p "void ~A(s7_scheme *sc)~%" init-name)
- (format p "{~%")
- (format p " s7_pointer cur_env;~%")
- (format p " s7_pointer ")
- (let ((pls (hash-table-entries signatures))
- (loc 1))
- (for-each
- (lambda (s)
- (format p "~A~A~A" (cdr s) (if (< loc pls) (values "," " ") (values ";" #\newline)))
- (set! loc (+ loc 1)))
- signatures))
-
- (let ((syms ())
- (names ()))
- (for-each
- (lambda (q)
- (when (positive? (cdr q))
- (set! syms (cons (car q) syms))
- (set! names (cons (signature->pl (car q)) names))))
- sig-symbols)
- (when (pair? syms)
- (format p " {~% s7_pointer ~{~C~^, ~};~%" names)
- (for-each
- (lambda (name sym)
- (format p (if (eq? sym 't)
- " t = s7_t(sc);~%"
- (values " ~C = s7_make_symbol(sc, ~S);~%" name (symbol->string sym)))))
- names syms)))
- (format p "~%")
- (for-each
- (lambda (sig)
- (let ((cyclic (char=? ((cdr sig) 1) #\c)))
- (format p (if cyclic
- (values " ~A = s7_make_circular_signature(sc, ~D, ~D" (cdr sig) (- (length (car sig)) 1) (length (car sig)))
- (values " ~A = s7_make_signature(sc, ~D" (cdr sig) (length (car sig)))))
- (format p "~{~^, ~C~}" (substring (cdr sig) (if cyclic 4 3)))
- (format p ");~%")))
- signatures)
- (format p " }~%~%")
- (format p " cur_env = s7_outlet(sc, s7_curlet(sc));~%") ; this must exist because we pass load the env ourselves
-
- ;; send out any special initialization code
- (for-each
- (lambda (init-str)
- (format p " ~A~%" init-str))
- (reverse inits))
-
- ;; "constants" -- actually variables in s7 because we want them to be local to the current environment
- (if (pair? constants)
- (begin
- (format p "~%")
- (for-each
- (lambda (c)
- (let* ((type (c 0))
- (c-name (c 1))
- (scheme-name (string-append prefix (if (> (length prefix) 0) ":" "") c-name)))
- (format p " s7_define(sc, cur_env, s7_make_symbol(sc, ~S), ~A(sc, (~A)~A));~%"
- scheme-name
- (C->s7 type)
- (C->s7-cast type)
- c-name)))
- constants)))
-
- ;; C macros -- need #ifdef name #endif wrapper
- (if (pair? macros)
- (begin
- (format p "~%")
- (for-each
- (lambda (c)
- (let* ((type (c 0))
- (c-name (c 1))
- (scheme-name (string-append prefix (if (> (length prefix) 0) ":" "") c-name)))
- (format p "#ifdef ~A~%" c-name)
- (format p " s7_define(sc, cur_env, s7_make_symbol(sc, ~S), ~A(sc, (~A)~A));~%"
- scheme-name
- (C->s7 type)
- (C->s7-cast type)
- c-name)
- (format p "#endif~%")))
- macros)))
-
- ;; functions
- (for-each
- (lambda (f)
- (let ((scheme-name (f 0))
- (base-name (f 1))
- (help (f 2))
- (num-args (f 3))
- (opt-args (if (> (length f) 4) (f 4) 0))
- (sig (and (> (length f) 5) (f 5))))
- (format p "~% s7_define(sc, cur_env,~% s7_make_symbol(sc, ~S),~%" scheme-name)
- (format p " s7_make_typed_function(sc, ~S, ~A, ~D, ~D, false, ~S, ~A));~%"
- scheme-name
- base-name
- num-args
- opt-args
- help
- (if (pair? sig) (signatures sig) 'NULL))))
- functions)
-
- ;; optimizer connection
- (when (pair? rf-funcs)
- (format p "~% /* rf optimizer connections */~%")
- (for-each
- (lambda (f)
- (format p " s7_rf_set_function(s7_name_to_value(sc, ~S), ~A_rf);~%" (cdr f) (car f)))
- rf-funcs))
-
- (when (pair? if-funcs)
- (format p "~% /* if optimizer connections */~%")
- (for-each
- (lambda (f)
- (format p " s7_if_set_function(s7_name_to_value(sc, ~S), ~A_if);~%" (cdr f) (car f)))
- if-funcs))
-
- (format p "}~%")
- (close-output-port p)
-
- ;; now we have the module .c file -- make it into a shared object, load it, delete the temp files
-
- (cond ((provided? 'osx)
- ;; I assume the caller is also compiled with these flags?
- (system (format #f "gcc -c ~A -o ~A ~A ~A"
- c-file-name o-file-name *cload-cflags* cflags))
- (system (format #f "gcc ~A -o ~A -dynamic -bundle -undefined suppress -flat_namespace ~A ~A"
- o-file-name so-file-name *cload-ldflags* ldflags)))
-
- ((provided? 'freebsd)
- (system (format #f "cc -fPIC -c ~A -o ~A ~A ~A"
- c-file-name o-file-name *cload-cflags* cflags))
- (system (format #f "cc ~A -shared -o ~A ~A ~A"
- o-file-name so-file-name *cload-ldflags* ldflags)))
-
- ((provided? 'openbsd)
- (system (format #f "cc -fPIC -ftrampolines -c ~A -o ~A ~A ~A"
- c-file-name o-file-name *cload-cflags* cflags))
- (system (format #f "cc ~A -shared -o ~A ~A ~A"
- o-file-name so-file-name *cload-ldflags* ldflags)))
-
- ((provided? 'sunpro_c) ; just guessing here...
- (system (format #f "cc -c ~A -o ~A ~A ~A"
- c-file-name o-file-name *cload-cflags* cflags))
- (system (format #f "cc ~A -G -o ~A ~A ~A"
- o-file-name so-file-name *cload-ldflags* ldflags)))
-
- ;; what about clang? Maybe use cc below, not gcc (and in osx case above)
-
- (else
- (system (format #f "gcc -fPIC -c ~A -o ~A ~A ~A"
- c-file-name o-file-name *cload-cflags* cflags))
- (system (format #f "gcc ~A -shared -o ~A ~A ~A"
- o-file-name so-file-name *cload-ldflags* ldflags)))))
-
- (define (handle-declaration func)
-
- (define (add-one-constant type name)
- ;; C constant -> scheme
- (let ((c-type (if (pair? type) (cadr type) type)))
- (if (symbol? name)
- (set! constants (cons (list c-type (symbol->string (collides? name))) constants))
- (for-each
- (lambda (c)
- (set! constants (cons (list c-type (symbol->string (collides? c))) constants)))
- name))))
-
- (define (add-one-macro type name)
- ;; C macro (with definition check) -> scheme
- (let ((c-type (if (pair? type) (cadr type) type)))
- (if (symbol? name)
- (set! macros (cons (list c-type (symbol->string (collides? name))) macros))
- (for-each
- (lambda (c)
- (set! macros (cons (list c-type (symbol->string (collides? c))) macros)))
- name))))
-
- (define (check-doc func-data)
- (let ((doc (caddr func-data)))
- (if (and (string? doc)
- (> (length doc) 0))
- func-data
- (append (list (car func-data) (cadr func-data) (car func-data)) (cdddr func-data)))))
-
- ;; functions
- (if (>= (length func) 3)
- (apply add-one-function func)
- (case (car func)
- ((in-C) (format p "~A~%" (cadr func)))
- ((C-init) (set! inits (cons (cadr func) inits)))
- ((C-macro) (apply add-one-macro (cadr func)))
- ((C-function) (collides? (caadr func)) (set! functions (cons (check-doc (cadr func)) functions)))
- (else (apply add-one-constant func)))))
-
-
- ;; this is the body of c-define
- (unless (and output-name
- (file-exists? c-file-name)
- (file-exists? so-file-name)
- (provided? 'system-extras)
- (>= (file-mtime so-file-name) (file-mtime c-file-name))
- (not (and (file-exists? (port-filename (current-input-port)))
- (< (file-mtime so-file-name) (file-mtime (port-filename (current-input-port)))))))
- (format *stderr* "writing ~A~%" c-file-name)
- ;; write a new C file and compile it
- (initialize-c-file)
-
- (if (and (pair? (cdr function-info))
- (symbol? (cadr function-info)))
- (handle-declaration function-info)
- (for-each handle-declaration function-info))
-
- (end-c-file)
- (delete-file o-file-name))
-
- ;; load the object file, clean up
- (let ((new-env (sublet cur-env 'init_func (string->symbol init-name))))
- (format *stderr* "loading ~A~%" so-file-name)
- (load so-file-name new-env)))))
-
-
-
- ;;; backwards compatibility
- (define define-c-function c-define)
-
-
- #|
- (let ((cd (symbol "complex double"))
- (cd* (symbol "complex double *")))
- (c-define (list cd 'mus_edot_product (list cd cd* 'int))))
-
- ;complex double mus_edot_product(complex double freq, complex double *data, mus_long_t size)
- |#
|