1 (in-package :SB-GROVEL)
2 (defvar *export-symbols* nil)
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)
8 (destructuring-bind (lisp-type lisp-el-name c-type c-el-name) 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...) --
14 (format stream "printf(\"(sb-grovel::define-c-accessor ~A-~A\\n\\~% ~
16 lisp-name lisp-el-name lisp-name lisp-type)
18 (format stream "{ ~A t;printf(\"%d \",((unsigned long)&(t.~A)) - ((unsigned long)&(t)) ); }~%"
21 (format stream "{ ~A t;printf(\"%d\",(sizeof t.~A));}~%"
23 (format stream "printf(\")\\n\");~%")))))
25 (defun c-for-function (stream lisp-name alien-defn)
26 (destructuring-bind (c-name &rest definition) alien-defn
27 (format stream "printf(\"(cl:declaim (cl:inline ~A))\\n\");~%" lisp-name)
29 "printf(\"(sb-grovel::define-foreign-routine (\\\"~A\\\" ~A)\\n\\~%~
30 ~{ ~W~^\\n\\~%~})\\n\");~%"
31 c-name lisp-name definition)))
33 (defun print-c-source (stream headers definitions package-name)
34 (let ((*print-right-margin* nil))
35 (format stream "#define SIGNEDP(x) (((x)-1)<0)~%")
36 (format stream "#define SIGNED_(x) (SIGNEDP(x)?\"\":\"un\")~%")
37 (loop for i in (cons "stdio.h" headers)
38 do (format stream "#include <~A>~%" i))
39 (format stream "main() { ~%
40 printf(\"(in-package ~S)\\\n\");~%" package-name)
41 (format stream "printf(\"(cl:deftype int () '(%ssigned-byte %d))\\\n\",SIGNED_(int),8*sizeof (int));~%")
42 (format stream "printf(\"(cl:deftype char () '(%ssigned-byte %d))\\\n\",SIGNED_(char),8*sizeof (char));~%")
43 (format stream "printf(\"(cl:deftype long () '(%ssigned-byte %d))\\\n\",SIGNED_(long),8*sizeof (long));~%")
44 (format stream "printf(\"(cl:defconstant size-of-int %d)\\\n\",sizeof (int));~%")
45 (format stream "printf(\"(cl:defconstant size-of-char %d)\\\n\",sizeof (char));~%")
46 (format stream "printf(\"(cl:defconstant size-of-long %d)\\\n\",sizeof (long));~%")
47 (dolist (def definitions)
48 (destructuring-bind (type lispname cname &optional doc) def
49 (cond ((eq type :integer)
51 "printf(\"(cl:defconstant ~A %d \\\"~A\\\")\\\n\",~A);~%"
55 "printf(\"(sb-alien:define-alien-type ~A (sb-alien:%ssigned %d))\\\n\",SIGNED_(~A),8*(sizeof(~A)));~%"
56 lispname cname cname))
59 "printf(\"(cl:defvar ~A %S \\\"~A\\\")\\\n\",~A);~%"
62 (c-for-function stream lispname cname))
64 (c-for-structure stream lispname cname))
67 "printf(\";; Non hablo Espagnol, Monsieur~%")))))
68 (format stream "exit(0);~%}~%")))
70 (defun c-constants-extract (filename output-file package)
71 (with-open-file (f output-file :direction :output)
72 (with-open-file (i filename :direction :input)
73 (let* ((headers (read i))
74 (definitions (read i)))
75 (print-c-source f headers definitions package)))))
77 (defclass grovel-constants-file (asdf:cl-source-file)
78 ((package :accessor constants-package :initarg :package)))
80 (defmethod asdf:perform ((op asdf:compile-op)
81 (component grovel-constants-file))
82 ;; we want to generate all our temporary files in the fasl directory
83 ;; because that's where we have write permission. Can't use /tmp;
84 ;; it's insecure (these files will later be owned by root)
85 (let* ((output-file (car (output-files op component)))
86 (filename (component-pathname component))
88 (if (typep output-file 'logical-pathname)
89 (translate-logical-pathname output-file)
90 (pathname output-file)))
91 (tmp-c-source (merge-pathnames #p"foo.c" real-output-file))
92 (tmp-a-dot-out (merge-pathnames #p"a.out" real-output-file))
93 (tmp-constants (merge-pathnames #p"constants.lisp-temp"
95 (princ (list filename output-file real-output-file
96 tmp-c-source tmp-a-dot-out tmp-constants))
98 (funcall (intern "C-CONSTANTS-EXTRACT" (find-package "SB-GROVEL"))
99 filename tmp-c-source (constants-package component))
101 (= (run-shell-command "gcc -o ~S ~S" (namestring tmp-a-dot-out)
102 (namestring tmp-c-source)) 0)
103 (= (run-shell-command "~A >~A"
104 (namestring tmp-a-dot-out)
105 (namestring tmp-constants)) 0)
106 (compile-file tmp-constants :output-file output-file))))