88e4bae92b9be549bd649677c493199badb0cc16
[sbcl.git] / contrib / sb-grovel / def-to-lisp.lisp
1 (in-package :SB-GROVEL)
2 (defvar *export-symbols* nil)
3
4 (defun c-for-structure (stream lisp-name c-struct)
5   (destructuring-bind (c-name &rest elements) c-struct
6     (format stream "printf(\"(sb-grovel::define-c-struct ~A %d)\\n\",sizeof (~A));~%" lisp-name c-name)
7     (dolist (e elements)
8       (destructuring-bind (lisp-type lisp-el-name c-type c-el-name &key distrust-length) e
9         ;; FIXME: this format string doesn't actually guarantee
10         ;; non-multilined-string-constantness, it just makes it more
11         ;; likely.  Sort out the required behaviour (and maybe make
12         ;; the generated C more readable, while we're at it...) --
13         ;; CSR, 2003-05-27
14         (format stream "printf(\"(sb-grovel::define-c-accessor ~A-~A\\n\\~%  ~
15                         ~A ~A \");~%"
16                 lisp-name lisp-el-name lisp-name lisp-type)
17         ;; offset
18         (format stream "{ ~A t;printf(\"%d \",((unsigned long)&(t.~A)) - ((unsigned long)&(t)) ); }~%"
19                 c-name c-el-name)
20         ;; length
21         (if distrust-length
22             (format stream "printf(\"|CL|:|NIL|\");")
23             (format stream "{ ~A t;printf(\"%d\",(sizeof t.~A));}~%"
24                     c-name c-el-name))
25         (format stream "printf(\")\\n\");~%")))))
26
27 (defun c-for-function (stream lisp-name alien-defn)
28   (destructuring-bind (c-name &rest definition) alien-defn
29     (format stream "printf(\"(cl:declaim (cl:inline ~A))\\n\");~%" lisp-name)
30     (format stream
31             "printf(\"(sb-grovel::define-foreign-routine (\\\"~A\\\" ~A)\\n\\~%~
32             ~{  ~W~^\\n\\~%~})\\n\");~%"
33             c-name lisp-name definition)))
34
35 (defun print-c-source (stream headers definitions package-name)
36   (let ((*print-right-margin* nil))
37     (format stream "#define SIGNEDP(x) (((x)-1)<0)~%")
38     (format stream "#define SIGNED_(x) (SIGNEDP(x)?\"\":\"un\")~%")
39     (loop for i in (cons "stdio.h" headers)
40           do (format stream "#include <~A>~%" i))
41     (format stream "main() { ~%
42 printf(\"(in-package ~S)\\\n\");~%" package-name)  
43     (format stream "printf(\"(cl:deftype int () '(%ssigned-byte %d))\\\n\",SIGNED_(int),8*sizeof (int));~%")
44     (format stream "printf(\"(cl:deftype char () '(%ssigned-byte %d))\\\n\",SIGNED_(char),8*sizeof (char));~%")
45     (format stream "printf(\"(cl:deftype long () '(%ssigned-byte %d))\\\n\",SIGNED_(long),8*sizeof (long));~%")
46     (format stream "printf(\"(cl:defconstant size-of-int %d)\\\n\",sizeof (int));~%")
47     (format stream "printf(\"(cl:defconstant size-of-char %d)\\\n\",sizeof (char));~%")
48     (format stream "printf(\"(cl:defconstant size-of-long %d)\\\n\",sizeof (long));~%")
49     (dolist (def definitions)
50       (destructuring-bind (type lispname cname &optional doc) def
51         (cond ((eq type :integer)
52                (format stream
53                        "#ifdef ~A~%~
54                         printf(\"(cl:defconstant ~A %d \\\"~A\\\")\\\n\",~A);~%~
55                         #else~%~
56                         printf(\"(sb-int:style-warn \\\"Couln't grovel definition for ~A (unknown to the C compiler).\\\")\\n\");~%~
57                         #endif~%"
58                        cname lispname doc cname cname))
59               ((eq type :type)
60                (format stream
61                        "printf(\"(sb-alien:define-alien-type ~A (sb-alien:%ssigned %d))\\\n\",SIGNED_(~A),8*(sizeof(~A)));~%"
62                        lispname cname cname))
63               ((eq type :string)
64                (format stream
65                        "printf(\"(cl:defvar ~A %S \\\"~A\\\")\\\n\",~A);~%"
66                      lispname doc cname))
67               ((eq type :function)
68                (c-for-function stream lispname cname))
69               ((eq type :structure)
70                (c-for-structure stream lispname cname))
71               (t
72                (format stream
73                        "printf(\";; Non hablo Espagnol, Monsieur~%")))))
74     (format stream "exit(0);~%}~%")))
75
76 (defun c-constants-extract  (filename output-file package)
77   (with-open-file (f output-file :direction :output)
78     (with-open-file (i filename :direction :input)
79       (let* ((headers (read i))
80              (definitions (read i)))
81         (print-c-source  f headers definitions package)))))
82
83 (defclass grovel-constants-file (asdf:cl-source-file)
84   ((package :accessor constants-package :initarg :package)))
85
86 (defmethod asdf:perform ((op asdf:compile-op)
87                          (component grovel-constants-file))
88   ;; we want to generate all our temporary files in the fasl directory
89   ;; because that's where we have write permission.  Can't use /tmp;
90   ;; it's insecure (these files will later be owned by root)
91   (let* ((output-file (car (output-files op component)))
92          (filename (component-pathname component))
93          (real-output-file
94           (if (typep output-file 'logical-pathname)
95               (translate-logical-pathname output-file)
96               (pathname output-file)))
97          (tmp-c-source (merge-pathnames #p"foo.c" real-output-file))
98          (tmp-a-dot-out (merge-pathnames #p"a.out" real-output-file))
99          (tmp-constants (merge-pathnames #p"constants.lisp-temp"
100                                          real-output-file)))
101     (princ (list filename output-file real-output-file
102                  tmp-c-source tmp-a-dot-out tmp-constants))
103     (terpri)
104     (funcall (intern "C-CONSTANTS-EXTRACT" (find-package "SB-GROVEL"))
105              filename tmp-c-source (constants-package component))
106     (and                
107      (= (run-shell-command "gcc ~A -o ~S ~S"
108                            (if (sb-ext:posix-getenv "CFLAGS")
109                                (sb-ext:posix-getenv "CFLAGS")
110                                 "")
111                            (namestring tmp-a-dot-out)
112                            (namestring tmp-c-source)) 0)
113      (= (run-shell-command "~A >~A"
114                            (namestring tmp-a-dot-out)
115                            (namestring tmp-constants)) 0)
116      (compile-file tmp-constants :output-file output-file))))
117