1 ;;;; -*- Mode: lisp; indent-tabs-mode: nil -*-
3 ;;; cffi-gcl.lisp --- CFFI-SYS implementation for GNU Common Lisp.
5 ;;; Copyright (C) 2005-2006, Luis Oliveira <loliveira(@)common-lisp.net>
7 ;;; Permission is hereby granted, free of charge, to any person
8 ;;; obtaining a copy of this software and associated documentation
9 ;;; files (the "Software"), to deal in the Software without
10 ;;; restriction, including without limitation the rights to use, copy,
11 ;;; modify, merge, publish, distribute, sublicense, and/or sell copies
12 ;;; of the Software, and to permit persons to whom the Software is
13 ;;; furnished to do so, subject to the following conditions:
15 ;;; The above copyright notice and this permission notice shall be
16 ;;; included in all copies or substantial portions of the Software.
18 ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 ;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 ;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 ;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 ;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 ;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 ;;; DEALINGS IN THE SOFTWARE.
28 ;;; GCL specific notes:
30 ;;; On ELF systems, a library can be loaded with the help of this:
31 ;;; http://www.copyleft.de/lisp/gcl-elf-loader.html
33 ;;; Another way is to link the library when creating a new image:
34 ;;; (compiler::link nil "new_image" "" "-lfoo")
36 ;;; As GCL's FFI is not dynamic, CFFI declarations will only work
37 ;;; after compiled and loaded.
39 ;;; *** this port is broken ***
40 ;;; gcl doesn't compile the rest of CFFI anyway..
42 (in-package #:cffi-sys
)
45 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
46 (pushnew :cffi
/no-foreign-funcall
*features
*))
50 (defun canonicalize-symbol-name-case (name)
51 (declare (string name
))
56 ;;; Functions and macros for allocating foreign memory on the stack
57 ;;; and on the heap. The main CFFI package defines macros that wrap
58 ;;; FOREIGN-ALLOC and FOREIGN-FREE in UNWIND-PROTECT for the common
59 ;;; usage when the memory has dynamic extent.
61 (defentry %foreign-alloc
(int) (int "malloc"))
63 ;(defun foreign-alloc (size)
64 ; "Allocate SIZE bytes on the heap and return a pointer."
65 ; (%foreign-alloc size))
67 (defentry foreign-free
(int) (void "free"))
69 ;(defun foreign-free (ptr)
70 ; "Free a PTR allocated by FOREIGN-ALLOC."
73 (defmacro with-foreign-ptr
((var size
&optional size-var
) &body body
)
74 "Bind VAR to SIZE bytes of foreign memory during BODY. The
75 pointer in VAR is invalid beyond the dynamic extent of BODY, and
76 may be stack-allocated if supported by the implementation. If
77 SIZE-VAR is supplied, it will be bound to SIZE during BODY."
79 (setf size-var
(gensym "SIZE")))
80 `(let* ((,size-var
,size
)
81 (,var
(foreign-alloc ,size-var
)))
84 (foreign-free ,var
))))
86 ;;;# Misc. Pointer Operations
89 "Return true if PTR is a foreign pointer."
93 "Construct and return a null pointer."
96 (defun null-ptr-p (ptr)
97 "Return true if PTR is a null pointer."
100 (defun inc-ptr (ptr offset
)
101 "Return a pointer OFFSET bytes past PTR."
104 ;;;# Shareable Vectors
106 ;;; This interface is very experimental. WITH-POINTER-TO-VECTOR-DATA
107 ;;; should be defined to perform a copy-in/copy-out if the Lisp
108 ;;; implementation can't do this.
110 ;(defun make-shareable-byte-vector (size)
111 ; "Create a Lisp vector of SIZE bytes that can passed to
112 ;WITH-POINTER-TO-VECTOR-DATA."
113 ; (make-array size :element-type '(unsigned-byte 8)))
115 ;(defmacro with-pointer-to-vector-data ((ptr-var vector) &body body)
116 ; "Bind PTR-VAR to a foreign pointer to the data in VECTOR."
117 ; `(ccl:with-pointer-to-ivector (,ptr-var ,vector)
122 (defmacro define-mem-ref
/set
(type gcl-type
&optional c-name
)
124 (setq c-name
(substitute #\_
#\Space type
)))
125 (let ((ref-fn (concatenate 'string
"ref_" c-name
))
126 (set-fn (concatenate 'string
"set_" c-name
)))
129 (defcfun ,(format nil
"~A ~A(~A *ptr)" type ref-fn type
)
131 (defentry ,(intern (string-upcase (substitute #\-
#\_ ref-fn
)))
132 (int) (,gcl-type
,ref-fn
))
134 (defcfun ,(format nil
"void ~A(~A *ptr, ~A value)" set-fn type type
)
136 (defentry ,(intern (string-upcase (substitute #\-
#\_ set-fn
)))
137 (int ,gcl-type
) (void ,set-fn
)))))
139 (define-mem-ref/set
"char" char
)
140 (define-mem-ref/set
"unsigned char" char
)
141 (define-mem-ref/set
"short" int
)
142 (define-mem-ref/set
"unsigned short" int
)
143 (define-mem-ref/set
"int" int
)
144 (define-mem-ref/set
"unsigned int" int
)
145 (define-mem-ref/set
"long" int
)
146 (define-mem-ref/set
"unsigned long" int
)
147 (define-mem-ref/set
"float" float
)
148 (define-mem-ref/set
"double" double
)
149 (define-mem-ref/set
"void *" int
"ptr")
151 (defun %mem-ref
(ptr type
&optional
(offset 0))
152 "Dereference an object of TYPE at OFFSET bytes from PTR."
153 (unless (zerop offset
)
156 (:char
(ref-char ptr
))
157 (:unsigned-char
(ref-unsigned-char ptr
))
158 (:short
(ref-short ptr
))
159 (:unsigned-short
(ref-unsigned-short ptr
))
161 (:unsigned-int
(ref-unsigned-int ptr
))
162 (:long
(ref-long ptr
))
163 (:unsigned-long
(ref-unsigned-long ptr
))
164 (:float
(ref-float ptr
))
165 (:double
(ref-double ptr
))
166 (:pointer
(ref-ptr ptr
))))
168 (defun %mem-set
(value ptr type
&optional
(offset 0))
169 (unless (zerop offset
)
172 (:char
(set-char ptr value
))
173 (:unsigned-char
(set-unsigned-char ptr value
))
174 (:short
(set-short ptr value
))
175 (:unsigned-short
(set-unsigned-short ptr value
))
176 (:int
(set-int ptr value
))
177 (:unsigned-int
(set-unsigned-int ptr value
))
178 (:long
(set-long ptr value
))
179 (:unsigned-long
(set-unsigned-long ptr value
))
180 (:float
(set-float ptr value
))
181 (:double
(set-double ptr value
))
182 (:pointer
(set-ptr ptr value
)))
185 ;;;# Calling Foreign Functions
187 ;; TODO: figure out if these type conversions make any sense...
188 (defun convert-foreign-type (type-keyword)
189 "Convert a CFFI type keyword to a GCL type."
192 (:unsigned-char
'char
)
194 (:unsigned-short
'int
)
198 (:unsigned-long
'int
)
204 (defparameter +cffi-types
+
205 '(:char
:unsigned-char
:short
:unsigned-short
:int
:unsigned-int
206 :long
:unsigned-long
:float
:double
:pointer
))
208 (defcfun "int size_of(int type)" 0
210 case 0: return sizeof(char);
211 case 1: return sizeof(unsigned char);
212 case 2: return sizeof(short);
213 case 3: return sizeof(unsigned short);
214 case 4: return sizeof(int);
215 case 5: return sizeof(unsigned int);
216 case 6: return sizeof(long);
217 case 7: return sizeof(unsigned long);
218 case 8: return sizeof(float);
219 case 9: return sizeof(double);
220 case 10: return sizeof(void *);
224 (defentry size-of
(int) (int "size_of"))
226 ;; TODO: all this is doable inside the defcfun; figure that out..
227 (defun %foreign-type-size
(type-keyword)
228 "Return the size in bytes of a foreign type."
229 (size-of (position type-keyword
+cffi-types
+)))
231 (defcfun "int align_of(int type)" 0
233 case 0: return __alignof__(char);
234 case 1: return __alignof__(unsigned char);
235 case 2: return __alignof__(short);
236 case 3: return __alignof__(unsigned short);
237 case 4: return __alignof__(int);
238 case 5: return __alignof__(unsigned int);
239 case 6: return __alignof__(long);
240 case 7: return __alignof__(unsigned long);
241 case 8: return __alignof__(float);
242 case 9: return __alignof__(double);
243 case 10: return __alignof__(void *);
247 (defentry align-of
(int) (int "align_of"))
249 ;; TODO: like %foreign-type-size
250 (defun %foreign-type-alignment
(type-keyword)
251 "Return the alignment in bytes of a foreign type."
252 (align-of (position type-keyword
+cffi-types
+)))
255 (defun convert-external-name (name)
256 "Add an underscore to NAME if necessary for the ABI."
257 #+darwinppc-target
(concatenate 'string
"_" name
)
258 #-darwinppc-target name
)
260 (defmacro %foreign-funcall
(function-name &rest args
)
261 "Perform a foreign function all, document it more later."
262 `(format t
"~&;; Calling ~A with args ~S.~%" ,name
',args
))
264 (defun defcfun-helper-forms (name rettype args types
)
265 "Return 2 values for DEFCFUN. A prelude form and a caller form."
266 (let ((ff-name (intern (format nil
"%foreign-function/TildeA:~A" name
))))
268 `(defentry ,ff-name
,(mapcar #'convert-foreign-type types
)
269 (,(convert-foreign-type rettype
) ,name
))
270 `(,ff-name
,@args
))))
274 ;;; XXX unimplemented
275 (defmacro make-callback
(name rettype arg-names arg-types body-form
)
278 ;;;# Loading Foreign Libraries
280 (defun %load-foreign-library
(name)
281 "_Won't_ load the foreign library NAME."
282 (declare (ignore name
)))
286 ;;; XXX unimplemented
287 (defmacro foreign-var-ptr
(name)
288 "Return a pointer pointing to the foreign symbol NAME."