changeset 149: | 2d1fe1d7b738 |
parent: | 85f27597cf60 |
child: | 7f8880bd2ac6 |
author: | ellis <ellis@rwest.io> |
date: | Sat, 30 Dec 2023 20:50:15 -0500 |
permissions: | -rw-r--r-- |
description: | ffi update to support darwin, smh |
96 | 1 | ;;; alien.lisp --- foreign alien friends |
5 | 2 | |
3 | ;;; Commentary: |
|
4 | ||
5 | ;; FFI in Lisp is somewhat different than FFI in other host langs. As |
|
6 | ;; such, we usually refer to our Lispy FFI interfaces inline with the |
|
7 | ;; CMUCL terminology: alien interfaces. |
|
8 | ||
9 | ;; ref: https://www.sbcl.org/manual/#Foreign-Function-Interface for details |
|
10 | ||
11 | ;; sb-alien is a high-level interface which automatically converts C |
|
12 | ;; memory pointers to lisp objects and back, but this can be slow for |
|
13 | ;; large or complex objects. |
|
14 | ||
15 | ;; The lower-level interface is based on System Area Pointers (or |
|
16 | ;; SAPs), which provide untyped access to foreign memory. |
|
17 | ||
18 | ;; Objects which can't be automatically converted into Lisp values are |
|
19 | ;; represented by objects of type ALIEN-VALUE. |
|
20 | ||
21 | ;;; Code: |
|
96 | 22 | (in-package :std) |
5 | 23 | ;; (reexport-from :sb-vm |
96 | 24 | ;; :include |
25 | ;; '(:with-pinned-objects :with-pinned-object-iterator :with-code-pages-pinned |
|
26 | ;; :sanctify-for-execution)) |
|
5 | 27 | |
149 | 28 | (defun shared-object-name (name) |
29 | "Return a filename with the correct extension for a shared library |
|
30 | on Linux and Darwin." |
|
31 | (format nil "lib~a.~a" name #+darwin "dylib" #-darwin "so")) |
|
32 | ||
33 | (defmacro define-alien-loader (name &optional export) |
|
34 | "Define a default loader function named load-NAME which calls |
|
35 | SB-ALIEN:LOAD-SHARED-OBJECT." |
|
36 | (let ((fname (sb-int:symbolicate 'load- name))) |
|
37 | `(prog1 |
|
38 | (defun ,fname (&optional save) |
|
39 | (prog1 (sb-alien:load-shared-object (shared-object-name ',name) :dont-save (not save)) |
|
40 | (pushnew ,(sb-int:keywordicate name) *features*))) |
|
41 | ,@(when export (list `(export '(,fname))))))) |
|
42 | |
|
110
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
43 | (defmacro define-opaque (ty &optional no-export) |
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
44 | `(prog1 |
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
45 | (define-alien-type ,ty (struct ,(symbolicate ty '-t))) |
cae8da4b1415
rocksdb macrofication, fixes for RDB (C Strings will be the death of me), removed PWN - quicklisp package conflict, smh.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
46 | ,(unless no-export `(export '(,ty))))) |
88 | 47 | |
82 | 48 | (defun setfa (place from) |
49 | (loop for x across from |
|
50 | for i from 0 below (length from) |
|
51 | do (setf (deref place i) x))) |
|
52 | ||
5 | 53 | (defun copy-c-string (src dest &aux (index 0)) |
54 | (loop (let ((b (sb-sys:sap-ref-8 src index))) |
|
55 | (when (= b 0) |
|
56 | (setf (fill-pointer dest) index) |
|
57 | (return)) |
|
58 | (setf (char dest index) (code-char b)) |
|
59 | (incf index)))) |
|
60 | ||
61 | (defun clone-strings (list) |
|
62 | (with-alien ((x (* (* char)) |
|
63 | (make-alien (* char) (length list)))) |
|
64 | (unwind-protect |
|
65 | (labels ((populate (list index function) |
|
66 | (if list |
|
67 | (let ((array (sb-ext:string-to-octets (car list) :null-terminate t))) |
|
68 | (sb-sys:with-pinned-objects (array) |
|
69 | (setf (deref x index) (sap-alien (sb-sys:vector-sap array) (* char))) |
|
70 | (populate (cdr list) (1+ index) function))) |
|
71 | (funcall function)))) |
|
72 | (populate list 0 |
|
73 | (lambda () |
|
74 | (loop for i below (length list) |
|
75 | do (print (cast (deref x i) c-string)))))) |
|
76 | (free-alien x)))) |
|
77 | ||
82 | 78 | (defmacro clone-octets-to-alien (lispa aliena) |
79 | (with-gensyms (i) |
|
80 | `(loop for ,i from 0 below (length ,lispa) |
|
81 | do (setf (deref ,aliena ,i) |
|
82 | (aref ,lispa ,i))))) |
|
47 | 83 | |
82 | 84 | (defmacro clone-octets-from-alien (aliena lispa len) |
85 | (with-gensyms (i) |
|
86 | `(loop for ,i from 0 below ,len |
|
87 | do (setf (aref ,lispa ,i) |
|
88 | (deref ,aliena ,i))))) |
|
47 | 89 | |
5 | 90 | (defun foreign-int-to-integer (buffer size) |
91 | "Check SIZE of int BUFFER. return BUFFER." |
|
92 | (assert (= size (sb-alien:alien-size sb-alien:int :bytes))) |
|
93 | buffer) |
|
94 | ||
95 | (defun foreign-int-to-bool (x size) |
|
96 | (if (zerop (foreign-int-to-integer x size)) |
|
97 | nil |
|
98 | t)) |
|
99 | ||
100 | (defun bool-to-foreign-int (val) |
|
101 | (if val 1 0)) |
|
102 | ||
119 | 103 | ;;; Bits |
104 | (defun make-bits (length &rest args) |
|
105 | (apply #'make-array length (nconc '(:element-type bit) args))) |
|
106 | ||
5 | 107 | ;;; Bytes |
96 | 108 | ;; (defmacro defbytes (&body bitsets) |
109 | ;; "For each cons-cell in BITSETS, define a new CAR-byte type for each |
|
110 | ;; member of CDR." |
|
111 | ;; `(loop for set in ',bitsets |
|
112 | ;; collect |
|
113 | ;; (let* ((ty (car set)) |
|
114 | ;; (pfx |
|
115 | ;; (cond |
|
116 | ;; ((eq 'signed-byte ty) "I") |
|
117 | ;; ((eq 'unsigned-byte ty) "U") |
|
118 | ;; ((eq 'float ty) "F") |
|
119 | ;; (t (subseq (symbol-name ty) 0 1)))) |
|
120 | ;; (nums (cdr set)) |
|
121 | ;; r) ;result |
|
122 | ;; (setf r |
|
123 | ;; (mapc |
|
124 | ;; (lambda (x) |
|
125 | ;; `(deftype ,(symbolicate pfx (format 'nil "~a" x)) () |
|
126 | ;; (cons ,ty ,x))) |
|
127 | ;; nums)) |
|
128 | ;; (cons ty r)))) |
|
5 | 129 | |
96 | 130 | ;; (defbytes |
131 | ;; (unsigned-byte 1 2 3 4 8 16 24 32 64 128) |
|
132 | ;; (signed-byte 2 3 4 8 16 24 32 64 128) |
|
133 | ;; (float 16 24 32 64 128)) |