You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cload.scm 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. (provide 'cload.scm)
  2. ;;; --------------------------------------------------------------------------------
  3. ;;; automatically link a C function into s7 (there are a bunch of examples below)
  4. ;;; (c-define '(double j0 (double)) "m" "math.h")
  5. ;;; means link the name m:j0 to the math library function j0 passing a double arg and getting a double result (reals in s7)
  6. ;;;
  7. ;;; (c-define c-info prefix headers cflags ldflags)
  8. ;;; prefix is some arbitrary prefix (it can be "") that you want prepended to various names.
  9. ;;; headers is a list of headers (as strings) that the c-info relies on, (("math.h") for example).
  10. ;;; cflags are any special C compiler flags that are needed ("-I." in particular).
  11. ;;; ldflags is the similar case for the loader.
  12. ;;; c-info is a list that describes the C entities that you want to tie into s7.
  13. ;;; it can be either one list describing one entity, or a list of such lists.
  14. ;;; Each description has the form: (return-type entity-name-in-C (argument-type...))
  15. ;;; where each entry is a symbol, and C names are used throughout. So, in the j0
  16. ;;; example above, (double j0 (double)) says we want access to j0, it returns
  17. ;;; a C double, and takes one argument, also a C double. s7 tries to figure out
  18. ;;; what the corresponding s7 type is, but in tricky cases, you should tell it
  19. ;;; by replacing the bare type name with a list: (C-type underlying-C-type). For example,
  20. ;;; the Snd function set_graph_style takes an (enum) argument of type graph_style_t.
  21. ;;; This is actually an int, so we use (graph_style_t int) as the type:
  22. ;;; (void set_graph_style ((graph_style_t int)))
  23. ;;; If the C entity is a constant, then the descriptor list has just two entries,
  24. ;;; the C-type and the entity name: (int F_OK) for example. The entity name can also be a list
  25. ;;; (an enum listing for example).
  26. ;;; If the C type has a space ("struct tm*" for example), use (symbol "struct tm*")
  27. ;;; to construct the corresponding symbol.
  28. ;;; The entity is placed in the current s7 environment under the name (string-append prefix ":" name)
  29. ;;; where the ":" is omitted if the prefix is null. So in the j0 example, we get in s7 the function m:j0.
  30. ;;;
  31. ;;; some examples:
  32. ;;;
  33. ;;; (c-define '((double j0 (double))
  34. ;;; (double j1 (double))
  35. ;;; (double erf (double))
  36. ;;; (double erfc (double))
  37. ;;; (double lgamma (double)))
  38. ;;; "m" "math.h")
  39. ;;;
  40. ;;;
  41. ;;; (c-define '(char* getenv (char*)))
  42. ;;; (c-define '(int setenv (char* char* int)))
  43. ;;; (define get-environment-variable (let () (c-define '(char* getenv (char*))) getenv))
  44. ;;;
  45. ;;; (define file-exists? (let () (c-define '((int F_OK) (int access (char* int))) "" "unistd.h") (lambda (arg) (= (access arg F_OK) 0))))
  46. ;;; (define delete-file (let () (c-define '(int unlink (char*)) "" "unistd.h") (lambda (file) (= (unlink file) 0)))) ; 0=success, -1=failure
  47. ;;;
  48. ;;;
  49. ;;; these pick up Snd stuff:
  50. ;;; (c-define '(char* version_info ()) "" "snd.h" "-I.")
  51. ;;; (c-define '(mus_float_t mus_degrees_to_radians (mus_float_t)) "" "snd.h" "-I.")
  52. ;;;
  53. ;;; (c-define '(snd_info* any_selected_sound ()) "" "snd.h" "-I.")
  54. ;;; (c-define '(void select_channel (snd_info* int)) "" "snd.h" "-I.")
  55. ;;; (c-define '(((graph_style_t int) (GRAPH_LINES GRAPH_DOTS GRAPH_FILLED GRAPH_DOTS_AND_LINES GRAPH_LOLLIPOPS))
  56. ;;; (void set_graph_style ((graph_style_t int))))
  57. ;;; "" "snd.h" "-I.")
  58. ;;;
  59. ;;;
  60. ;;; (c-define '(char* getcwd (char* size_t)) "" "unistd.h")
  61. ;;; :(let ((str (make-string 32))) (getcwd str 32) str)
  62. ;;; "/home/bil/cl\x00 "
  63. ;;; so it works in a sense -- there is a memory leak here
  64. ;;;
  65. ;;;
  66. ;;; (c-define (list '(void* calloc (size_t size_t))
  67. ;;; '(void* malloc (size_t))
  68. ;;; '(void free (void*))
  69. ;;; '(void* realloc(void* size_t))
  70. ;;; '(void time (time_t*)) ; ignore returned value
  71. ;;; (list (symbol "struct tm*") 'localtime '(time_t*))
  72. ;;; (list 'size_t 'strftime (list 'char* 'size_t 'char* (symbol "struct tm*"))))
  73. ;;; "" "time.h")
  74. ;;; > (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)
  75. ;;; "Sat 11-Aug-2012 08:55 PDT\x00 "
  76. ;;;
  77. ;;;
  78. ;;; (c-define '((int closedir (DIR*))
  79. ;;; (DIR* opendir (char*))
  80. ;;; (in-C "static char *read_dir(DIR *p) \
  81. ;;; { \
  82. ;;; struct dirent *dirp; \
  83. ;;; dirp = readdir(p); \
  84. ;;; if (!dirp) return(NULL); \
  85. ;;; else return(dirp->d_name); \
  86. ;;; }")
  87. ;;; (char* read_dir (DIR*)))
  88. ;;; "" '("sys/types.h" "dirent.h"))
  89. ;;;
  90. ;;; (let ((dir (opendir "/home/bil/gtk-snd")))
  91. ;;; (do ((p (read_dir dir) (read_dir dir)))
  92. ;;; ((= (length p) 0))
  93. ;;; (format *stderr* "~A " p))
  94. ;;; (closedir dir))
  95. ;;;
  96. ;;; (define (memory-usage)
  97. ;;; (with-let *libc*
  98. ;;; (let ((v (rusage.make)))
  99. ;;; (getrusage RUSAGE_SELF v)
  100. ;;; (let ((mem (rusage.ru_maxrss v)))
  101. ;;; (free v)
  102. ;;; (* 1024 mem)))))
  103. ;;; --------------------------------------------------------------------------------
  104. (define *cload-cflags* "")
  105. (define *cload-ldflags* "")
  106. (if (not (defined? '*cload-directory*))
  107. (define *cload-directory* ""))
  108. (define-macro (defvar name value)
  109. `(if (not (defined? ',name))
  110. (define ,name ,value)))
  111. (defvar c-define-output-file-counter 0) ; ugly, but I can't find a way around this (dlopen/dlsym stupidity)
  112. ;;; to place the new function in the caller's current environment, we need to pass the environment in explicitly:
  113. (define-macro (c-define . args)
  114. `(c-define-1 (curlet) ,@args))
  115. (define* (c-define-1 cur-env function-info (prefix "") (headers ()) (cflags "") (ldflags "") output-name)
  116. ;; write a C shared library module that links in the functions in function-info
  117. ;; function info is either a list: (return-type c-name arg-type) or a list thereof
  118. ;; the new functions are placed in cur-env
  119. (define handlers (list '(integer s7_is_integer s7_integer s7_make_integer s7_int)
  120. '(boolean s7_is_boolean s7_boolean s7_make_boolean bool)
  121. '(real s7_is_real s7_number_to_real s7_make_real s7_double)
  122. ;; '(complex s7_is_complex #f s7_make_complex s7_Complex)
  123. ;; the typedef is around line 6116 in s7.c, but we also need s7_complex which requires the s7_Complex type
  124. ;; 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
  125. '(string s7_is_string s7_string s7_make_string char*)
  126. (list 'character 's7_is_character 's7_character 's7_make_character (symbol "unsigned char"))
  127. '(c_pointer s7_is_c_pointer s7_c_pointer s7_make_c_pointer void*)
  128. '(s7_pointer #f #f #f s7_pointer)
  129. ))
  130. (define (C-type->s7-type type)
  131. (if (pair? type) ; in case the type name does not make its C type obvious: (graph_style_t int)
  132. (C-type->s7-type (cadr type))
  133. (let ((type-name (symbol->string type)))
  134. (cond ((string-position "**" type-name) ; any complicated C pointer is uninterpreted
  135. 'c_pointer)
  136. ((string=? "s7_pointer" type-name)
  137. 's7_pointer)
  138. ((string-position "char*" type-name) ; but not char** (caught above)
  139. 'string)
  140. ((or (string-position "*" type-name) ; float* etc
  141. (string-position "pointer" type-name))
  142. 'c_pointer)
  143. ((assoc type-name '(("char" . character)
  144. ("bool" . boolean)) string-position)
  145. => cdr)
  146. ;; ((string-position "complex" type-name)
  147. ;; 'complex) ; double complex or complex double (mus_edot_product in clm.c uses the latter)
  148. ((or (string-position "float" type-name)
  149. (string-position "double" type-name))
  150. 'real)
  151. ((or (string-position "int" type-name)
  152. (string-position "long" type-name) ; assuming not "long double" here so we need to look for it first (above)
  153. (string-position "short" type-name)
  154. (string-position "size" type-name)
  155. (string-position "byte" type-name))
  156. 'integer)
  157. (#t #t)))))
  158. (define (find-handler type choice)
  159. (cond ((assq (C-type->s7-type type) handlers) => choice) (else #t)))
  160. (define (C->s7-cast type)
  161. (find-handler type (lambda (p) (list-ref p 4))))
  162. (define (C->s7 type)
  163. (find-handler type cadddr))
  164. (define (s7->C type)
  165. (find-handler type caddr))
  166. (define (checker type)
  167. (find-handler type cadr))
  168. (define* (cload->signature type rtn)
  169. (case (C-type->s7-type type)
  170. ((real) (if rtn 'float? 'real?))
  171. ((integer) 'integer?)
  172. ((string) 'string?)
  173. ((boolean) 'boolean?)
  174. ((character) 'char?)
  175. ((c_pointer) 'c-pointer?)
  176. (else #t)))
  177. (define (signature->pl type)
  178. (case type
  179. ((integer?) #\i)
  180. ((boolean?) #\b)
  181. ((real?) #\r)
  182. ((float?) #\d)
  183. ((char?) #\c)
  184. ((string?) #\s)
  185. ((c-pointer?) #\x)
  186. (else #\t)))
  187. (set! c-define-output-file-counter (+ c-define-output-file-counter 1))
  188. (let ((file-name (string-append *cload-directory* (or output-name (format #f "temp-s7-output-~D" c-define-output-file-counter)))))
  189. (let ((c-file-name (string-append file-name ".c"))
  190. (o-file-name (string-append file-name ".o"))
  191. (so-file-name (string-append file-name ".so"))
  192. (init-name (if (string? output-name)
  193. (string-append output-name "_init")
  194. (string-append "init_" (number->string c-define-output-file-counter))))
  195. (functions ())
  196. (constants ())
  197. (macros ()) ; these are protected by #ifdef ... #endif
  198. (inits ()) ; C code (a string in s7) inserted in the library initialization function
  199. (p #f)
  200. (if-funcs ()) ; if-functions (guaranteed to return int, so we can optimize away make-integer etc)
  201. (rf-funcs ()) ; rf-functions
  202. (sig-symbols (list (cons 'integer? 0) (cons 'boolean? 0) (cons 'real? 0) (cons 'float? 0)
  203. (cons 'char? 0) (cons 'string? 0) (cons 'c-pointer? 0) (cons 't 0)))
  204. (signatures (make-hash-table)))
  205. (define (make-signature rtn args)
  206. (define (compress sig)
  207. (if (and (pair? sig)
  208. (pair? (cdr sig))
  209. (eq? (car sig) (cadr sig)))
  210. (compress (cdr sig))
  211. sig))
  212. (let ((sig (list (cload->signature rtn #t)))
  213. (cyclic #f))
  214. (for-each
  215. (lambda (arg)
  216. (set! sig (cons (cload->signature arg) sig)))
  217. args)
  218. (let ((len (length sig)))
  219. (set! sig (compress sig))
  220. (set! cyclic (not (= len (length sig)))))
  221. (set! sig (reverse sig))
  222. (unless (signatures sig) ; it's not in our collection yet
  223. (let ((pl (make-string (+ (if cyclic 4 3) (length sig))))
  224. (loc (if cyclic 4 3)))
  225. (set! (pl 0) #\p)
  226. (if cyclic
  227. (begin (set! (pl 1) #\c) (set! (pl 2) #\l) (set! (pl 3) #\_))
  228. (begin (set! (pl 1) #\l) (set! (pl 2) #\_)))
  229. (for-each
  230. (lambda (typer)
  231. (set! (pl loc) (signature->pl typer))
  232. (let ((count (or (assq typer sig-symbols)
  233. (assq 't sig-symbols))))
  234. (set-cdr! count (+ (cdr count) 1)))
  235. (set! loc (+ loc 1)))
  236. sig)
  237. (set! (signatures sig) pl)))
  238. sig))
  239. (define (initialize-c-file)
  240. ;; C header stuff
  241. (set! p (open-output-file c-file-name))
  242. (format p "#include <stdlib.h>~%")
  243. (format p "#include <stdio.h>~%")
  244. (format p "#include <string.h>~%")
  245. (if (string? headers)
  246. (format p "#include <~A>~%" headers)
  247. (for-each
  248. (lambda (header)
  249. (format p "#include <~A>~%" header))
  250. headers))
  251. (format p "#include \"s7.h\"~%~%"))
  252. (define collides?
  253. (let ((all-names ()))
  254. (lambda (name)
  255. (if (memq name all-names)
  256. (format *stderr* "~A twice?~%" name)
  257. (set! all-names (cons name all-names)))
  258. name)))
  259. (define* (add-one-function return-type name arg-types doc)
  260. ;; (format *stderr* "~A ~A ~A~%" return-type name arg-types): double j0 (double) for example
  261. ;; C function -> scheme
  262. (let ((func-name (symbol->string (collides? name))))
  263. (let ((num-args (length arg-types))
  264. (base-name (string-append (if (> (length prefix) 0) prefix "s7_dl") "_" func-name)) ; not "g" -- collides with glib
  265. (scheme-name (string-append prefix (if (> (length prefix) 0) ":" "") func-name)))
  266. (if (and (= num-args 1)
  267. (eq? (car arg-types) 'void))
  268. (set! num-args 0))
  269. (format p "~%/* -------- ~A -------- */~%" func-name)
  270. (format p "static s7_pointer ~A(s7_scheme *sc, s7_pointer args)~%" base-name)
  271. (format p "{~%")
  272. ;; get the Scheme args, check their types, assign to local C variables
  273. (when (positive? num-args)
  274. (format p " s7_pointer arg;~%")
  275. (do ((i 0 (+ i 1))
  276. (type arg-types (cdr type)))
  277. ((= i num-args))
  278. (format p " ~A ~A_~D;~%" ((if (pair? (car type)) caar car) type) base-name i))
  279. (format p " arg = args;~%")
  280. (do ((i 0 (+ i 1))
  281. (type arg-types (cdr type)))
  282. ((= i num-args))
  283. (let* ((nominal-type ((if (pair? (car type)) caar car) type)) ; double in the example
  284. (true-type ((if (pair? (car type)) cadar car) type))
  285. (s7-type (C-type->s7-type true-type))) ; real
  286. (if (eq? true-type 's7_pointer)
  287. (format p " ~A_~D = s7_car(arg);~%" base-name i)
  288. (begin
  289. (format p " if (~A(s7_car(arg)))~%" (checker true-type))
  290. (format p " ~A_~D = (~A)~A(~As7_car(arg));~%"
  291. base-name i
  292. nominal-type
  293. (s7->C true-type) ; s7_number_to_real which requires
  294. (if (memq s7-type '(boolean real)) ; the extra sc arg
  295. "sc, " ""))
  296. (format p " else return(s7_wrong_type_arg_error(sc, ~S, ~D, s7_car(arg), ~S));~%"
  297. func-name
  298. (if (= num-args 1) 0 (+ i 1))
  299. (if (symbol? s7-type)
  300. (symbol->string s7-type)
  301. (error 'bad-arg (format #f "in ~S, ~S is not a symbol~%" name s7-type))))))
  302. (if (< i (- num-args 1))
  303. (format p " arg = s7_cdr(arg);~%")))))
  304. ;; return C value to Scheme
  305. (if (pair? return-type)
  306. (set! return-type (cadr return-type)))
  307. (let ((return-translator (C->s7 return-type)))
  308. (format p " ")
  309. (if (not (eq? return-translator #t))
  310. (format p "return("))
  311. (if (symbol? return-translator)
  312. (format p "~A(sc, (~A)" return-translator (C->s7-cast return-type)))
  313. (format p "~A(" func-name)
  314. (do ((i 0 (+ i 1)))
  315. ((>= i (- num-args 1)))
  316. (format p "~A_~D, " base-name i))
  317. (if (positive? num-args)
  318. (format p "~A_~D" base-name (- num-args 1)))
  319. (format p ")")
  320. (if (symbol? return-translator)
  321. (format p ")"))
  322. (format p (if (not (eq? return-translator #t))
  323. ");~%"
  324. ";~% return(s7_unspecified(sc));~%"))
  325. (format p "}~%"))
  326. ;; add optimizer connection
  327. (when (and (eq? return-type 'double) ; double (f double) -- s7_rf_t: double f(s7, s7_pointer **p)
  328. (eq? (car arg-types) 'double)
  329. (or (= num-args 1)
  330. (and (= num-args 2) ; double (f double double)
  331. (eq? (cadr arg-types) 'double))))
  332. (set! rf-funcs (cons (cons func-name scheme-name) rf-funcs))
  333. (format p (if (= num-args 1)
  334. "static s7_double ~A_rf_r(s7_scheme *sc, s7_pointer **p)~
  335. {s7_rf_t f; s7_double x; f = (s7_rf_t)(**p); (*p)++; x = f(sc, p); return(~A(x));}~%"
  336. "static s7_double ~A_rf_r(s7_scheme *sc, s7_pointer **p)~% ~
  337. {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));}~%")
  338. func-name func-name)
  339. (format p "static s7_rf_t ~A_rf(s7_scheme *sc, s7_pointer expr) ~
  340. {if (s7_arg_to_rf(sc, s7_cadr(expr))) return(~A_rf_r); return(NULL);}~%"
  341. func-name func-name))
  342. (when (and (eq? return-type 'int) ; int (f int|double|void)
  343. (memq (car arg-types) '(int double void))
  344. (<= num-args 1))
  345. (set! if-funcs (cons (cons func-name scheme-name) if-funcs))
  346. (case (car arg-types)
  347. ((double)
  348. (format p "static s7_int ~A_if_r(s7_scheme *sc, s7_pointer **p)~
  349. {s7_rf_t f; s7_double x; f = (s7_rf_t)(**p); (*p)++; x = f(sc, p); return(~A(x));}~%"
  350. func-name func-name)
  351. (format p "static s7_if_t ~A_if(s7_scheme *sc, s7_pointer expr) ~
  352. {if (s7_arg_to_if(sc, s7_cadr(expr))) return(~A_if_r); return(NULL);}~%"
  353. func-name func-name))
  354. ((int)
  355. (format p "static s7_int ~A_if_i(s7_scheme *sc, s7_pointer **p)~
  356. {s7_if_t f; s7_int x; f = (s7_if_t)(**p); (*p)++; x = f(sc, p); return(~A(x));}~%"
  357. func-name (if (string=? func-name "abs") "llabs" func-name))
  358. (format p "static s7_if_t ~A_if(s7_scheme *sc, s7_pointer expr) ~
  359. {if (s7_arg_to_if(sc, s7_cadr(expr))) return(~A_if_i); return(NULL);}~%"
  360. func-name func-name))
  361. ((void)
  362. (format p "static s7_int ~A_if_i(s7_scheme *sc, s7_pointer **p) {return(~A());}~%" func-name func-name)
  363. (format p "static s7_if_t ~A_if(s7_scheme *sc, s7_pointer expr) {return(~A_if_i);}~%" func-name func-name))))
  364. (format p "~%")
  365. (set! functions (cons (list scheme-name base-name
  366. (if (and (string? doc)
  367. (> (length doc) 0))
  368. doc
  369. (format #f "~A ~A~A" return-type func-name arg-types))
  370. num-args 0
  371. (make-signature return-type arg-types))
  372. functions)))))
  373. (define (end-c-file)
  374. ;; now the init function
  375. ;; the new scheme variables and functions are placed in the current environment
  376. (format p "void ~A(s7_scheme *sc);~%" init-name)
  377. (format p "void ~A(s7_scheme *sc)~%" init-name)
  378. (format p "{~%")
  379. (format p " s7_pointer cur_env;~%")
  380. (format p " s7_pointer ")
  381. (let ((pls (hash-table-entries signatures))
  382. (loc 1))
  383. (for-each
  384. (lambda (s)
  385. (format p "~A~A~A" (cdr s) (if (< loc pls) (values "," " ") (values ";" #\newline)))
  386. (set! loc (+ loc 1)))
  387. signatures))
  388. (let ((syms ())
  389. (names ()))
  390. (for-each
  391. (lambda (q)
  392. (when (positive? (cdr q))
  393. (set! syms (cons (car q) syms))
  394. (set! names (cons (signature->pl (car q)) names))))
  395. sig-symbols)
  396. (when (pair? syms)
  397. (format p " {~% s7_pointer ~{~C~^, ~};~%" names)
  398. (for-each
  399. (lambda (name sym)
  400. (format p (if (eq? sym 't)
  401. " t = s7_t(sc);~%"
  402. (values " ~C = s7_make_symbol(sc, ~S);~%" name (symbol->string sym)))))
  403. names syms)))
  404. (format p "~%")
  405. (for-each
  406. (lambda (sig)
  407. (let ((cyclic (char=? ((cdr sig) 1) #\c)))
  408. (format p (if cyclic
  409. (values " ~A = s7_make_circular_signature(sc, ~D, ~D" (cdr sig) (- (length (car sig)) 1) (length (car sig)))
  410. (values " ~A = s7_make_signature(sc, ~D" (cdr sig) (length (car sig)))))
  411. (format p "~{~^, ~C~}" (substring (cdr sig) (if cyclic 4 3)))
  412. (format p ");~%")))
  413. signatures)
  414. (format p " }~%~%")
  415. (format p " cur_env = s7_outlet(sc, s7_curlet(sc));~%") ; this must exist because we pass load the env ourselves
  416. ;; send out any special initialization code
  417. (for-each
  418. (lambda (init-str)
  419. (format p " ~A~%" init-str))
  420. (reverse inits))
  421. ;; "constants" -- actually variables in s7 because we want them to be local to the current environment
  422. (if (pair? constants)
  423. (begin
  424. (format p "~%")
  425. (for-each
  426. (lambda (c)
  427. (let* ((type (c 0))
  428. (c-name (c 1))
  429. (scheme-name (string-append prefix (if (> (length prefix) 0) ":" "") c-name)))
  430. (format p " s7_define(sc, cur_env, s7_make_symbol(sc, ~S), ~A(sc, (~A)~A));~%"
  431. scheme-name
  432. (C->s7 type)
  433. (C->s7-cast type)
  434. c-name)))
  435. constants)))
  436. ;; C macros -- need #ifdef name #endif wrapper
  437. (if (pair? macros)
  438. (begin
  439. (format p "~%")
  440. (for-each
  441. (lambda (c)
  442. (let* ((type (c 0))
  443. (c-name (c 1))
  444. (scheme-name (string-append prefix (if (> (length prefix) 0) ":" "") c-name)))
  445. (format p "#ifdef ~A~%" c-name)
  446. (format p " s7_define(sc, cur_env, s7_make_symbol(sc, ~S), ~A(sc, (~A)~A));~%"
  447. scheme-name
  448. (C->s7 type)
  449. (C->s7-cast type)
  450. c-name)
  451. (format p "#endif~%")))
  452. macros)))
  453. ;; functions
  454. (for-each
  455. (lambda (f)
  456. (let ((scheme-name (f 0))
  457. (base-name (f 1))
  458. (help (f 2))
  459. (num-args (f 3))
  460. (opt-args (if (> (length f) 4) (f 4) 0))
  461. (sig (and (> (length f) 5) (f 5))))
  462. (format p "~% s7_define(sc, cur_env,~% s7_make_symbol(sc, ~S),~%" scheme-name)
  463. (format p " s7_make_typed_function(sc, ~S, ~A, ~D, ~D, false, ~S, ~A));~%"
  464. scheme-name
  465. base-name
  466. num-args
  467. opt-args
  468. help
  469. (if (pair? sig) (signatures sig) 'NULL))))
  470. functions)
  471. ;; optimizer connection
  472. (when (pair? rf-funcs)
  473. (format p "~% /* rf optimizer connections */~%")
  474. (for-each
  475. (lambda (f)
  476. (format p " s7_rf_set_function(s7_name_to_value(sc, ~S), ~A_rf);~%" (cdr f) (car f)))
  477. rf-funcs))
  478. (when (pair? if-funcs)
  479. (format p "~% /* if optimizer connections */~%")
  480. (for-each
  481. (lambda (f)
  482. (format p " s7_if_set_function(s7_name_to_value(sc, ~S), ~A_if);~%" (cdr f) (car f)))
  483. if-funcs))
  484. (format p "}~%")
  485. (close-output-port p)
  486. ;; now we have the module .c file -- make it into a shared object, load it, delete the temp files
  487. (cond ((provided? 'osx)
  488. ;; I assume the caller is also compiled with these flags?
  489. (system (format #f "gcc -c ~A -o ~A ~A ~A"
  490. c-file-name o-file-name *cload-cflags* cflags))
  491. (system (format #f "gcc ~A -o ~A -dynamic -bundle -undefined suppress -flat_namespace ~A ~A"
  492. o-file-name so-file-name *cload-ldflags* ldflags)))
  493. ((provided? 'freebsd)
  494. (system (format #f "cc -fPIC -c ~A -o ~A ~A ~A"
  495. c-file-name o-file-name *cload-cflags* cflags))
  496. (system (format #f "cc ~A -shared -o ~A ~A ~A"
  497. o-file-name so-file-name *cload-ldflags* ldflags)))
  498. ((provided? 'openbsd)
  499. (system (format #f "cc -fPIC -ftrampolines -c ~A -o ~A ~A ~A"
  500. c-file-name o-file-name *cload-cflags* cflags))
  501. (system (format #f "cc ~A -shared -o ~A ~A ~A"
  502. o-file-name so-file-name *cload-ldflags* ldflags)))
  503. ((provided? 'sunpro_c) ; just guessing here...
  504. (system (format #f "cc -c ~A -o ~A ~A ~A"
  505. c-file-name o-file-name *cload-cflags* cflags))
  506. (system (format #f "cc ~A -G -o ~A ~A ~A"
  507. o-file-name so-file-name *cload-ldflags* ldflags)))
  508. ;; what about clang? Maybe use cc below, not gcc (and in osx case above)
  509. (else
  510. (system (format #f "gcc -fPIC -c ~A -o ~A ~A ~A"
  511. c-file-name o-file-name *cload-cflags* cflags))
  512. (system (format #f "gcc ~A -shared -o ~A ~A ~A"
  513. o-file-name so-file-name *cload-ldflags* ldflags)))))
  514. (define (handle-declaration func)
  515. (define (add-one-constant type name)
  516. ;; C constant -> scheme
  517. (let ((c-type (if (pair? type) (cadr type) type)))
  518. (if (symbol? name)
  519. (set! constants (cons (list c-type (symbol->string (collides? name))) constants))
  520. (for-each
  521. (lambda (c)
  522. (set! constants (cons (list c-type (symbol->string (collides? c))) constants)))
  523. name))))
  524. (define (add-one-macro type name)
  525. ;; C macro (with definition check) -> scheme
  526. (let ((c-type (if (pair? type) (cadr type) type)))
  527. (if (symbol? name)
  528. (set! macros (cons (list c-type (symbol->string (collides? name))) macros))
  529. (for-each
  530. (lambda (c)
  531. (set! macros (cons (list c-type (symbol->string (collides? c))) macros)))
  532. name))))
  533. (define (check-doc func-data)
  534. (let ((doc (caddr func-data)))
  535. (if (and (string? doc)
  536. (> (length doc) 0))
  537. func-data
  538. (append (list (car func-data) (cadr func-data) (car func-data)) (cdddr func-data)))))
  539. ;; functions
  540. (if (>= (length func) 3)
  541. (apply add-one-function func)
  542. (case (car func)
  543. ((in-C) (format p "~A~%" (cadr func)))
  544. ((C-init) (set! inits (cons (cadr func) inits)))
  545. ((C-macro) (apply add-one-macro (cadr func)))
  546. ((C-function) (collides? (caadr func)) (set! functions (cons (check-doc (cadr func)) functions)))
  547. (else (apply add-one-constant func)))))
  548. ;; this is the body of c-define
  549. (unless (and output-name
  550. (file-exists? c-file-name)
  551. (file-exists? so-file-name)
  552. (provided? 'system-extras)
  553. (>= (file-mtime so-file-name) (file-mtime c-file-name))
  554. (not (and (file-exists? (port-filename (current-input-port)))
  555. (< (file-mtime so-file-name) (file-mtime (port-filename (current-input-port)))))))
  556. (format *stderr* "writing ~A~%" c-file-name)
  557. ;; write a new C file and compile it
  558. (initialize-c-file)
  559. (if (and (pair? (cdr function-info))
  560. (symbol? (cadr function-info)))
  561. (handle-declaration function-info)
  562. (for-each handle-declaration function-info))
  563. (end-c-file)
  564. (delete-file o-file-name))
  565. ;; load the object file, clean up
  566. (let ((new-env (sublet cur-env 'init_func (string->symbol init-name))))
  567. (format *stderr* "loading ~A~%" so-file-name)
  568. (load so-file-name new-env)))))
  569. ;;; backwards compatibility
  570. (define define-c-function c-define)
  571. #|
  572. (let ((cd (symbol "complex double"))
  573. (cd* (symbol "complex double *")))
  574. (c-define (list cd 'mus_edot_product (list cd cd* 'int))))
  575. ;complex double mus_edot_product(complex double freq, complex double *data, mus_long_t size)
  576. |#