~ubuntu-branches/ubuntu/lucid/gauche-c-wrapper/lucid

« back to all changes in this revision

Viewing changes to lib/c-wrapper/stubgen.scm.in

  • Committer: Bazaar Package Importer
  • Author(s): NIIBE Yutaka
  • Date: 2008-04-07 09:15:03 UTC
  • Revision ID: james.westby@ubuntu.com-20080407091503-wu0h414koe95kj4i
Tags: upstream-0.5.2
ImportĀ upstreamĀ versionĀ 0.5.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
;; -*- coding: utf-8; mode: scheme -*-
 
2
;;
 
3
;; stubgen.scm - stub generator
 
4
;;
 
5
;;   Copyright (c) 2006 KOGURO, Naoki (naoki@koguro.net)
 
6
;;   All rights reserved.
 
7
;;
 
8
;;   Redistribution and use in source and binary forms, with or without 
 
9
;;   modification, are permitted provided that the following conditions 
 
10
;;   are met:
 
11
;;
 
12
;;   1. Redistributions of source code must retain the above copyright 
 
13
;;      notice, this list of conditions and the following disclaimer.
 
14
;;   2. Redistributions in binary form must reproduce the above copyright 
 
15
;;      notice, this list of conditions and the following disclaimer in the 
 
16
;;      documentation and/or other materials provided with the distribution.
 
17
;;   3. Neither the name of the authors nor the names of its contributors 
 
18
;;      may be used to endorse or promote products derived from this 
 
19
;;      software without specific prior written permission.
 
20
;;
 
21
;;   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 
22
;;   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 
23
;;   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 
24
;;   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 
25
;;   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 
26
;;   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
 
27
;;   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 
28
;;   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 
29
;;   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 
30
;;   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 
31
;;   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
32
;;
 
33
;;   $Id: $
 
34
;;
 
35
 
 
36
(define-module c-wrapper.stubgen
 
37
  (use srfi-1)
 
38
  (use srfi-13)
 
39
  (use gauche.parameter)
 
40
  (use gauche.process)
 
41
  (use gauche.parseopt)
 
42
  (use file.util)
 
43
  (use util.match)
 
44
  (use c-wrapper.c-parser)
 
45
  (use @STUBGEN_FFI_MODULE@)
 
46
  (use text.tr)
 
47
 
 
48
  (export compile-wrapper)
 
49
  )
 
50
 
 
51
(select-module c-wrapper.stubgen)
 
52
 
 
53
(define (listize obj)
 
54
  (if (list? obj)
 
55
      (cond
 
56
       ((null? obj)
 
57
        obj)
 
58
       ((eq? (car obj) 'quote)
 
59
        (cadr obj))
 
60
       (else
 
61
        obj))
 
62
      (list obj)))
 
63
 
 
64
(define *dummy-line* "/**/")
 
65
 
 
66
;; from genstub.scm
 
67
(define (get-c-name prefix scheme-name)
 
68
  (with-output-to-string
 
69
    (lambda ()
 
70
      (display (x->string prefix)) 
 
71
      (with-input-from-string (x->string scheme-name)
 
72
        (lambda ()
 
73
          (let loop ((c (read-char)))
 
74
            (unless (eof-object? c)
 
75
              (case c
 
76
                ((#\-) (let ((d (read-char)))
 
77
                         (cond ((eof-object? d)
 
78
                                (display #\_))
 
79
                               ((eqv? d #\>)
 
80
                                (display "_TO") (loop (read-char)))
 
81
                               (else
 
82
                                (display #\_) (loop d)))))
 
83
                ((#\?) (display #\P) (loop (read-char)))
 
84
                ((#\!) (display #\X) (loop (read-char)))
 
85
                ((#\<) (display "_LT") (loop (read-char)))
 
86
                ((#\>) (display "_GT") (loop (read-char)))
 
87
                ((#\* #\> #\@ #\$ #\% #\^ #\& #\* #\+ #\=
 
88
                  #\: #\. #\/ #\~)
 
89
                 (display #\_)
 
90
                 (display (number->string (char->integer c) 16))
 
91
                 (loop (read-char)))
 
92
                (else (display c) (loop (read-char)))
 
93
                ))))
 
94
        )
 
95
      )
 
96
    )
 
97
  )
 
98
 
 
99
(define stub-unit (make-parameter #f))
 
100
 
 
101
(define-class <stub-unit> ()
 
102
  ((stub-file :init-keyword :stub-file :init-value #f)
 
103
   (module :init-keyword :module :init-value #f)
 
104
   (header-comments :init-value '())
 
105
   (footer-comments :init-value '())
 
106
   (includes :init-value '())
 
107
   (embedding-c-codes :init-value '())
 
108
   (define-cprocs :init-value '())
 
109
   (define-symbols :init-value '())
 
110
   (initcodes :init-value '())
 
111
   (value-table :init-form (make-hash-table))
 
112
   (symbol-table :init-form (make-hash-table))
 
113
   (string-table :init-form (make-hash-table 'string=?))
 
114
   (memoise-table :init-form (make-hash-table 'equal?))
 
115
   (cproc-table :init-form (make-hash-table))))
 
116
 
 
117
(define (make-stub-unit module stub-file)
 
118
  (let ((unit (make <stub-unit> :stub-file stub-file :module module)))
 
119
    (parameterize ((stub-unit unit))
 
120
      (emit-header-comment #`";;;")
 
121
      (emit-header-comment #`";;; ,(slot-ref unit 'stub-file)")
 
122
      (emit-header-comment #`";;;")
 
123
 
 
124
      (emit-include "stdlib.h")
 
125
      (emit-include "gauche.h")
 
126
      (emit-include "gauche/extend.h")
 
127
      (emit-include "gauche/uvector.h")
 
128
 
 
129
      (let ((cname (get-c-name "" (path-sans-extension stub-file))))
 
130
        (emit-c-code "/* Hack for initialization stub */")
 
131
        (emit-c-code "static void internal_init(ScmModule*);")
 
132
        (emit-c-code "static ScmObj __c_wrapper_mod;")
 
133
        (emit-c-code #`"void Scm_Init_,|cname|(void)")
 
134
        (emit-c-code #`"{")
 
135
        (emit-c-code #`"    SCM_INIT_EXTENSION(,|cname|);")
 
136
        (emit-c-code #`"    __c_wrapper_mod = SCM_OBJ(SCM_FIND_MODULE(\",|module|\",, 0));")
 
137
        (emit-c-code #`"    internal_init(SCM_MODULE(__c_wrapper_mod));")
 
138
        (emit-c-code #`"}")
 
139
        (emit-c-code #`"#define Scm_Init_,|cname| internal_init"))
 
140
 
 
141
      ;; define helper functions
 
142
      (emit-c-code "#define INIT_SYMVAL(var, sym) if (!var) { var = Scm_SymbolValue(SCM_MODULE(__c_wrapper_mod), SCM_SYMBOL(SCM_INTERN(sym))); }")
 
143
 
 
144
      (emit-c-code "static ScmObj cw_boxvar(ScmObj klass, void *varptr)")
 
145
      (emit-c-code "{")
 
146
      (emit-c-code "    static ScmObj make_proc = NULL;")
 
147
      (emit-c-code "    static ScmObj csizeof_proc = NULL;")
 
148
      (emit-c-code "    ScmObj obj;")
 
149
      (emit-c-code "    ScmObj buf;")
 
150
      (emit-c-code "    size_t size;")
 
151
      (emit-c-code "    INIT_SYMVAL(make_proc, \"make\");")
 
152
      (emit-c-code "    INIT_SYMVAL(csizeof_proc, \"c-sizeof\");")
 
153
      (emit-c-code "    size = Scm_GetIntegerU(Scm_ApplyRec(csizeof_proc, SCM_LIST1(klass)));")
 
154
      (emit-c-code "    buf = Scm_MakeU8VectorFromArrayShared(size, varptr);")
 
155
      (emit-c-code "    obj = Scm_ApplyRec(make_proc, SCM_LIST3(klass, SCM_MAKE_KEYWORD(\"buffer\"), buf));")
 
156
      (emit-c-code "    SCM_RETURN(obj);")
 
157
      (emit-c-code "}")
 
158
 
 
159
      (emit-c-code "static void cw_unbox(void *dest, ScmObj obj, size_t size)")
 
160
      (emit-c-code "{")
 
161
      (emit-c-code "    static ScmObj bufferof_proc = NULL;")
 
162
      (emit-c-code "    ScmObj buf;")
 
163
      (emit-c-code "    if (!bufferof_proc) {")
 
164
      (emit-c-code "        bufferof_proc = SCM_SYMBOL_VALUE(\"c-wrapper.c-ffi\", \"buffer-of\");")
 
165
      (emit-c-code "    }")
 
166
      (emit-c-code "    buf = Scm_ApplyRec(bufferof_proc, SCM_LIST1(obj));")
 
167
      (emit-c-code "    memcpy(dest, SCM_UVECTOR_ELEMENTS(buf), size);")
 
168
      (emit-c-code "}")
 
169
 
 
170
      (emit-footer-comment ";; Local variables:")
 
171
      (emit-footer-comment ";; mode: scheme")
 
172
      (emit-footer-comment ";; end:"))
 
173
    unit))
 
174
 
 
175
(define-method emit-header-comment ((comment <string>))
 
176
  (slot-push! (stub-unit) 'header-comments comment))
 
177
 
 
178
(define-method emit-footer-comment ((comment <string>))
 
179
  (slot-push! (stub-unit) 'footer-comments comment))
 
180
 
 
181
(define-method emit-include ((header-file <string>))
 
182
  (slot-push! (stub-unit) 'includes header-file))
 
183
 
 
184
(define-method emit-c-code ((c-code <string>))
 
185
  (slot-push! (stub-unit) 'embedding-c-codes c-code))
 
186
                
 
187
(define-method emit-define-cproc ((name <symbol>) ret-type (arg-types <list>)
 
188
                                  (args <list>) (body <string>))
 
189
  (cond
 
190
   ((hash-table-exists? (slot-ref (stub-unit) 'cproc-table) name)
 
191
    ;; DO NOTHING
 
192
    #t)
 
193
   (else
 
194
    (slot-push! (stub-unit) 'define-cprocs
 
195
                (with-output-to-string
 
196
                  (lambda ()
 
197
                    (format #t "(define-cproc ~a ~a" name args)
 
198
                    (let ((bodies (string-split body #[\x0d\x0a])))
 
199
                      (format #t "~%  (code ~s" (car bodies))
 
200
                      (for-each (cut format #t "~%        ~s" <>) (cdr bodies))
 
201
                      (format #t "))~%")))))
 
202
    (hash-table-put! (slot-ref (stub-unit) 'cproc-table) name
 
203
                     (cons ret-type arg-types)))))
 
204
 
 
205
(define-method emit-define-symbol ((name <symbol>) (varnam <symbol>))
 
206
  (slot-push! (stub-unit) 'define-symbols
 
207
              (format "(define-symbol ~a \"~a\")" name varnam)))
 
208
 
 
209
(define-method emit-initcode ((c-code <string>))
 
210
  (slot-push! (stub-unit) 'initcodes c-code))
 
211
 
 
212
(define (write-stub dir)
 
213
  (with-output-to-file (build-path dir (slot-ref (stub-unit) 'stub-file))
 
214
    (lambda ()
 
215
      (for-each print (reverse (slot-ref (stub-unit) 'header-comments)))
 
216
      (for-each (cut format #t "\"#include \\\"~a\\\"\"~%" <>)
 
217
                (reverse (slot-ref (stub-unit) 'includes)))
 
218
      (for-each (cut format #t "~s~%" <>)
 
219
                (reverse (slot-ref (stub-unit) 'embedding-c-codes)))
 
220
      (for-each print (reverse (slot-ref (stub-unit) 'define-symbols)))
 
221
      (for-each print (reverse (slot-ref (stub-unit) 'define-cprocs)))
 
222
      (for-each (lambda (line)
 
223
                  (unless (string=? line *dummy-line*)
 
224
                    (format #t "(initcode ~s)~%" (string-append line ";"))))
 
225
                (reverse (slot-ref (stub-unit) 'initcodes)))
 
226
      (for-each print (reverse (slot-ref (stub-unit) 'footer-comments))))))
 
227
 
 
228
;;
 
229
 
 
230
(define (classname->ctype sym)
 
231
  (match sym
 
232
    (('c-struct ('quote nam))
 
233
     #`"struct ,nam")
 
234
    (('c-union ('quote nam))
 
235
     #`"union ,nam")
 
236
    (('ptr type)
 
237
     "void*")
 
238
    (('c-array type num)
 
239
     "void*")
 
240
    (('c-func-ptr ret-type ('list ('list nam arg-type) ...))
 
241
     "void*")
 
242
    (('c-func-ptr ret-type ('list arg-type ...))
 
243
     "void*")
 
244
    ('<c-char>
 
245
     "char")
 
246
    ('<c-uchar>
 
247
     "unsigned char")
 
248
    ('<c-short>
 
249
     "short")
 
250
    ('<c-ushort>
 
251
     "unsigned short")
 
252
    ('<c-int>
 
253
     "int")
 
254
    ('<c-uint>
 
255
     "unsigned int")
 
256
    ('<c-long>
 
257
     "long")
 
258
    ('<c-ulong>
 
259
     "unsigned long")
 
260
    ('<c-longlong>
 
261
     "long long")
 
262
    ('<c-ulonglong>
 
263
     "unsigned long long")
 
264
    ('<c-float>
 
265
     "float")
 
266
    ('<c-double>
 
267
     "double")
 
268
    ('<c-longdouble>
 
269
     "long double")
 
270
    ('<c-void>
 
271
     "void")
 
272
    ((= (lambda (sym) (#/^<(.*)>$/ (x->string sym))) rmatch)
 
273
     (if rmatch
 
274
         (rmatch 1)
 
275
         (errorf "Unknown type ~a" sym)))))
 
276
 
 
277
(define-method emit-define-cproc ((name <symbol>) ret-type (arg-types <list>))
 
278
  (let* ((narg-types (remove (cut equal? '<c-void> <>) arg-types))
 
279
         (ret-ctype (classname->ctype ret-type))
 
280
         (narg-ctypes (map classname->ctype narg-types))
 
281
         (arg-objs (map (cut format "obj~a" <>) (iota (length narg-types))))
 
282
         (arg-vars (map (cut format "v~a" <>) (iota (length narg-types))))
 
283
         (body (with-output-to-string
 
284
                 (lambda ()
 
285
                   (for-each (cut format #t "~a ~a;~%" <> <>)
 
286
                             narg-ctypes arg-vars)
 
287
                   (for-each (lambda (var obj type)
 
288
                               (format #t "cw_unbox(&~a, ~a, sizeof(~a));~%"
 
289
                                       var
 
290
                                       (ccode-eval
 
291
                                        `(cast ,type
 
292
                                               (cexpr ,(string->symbol obj))))
 
293
                                       var))
 
294
                             arg-vars arg-objs narg-types)
 
295
                   (cond
 
296
                    ((equal? '<c-void> ret-type)
 
297
                     (format #t "(~a)(~a);~%"
 
298
                             name (string-join arg-vars ","))
 
299
                     (format #t "SCM_RETURN(SCM_UNDEFINED);"))
 
300
                    (else
 
301
                     (format #t "{~%")
 
302
                     (format #t "    ~a *result_buf = SCM_NEW2(~a*, sizeof(~a));~%"
 
303
                             ret-ctype ret-ctype ret-ctype)
 
304
                     (format #t "    *result_buf = (~a) (~a)(~a);~%"
 
305
                             ret-ctype name (string-join arg-vars ","))
 
306
                     (format #t "    SCM_RETURN(~a);~%"
 
307
                             (ccode-eval
 
308
                              `(scm-cast
 
309
                                (cexpr ,(format "cw_boxvar(~a, result_buf)"
 
310
                                                (ccode-eval ret-type))))))
 
311
                     (format #t "}")))))))
 
312
    (emit-define-cproc name ret-type arg-types
 
313
                       (map string->symbol arg-objs) body)))
 
314
 
 
315
(define (ccode-intern sym)
 
316
  (let ((symbol-table (slot-ref (stub-unit) 'symbol-table)))
 
317
    (symbol->string (or (hash-table-get symbol-table sym #f)
 
318
                        (let ((varnam (gensym "__c_wrapper_")))
 
319
                          (emit-define-symbol sym varnam)
 
320
                          (hash-table-put! symbol-table sym varnam)
 
321
                          varnam)))))
 
322
 
 
323
(define (ccode-string str)
 
324
  (let ((string-table (slot-ref (stub-unit) 'string-table)))
 
325
    (format "SCM_OBJ(&~a)"
 
326
            (or (hash-table-get string-table str #f)
 
327
                (let ((varnam (gensym "__c_wrapper_"))
 
328
                      (len (string-length str)))
 
329
                  (emit-c-code
 
330
                   (format "static SCM_DEFINE_STRING_CONST(~a, ~s, ~a, ~a);"
 
331
                           varnam str len len))
 
332
                  (hash-table-put! string-table str varnam)
 
333
                  varnam)))))
 
334
 
 
335
(define (ccode-lookup-value sym)
 
336
  (let ((value-table (slot-ref (stub-unit) 'value-table)))
 
337
     (or (hash-table-get value-table sym #f)
 
338
         (let ((varnam (gensym "__c_wrapper_")))
 
339
           (emit-c-code (format "static ScmObj ~a;    /* ~a */" varnam sym))
 
340
           (emit-initcode
 
341
            (format
 
342
             "~a = Scm_SymbolValue(SCM_MODULE(__c_wrapper_mod), SCM_SYMBOL(~a))"
 
343
             varnam (ccode-intern sym)))
 
344
           (hash-table-put! value-table sym varnam)
 
345
           (symbol->string varnam)))))
 
346
 
 
347
(define (ccode-define name cexpr)
 
348
  (let ((varnam (gensym "__c_wrapper_"))
 
349
        (value-table (slot-ref (stub-unit) 'value-table)))
 
350
    (hash-table-put! value-table name varnam)
 
351
    (emit-c-code (format "static ScmObj ~a;    /* ~a */" varnam name))
 
352
    (emit-initcode (format "~a = ~a" varnam cexpr))
 
353
    (format "Scm_Define(SCM_MODULE(__c_wrapper_mod), SCM_SYMBOL(~a), ~a)"
 
354
            (ccode-intern name) varnam)))
 
355
 
 
356
(define (ccode-memoise-apply proc args)
 
357
  (let ((memoise-table (slot-ref (stub-unit) 'memoise-table)))
 
358
    (symbol->string
 
359
     (or (hash-table-get memoise-table (cons proc args) #f)
 
360
         (let ((varnam (gensym "__c_wrapper_")))
 
361
           (emit-c-code (format "static ScmObj ~a;    /* ~a */"
 
362
                                varnam (cons proc args)))
 
363
           (emit-initcode (format "~a = ~a"
 
364
                                  varnam
 
365
                                  (ccode-eval `(apply ,proc (list ,@args)))))
 
366
           (hash-table-put! memoise-table (cons proc args) varnam)
 
367
           varnam)))))
 
368
           
 
369
(define (ccode-eval expr)
 
370
  (match expr
 
371
    ((('with-module 'c-wrapper 'define-inline-cfunc)
 
372
      name ret-type _ (arg-types ...) _ ...)
 
373
     (emit-define-cproc name ret-type arg-types)
 
374
     *dummy-line*)
 
375
    (('define name ('make-c-var _ type))
 
376
     (ccode-define name (format "cw_boxvar(~a, (void*) &(~a))"
 
377
                                (ccode-eval type) name)))
 
378
    (('define name ('make-c-func _ ret-type ('list arg-types ...)))
 
379
     (emit-define-cproc name ret-type arg-types)
 
380
     *dummy-line*)
 
381
    (('define sym expr)
 
382
     (ccode-define sym (ccode-eval expr)))
 
383
    ((('with-module 'c-wrapper 'define-enum) name val)
 
384
     (ccode-define name (format "Scm_MakeInteger(~a)" name)))
 
385
    (('init-c-struct! name members)
 
386
     (ccode-eval `(apply init-c-struct! (list ,name ,members))))
 
387
    (('init-c-union! name members)
 
388
     (ccode-eval `(apply init-c-union! (list ,name ,members))))
 
389
    (('c-enum tagname)
 
390
     (ccode-eval '<c-int>))
 
391
    (('init-c-enum! name symbols)
 
392
     *dummy-line*)
 
393
    (('export-all)
 
394
     "Scm_ExportAll(SCM_MODULE(__c_wrapper_mod))")
 
395
    (('export symbols ...)
 
396
     (format "Scm_ExportSymbols(SCM_MODULE(__c_wrapper_mod), ~a)"
 
397
             (ccode-eval `(list ,@(map (lambda (x) `(quote ,x)) symbols)))))
 
398
    ((? symbol? x)
 
399
     (ccode-lookup-value x))
 
400
    (#t
 
401
     "SCM_TRUE")
 
402
    (#f
 
403
     "SCM_FALSE")
 
404
    ((? string? x)
 
405
     (ccode-string x))
 
406
    ((? fixnum? x)
 
407
     (format "SCM_MAKE_INT(~a)" x))
 
408
    ((? number? x)
 
409
     (format "Scm_ReadFromCString(\"~a\")" x))
 
410
    (('list)
 
411
     "SCM_NIL")
 
412
    (('list a)
 
413
     (apply (cut format "SCM_LIST1(~a)" <>)
 
414
            (map ccode-eval (cdr expr))))
 
415
    (('list a b)
 
416
     (apply (cut format "SCM_LIST2(~a, ~a)" <> <>)
 
417
            (map ccode-eval (cdr expr))))
 
418
    (('list a b c)
 
419
     (apply (cut format "SCM_LIST3(~a, ~a, ~a)" <> <> <>)
 
420
            (map ccode-eval (cdr expr))))
 
421
    (('list a b c d)
 
422
     (apply (cut format "SCM_LIST4(~a, ~a, ~a, ~a)" <> <> <> <>)
 
423
            (map ccode-eval (cdr expr))))
 
424
    (('list a b c d e)
 
425
     (apply (cut format "SCM_LIST5(~a, ~a, ~a, ~a, ~a)" <> <> <> <> <>)
 
426
            (map ccode-eval (cdr expr))))
 
427
    (('list kar rest ...)
 
428
     (format "Scm_Cons(~a, ~a)" (ccode-eval kar) (ccode-eval `(list ,@rest))))
 
429
    (('quote #f)
 
430
     "SCM_FALSE")
 
431
    (('quote name)
 
432
     (ccode-intern name))
 
433
    (('cons kar kdr)
 
434
     (format "Scm_Cons(~a, ~a)" (ccode-eval kar) (ccode-eval kdr)))
 
435
    (('ptr ctype)
 
436
     (ccode-memoise-apply 'ptr (list ctype)))
 
437
    (('apply proc lst)
 
438
     (format "Scm_ApplyRec(~a, ~a)" (ccode-eval proc) (ccode-eval lst)))
 
439
    (('cast ctype val)
 
440
     (ccode-eval `(apply cast (list ,ctype ,val))))
 
441
    (('scm-cast val)
 
442
     (ccode-eval `(apply scm-cast (list ,val))))
 
443
    (('c-bit-field ctype n)
 
444
     (ccode-eval `(apply c-bit-field (list ,ctype ,n))))
 
445
    (('c-array ctype size)
 
446
     (ccode-memoise-apply 'c-array (list ctype size)))
 
447
    (('c-func-ptr rettype argtypes)
 
448
     (ccode-memoise-apply 'c-func-ptr (list rettype argtypes)))
 
449
    (('c-struct ('quote name))
 
450
     (ccode-eval ((with-module c-wrapper.c-ffi c-struct-symbol) name)))
 
451
    (('c-union ('quote name))
 
452
     (ccode-eval ((with-module c-wrapper.c-ffi c-union-symbol) name)))
 
453
    (('make-c-func-vaargs name rettype argtypes)
 
454
     (ccode-memoise-apply 'make-c-func-vaargs (list name rettype argtypes)))
 
455
    (('cexpr expr)
 
456
     expr)
 
457
    (else
 
458
     (format "Scm_EvalRec(~a, SCM_OBJ(__c_wrapper_mod))"
 
459
             (letrec ((traverse
 
460
                       (lambda (obj)
 
461
                         (cond
 
462
                          ((list? obj)
 
463
                           `(cexpr ,(ccode-eval `(list ,@(map traverse obj)))))
 
464
                          ((pair? obj)
 
465
                           `(cexpr
 
466
                             ,(ccode-eval `(cons ,(traverse (car obj))
 
467
                                                 ,(traverse (cdr obj))))))
 
468
                          ((symbol? obj)
 
469
                           `(cexpr ,(ccode-eval `(quote ,obj))))
 
470
                          ((or (number? obj)
 
471
                               (string? obj)
 
472
                               (boolean? obj))
 
473
                           `(cexpr ,(ccode-eval obj)))
 
474
                          (else
 
475
                           `(cexpr
 
476
                             ,(format "Scm_ReadFromCString(\"~s\")" obj)))))))
 
477
               (ccode-eval (traverse expr)))))))
 
478
 
 
479
(define (wrapper->c headers include-dirs options import-arg export?)
 
480
  (for-each emit-include headers)
 
481
  (with-input-from-string (c-parse include-dirs headers options
 
482
                                   import-arg export? (if import-arg
 
483
                                                          #t
 
484
                                                          #f))
 
485
    (lambda ()
 
486
      (port-for-each (lambda (expr)
 
487
                       (emit-initcode (ccode-eval expr))) read))))
 
488
 
 
489
(define (run-command command module compiled-lib headers include-dirs import-arg
 
490
                     export? cppflags cflags ldflags libs verbose?)
 
491
  (unless import-arg
 
492
    (c-ld (string-append ldflags libs)))
 
493
  (let* ((extension (path-sans-extension compiled-lib))
 
494
         (stub-file (path-swap-extension compiled-lib "stub"))
 
495
         (cmdlines (case command
 
496
                     ((compile)
 
497
                      (list #`"gauche-package compile ,(if verbose? \"--verbose\" \"\") --cflags=\",|cflags|\" --cppflags=\",|cppflags|\" --ldflags=\",|ldflags|\" --libs=\",|libs|\" ,|extension| ,|stub-file|"))
 
498
                     ((clean)
 
499
                      (list #`"gauche-package compile --clean ,(if verbose? \"--verbose\" \"\") ,|extension| ,|stub-file|"
 
500
                            #`"rm -f ,|stub-file|")))))
 
501
    (parameterize ((stub-unit (make-stub-unit module stub-file)))
 
502
      (wrapper->c (listize headers)
 
503
                  (listize include-dirs)
 
504
                  (string-split cppflags #[\s])
 
505
                  import-arg
 
506
                  export?)
 
507
      (write-stub (sys-dirname compiled-lib))
 
508
      (for-each (lambda (cmd)
 
509
                  (when verbose?
 
510
                    (print cmd))
 
511
                  (with-input-from-process cmd
 
512
                    (lambda ()
 
513
                      (port-for-each print read-line))))
 
514
                cmdlines))))
 
515
 
 
516
(define (compile-wrapper filename command
 
517
                         cflags-arg cppflags-arg ldflags-arg libs-arg verbose?)
 
518
  (with-input-from-file filename
 
519
    (lambda ()
 
520
      (let loop ((curmod 'user)
 
521
                 (expr (read))
 
522
                 (cppflags (list cppflags-arg))
 
523
                 (ldflags (list ldflags-arg))
 
524
                 (libs (list libs-arg)))
 
525
        (match expr
 
526
         ((? eof-object? v)
 
527
          #t)
 
528
 
 
529
         (('define-module module lst ...)
 
530
          (with-input-from-string (with-output-to-string
 
531
                                    (lambda ()
 
532
                                      (for-each (cut format #t "~s" <>) lst)))
 
533
            (lambda ()
 
534
              (loop module (read) cppflags ldflags libs)))
 
535
          (loop curmod (read) cppflags ldflags libs))
 
536
 
 
537
         (('use 'objc-wrapper)
 
538
          (loop curmod (read) (append cppflags (list "-ObjC")) ldflags libs))
 
539
 
 
540
         (('c-load-framework frameworks)
 
541
          (loop curmod (read) cppflags ldflags
 
542
                (append libs (map (lambda (fw)
 
543
                                    #`"-framework ,|fw|")
 
544
                                  (listize frameworks)))))
 
545
 
 
546
         (('c-ld keywords ...)
 
547
          (loop curmod `(c-load-library () ,@keywords)
 
548
                cppflags ldflags libs))
 
549
 
 
550
         (('c-load-library libs keywords ...)
 
551
          (let-keywords* keywords ((library-dirs '())
 
552
                                   (option ""))
 
553
            (let ((ldflags&libs
 
554
                   (fold (lambda (filename ldflags&libs)
 
555
                           (receive (dir lib _)
 
556
                               (decompose-path filename)
 
557
                             (cons
 
558
                              (append (car ldflags&libs)
 
559
                                      (if (string=? dir ".")
 
560
                                          '()
 
561
                                          (list #`"-L,|dir|")))
 
562
                              (append (cdr ldflags&libs)
 
563
                                      (let ((name (regexp-replace #/lib(.*)/
 
564
                                                                  "\\1")))
 
565
                                        (list #`"-l,|name|"))))))
 
566
                         (receive (libs ldflags)
 
567
                             (partition (cut string-prefix? "-l" <>)
 
568
                                        (string-split option #[\s]))
 
569
                           (cons ldflags libs))
 
570
                         (listize libs))))
 
571
              (loop curmod (read) cppflags
 
572
                    (append ldflags (car ldflags&libs))
 
573
                    (append libs (cdr ldflags&libs))))))
 
574
         
 
575
         (('c-include headers keywords ...)
 
576
          (let-keywords* keywords ((include-dirs '())
 
577
                                   (option "")
 
578
                                   (import-arg :import #f)
 
579
                                   (compiled-lib #f)
 
580
                                   (export? #f))
 
581
            (when compiled-lib
 
582
              (let* ((options (string-split option #[\s]))
 
583
                     (cppflags-str (string-join (append cppflags options) " "))
 
584
                     (ldflags-str (string-join ldflags " "))
 
585
                     (libs-str (string-join libs " ")))
 
586
                (run-command command
 
587
                             curmod
 
588
                             compiled-lib
 
589
                             headers
 
590
                             include-dirs
 
591
                             (eval import-arg (current-module))
 
592
                             export?
 
593
                             cppflags-str "" ldflags-str libs-str
 
594
                             verbose?))))
 
595
          (loop curmod (read) cppflags ldflags libs))
 
596
 
 
597
         (('c-load headers keywords ...)
 
598
          (let-keywords* keywords ((cflags-str :cflags "")
 
599
                                   (cflags-cmd #f)
 
600
                                   (cppflags-str :cppflags "")
 
601
                                   (cppflags-cmd #f)
 
602
                                   (ldflags-str :ldflags "")
 
603
                                   (ldflags-cmd #f)
 
604
                                   (libs-str :libs "")
 
605
                                   (libs-cmd #f)
 
606
                                   (compiled-lib #f)
 
607
                                   (import-arg :import #f)
 
608
                                   (export? #f))
 
609
            (when compiled-lib
 
610
              (let ((append-cmd
 
611
                     (lambda (flags str cmd)
 
612
                       (string-join (append (reverse flags)
 
613
                                            (list str)
 
614
                                            (list (cond
 
615
                                                   (cmd => process-output->string)
 
616
                                                   (else ""))))
 
617
                                    " "))))
 
618
                (run-command command
 
619
                             curmod
 
620
                             compiled-lib
 
621
                             headers
 
622
                             '()
 
623
                             (eval import-arg (current-module))
 
624
                             export?
 
625
                             (append-cmd cppflags cppflags-str cppflags-cmd)
 
626
                             (append-cmd '() cflags-str cflags-cmd)
 
627
                             (append-cmd ldflags ldflags-str ldflags-cmd)
 
628
                             (append-cmd libs libs-str libs-cmd)
 
629
                             verbose?))))
 
630
          (loop curmod (read) cppflags ldflags libs))
 
631
         
 
632
         (('select-module module)
 
633
          (loop module (read) cppflags ldflags libs))
 
634
 
 
635
         (else
 
636
          (loop curmod (read) cppflags ldflags libs)))))))
 
637
 
 
638
(provide "c-wrapper/stubgen")
 
639
 
 
640
;; end of file