(in-package :SB-GROVEL) (defvar *export-symbols* nil) (defun c-for-structure (stream lisp-name c-struct) (destructuring-bind (c-name &rest elements) c-struct (format stream "printf(\"(sb-grovel::define-c-struct ~A %d)\\n\",sizeof (~A));~%" lisp-name c-name) (dolist (e elements) (destructuring-bind (lisp-type lisp-el-name c-type c-el-name &key distrust-length) e ;; FIXME: this format string doesn't actually guarantee ;; non-multilined-string-constantness, it just makes it more ;; likely. Sort out the required behaviour (and maybe make ;; the generated C more readable, while we're at it...) -- ;; CSR, 2003-05-27 (format stream "printf(\"(sb-grovel::define-c-accessor ~A-~A\\n\\~% ~ ~A ~A \");~%" lisp-name lisp-el-name lisp-name lisp-type) ;; offset (format stream "{ ~A t;printf(\"%d \",((unsigned long)&(t.~A)) - ((unsigned long)&(t)) ); }~%" c-name c-el-name) ;; length (if distrust-length (format stream "printf(\"|CL|:|NIL|\");") (format stream "{ ~A t;printf(\"%d\",(sizeof t.~A));}~%" c-name c-el-name)) (format stream "printf(\")\\n\");~%"))))) (defun c-for-function (stream lisp-name alien-defn) (destructuring-bind (c-name &rest definition) alien-defn (format stream "printf(\"(cl:declaim (cl:inline ~A))\\n\");~%" lisp-name) (format stream "printf(\"(sb-grovel::define-foreign-routine (\\\"~A\\\" ~A)\\n\\~%~ ~{ ~W~^\\n\\~%~})\\n\");~%" c-name lisp-name definition))) (defun print-c-source (stream headers definitions package-name) (let ((*print-right-margin* nil)) (format stream "#define SIGNEDP(x) (((x)-1)<0)~%") (format stream "#define SIGNED_(x) (SIGNEDP(x)?\"\":\"un\")~%") (loop for i in (cons "stdio.h" headers) do (format stream "#include <~A>~%" i)) (format stream "main() { ~% printf(\"(in-package ~S)\\\n\");~%" package-name) (format stream "printf(\"(cl:deftype int () '(%ssigned-byte %d))\\\n\",SIGNED_(int),8*sizeof (int));~%") (format stream "printf(\"(cl:deftype char () '(%ssigned-byte %d))\\\n\",SIGNED_(char),8*sizeof (char));~%") (format stream "printf(\"(cl:deftype long () '(%ssigned-byte %d))\\\n\",SIGNED_(long),8*sizeof (long));~%") (format stream "printf(\"(cl:defconstant size-of-int %d)\\\n\",sizeof (int));~%") (format stream "printf(\"(cl:defconstant size-of-char %d)\\\n\",sizeof (char));~%") (format stream "printf(\"(cl:defconstant size-of-long %d)\\\n\",sizeof (long));~%") (dolist (def definitions) (destructuring-bind (type lispname cname &optional doc) def (cond ((eq type :integer) (format stream "#ifdef ~A~%~ printf(\"(cl:defconstant ~A %d \\\"~A\\\")\\\n\",~A);~%~ #else~%~ printf(\"(sb-int:style-warn \\\"Couln't grovel definition for ~A (unknown to the C compiler).\\\")\\n\");~%~ #endif~%" cname lispname doc cname cname)) ((eq type :type) (format stream "printf(\"(sb-alien:define-alien-type ~A (sb-alien:%ssigned %d))\\\n\",SIGNED_(~A),8*(sizeof(~A)));~%" lispname cname cname)) ((eq type :string) (format stream "printf(\"(cl:defvar ~A %S \\\"~A\\\")\\\n\",~A);~%" lispname doc cname)) ((eq type :function) (c-for-function stream lispname cname)) ((eq type :structure) (c-for-structure stream lispname cname)) (t (format stream "printf(\";; Non hablo Espagnol, Monsieur~%"))))) (format stream "exit(0);~%}~%"))) (defun c-constants-extract (filename output-file package) (with-open-file (f output-file :direction :output) (with-open-file (i filename :direction :input) (let* ((headers (read i)) (definitions (read i))) (print-c-source f headers definitions package))))) (defclass grovel-constants-file (asdf:cl-source-file) ((package :accessor constants-package :initarg :package))) (defmethod asdf:perform ((op asdf:compile-op) (component grovel-constants-file)) ;; we want to generate all our temporary files in the fasl directory ;; because that's where we have write permission. Can't use /tmp; ;; it's insecure (these files will later be owned by root) (let* ((output-file (car (output-files op component))) (filename (component-pathname component)) (real-output-file (if (typep output-file 'logical-pathname) (translate-logical-pathname output-file) (pathname output-file))) (tmp-c-source (merge-pathnames #p"foo.c" real-output-file)) (tmp-a-dot-out (merge-pathnames #p"a.out" real-output-file)) (tmp-constants (merge-pathnames #p"constants.lisp-temp" real-output-file))) (princ (list filename output-file real-output-file tmp-c-source tmp-a-dot-out tmp-constants)) (terpri) (funcall (intern "C-CONSTANTS-EXTRACT" (find-package "SB-GROVEL")) filename tmp-c-source (constants-package component)) (and (= (run-shell-command "gcc -o ~S ~S" (namestring tmp-a-dot-out) (namestring tmp-c-source)) 0) (= (run-shell-command "~A >~A" (namestring tmp-a-dot-out) (namestring tmp-constants)) 0) (compile-file tmp-constants :output-file output-file))))