From 8ed7e411c55bd4db8036c17485268de07a303539 Mon Sep 17 00:00:00 2001 From: Nathaniel Nicandro Date: Thu, 14 Dec 2017 10:46:43 -0600 Subject: [PATCH 1/2] Define library as a constant instead of a function --- ffi.el | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ffi.el b/ffi.el index 64f53a3..1f8c5b2 100644 --- a/ffi.el +++ b/ffi.el @@ -7,11 +7,8 @@ (gv-define-simple-setter ffi--mem-ref ffi--mem-set t) (defmacro define-ffi-library (symbol name) - (let ((library (cl-gensym))) - (set library nil) - `(defun ,symbol () - (or ,library - (setq ,library (ffi--dlopen ,name)))))) + `(defconst ,(intern (concat "ffi-" (symbol-name symbol))) + (ffi--dlopen ,name))) (defmacro define-ffi-function (name c-name return-type arg-types library) (let* ( From 995894f9026343245db355dc0c218b7daae70fcd Mon Sep 17 00:00:00 2001 From: Nathaniel Nicandro Date: Thu, 14 Dec 2017 10:40:02 -0600 Subject: [PATCH 2/2] Perform work in macro calling environment In `define-ffi-function` and `ffi--struct-union-helper` the work to define ffi functions (using `ffi--prep-cif` and `ffi--dlsym`) and types was done in the macro environment. This works fine during runtime, but fails for complied code since the objects would be created at compile time instead of at runtime. By moving the work to the macro's calling environment we avoid this problem. --- ffi.el | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/ffi.el b/ffi.el index 1f8c5b2..f34d109 100644 --- a/ffi.el +++ b/ffi.el @@ -11,20 +11,27 @@ (ffi--dlopen ,name))) (defmacro define-ffi-function (name c-name return-type arg-types library) - (let* ( - ;; Turn variable references into actual types; while keeping - ;; keywords the same. - (arg-types (mapcar #'symbol-value arg-types)) - (arg-names (mapcar (lambda (_ignore) (cl-gensym)) arg-types)) - (arg-types (vconcat arg-types)) - (function (cl-gensym)) - (cif (ffi--prep-cif (symbol-value return-type) arg-types))) - (set function nil) - `(defun ,name (,@arg-names) - (unless ,function - (setq ,function (ffi--dlsym ,c-name (,library)))) + (let ((arg-names (mapcar (lambda (_ignore) (cl-gensym)) arg-types)) + (arg-types (vconcat arg-types)) + (function (concat "ffi-fun-" c-name)) + (cif (concat "ffi-cif-" c-name)) + (library (intern (concat "ffi-" (symbol-name library))))) + ;; Adapted from the expansion of lexical-let + `(let ((fun (make-symbol ,function)) + (cif (make-symbol ,cif))) + (set fun (ffi--dlsym ,c-name ,library)) ;; FIXME do we even need a separate prep? - (ffi--call ,cif ,function ,@arg-names)))) + (set cif (ffi--prep-cif ,return-type ,arg-types)) + (defalias ',name + (list 'lambda ',arg-names + (list 'funcall (lambda (cif fun ,@arg-names) + (ffi--call (symbol-value cif) + (symbol-value fun) + ,@arg-names)) + (list 'quote cif) + (list 'quote fun) + ,@(cl-loop for arg in arg-names + collect `(quote ,arg)))))))) (defun ffi-lambda (function-pointer return-type arg-types) (let* ((cif (ffi--prep-cif return-type (vconcat arg-types)))) @@ -54,10 +61,10 @@ (cl-assert (eq (cadr slot) :type)) (symbol-value (cl-caddr slot))) slots)) - (the-type (apply definer-function field-types)) (field-offsets (funcall layout-function field-types))) - (push `(defvar ,name ,the-type ,docstring) - result-forms) + (push `(defvar ,name (apply #',definer-function ',field-types) + ,docstring) + result-forms) (cl-mapc (lambda (slot type offset) (let ((getter-name (intern (concat conc-name @@ -94,10 +101,9 @@ SLOT-NAME is a symbol and TYPE is an FFI type descriptor." (defmacro define-ffi-array (name type length &optional docstring) ;; This is a hack until libffi gives us direct support. - (let ((type-description - (apply #'ffi--define-struct - (make-list (eval length) (symbol-value type))))) - `(defvar ,name ,type-description ,docstring))) + `(defvar ,name (apply #'ffi--define-struct + (make-list ,length ,type)) + ,docstring)) (defsubst ffi-aref (array type index) (ffi--mem-ref (ffi-pointer+ array (* index (ffi--type-size type))) type))