The attached patch adds a :type attribute to foreign libraries(:system
or :wrapper), per-library search paths(needed for cffi-grovel wrappers)
and a function list-foreign-libraries. It also adds the readers
foreign-library-type, foreign-library-search-path and
foreign-library-loaded-p.
Any objections against merging this ?

-- 
Stelian Ionescu a.k.a. fe[nl]ix
Quidquid latine dictum sit, altum videtur.
http://common-lisp.net/project/iolib
diff -rN -u old-cffi/src/libraries.lisp new-cffi/src/libraries.lisp
--- old-cffi/src/libraries.lisp	2009-07-09 13:44:30.019302872 +0200
+++ new-cffi/src/libraries.lisp	2009-07-09 13:44:30.025972319 +0200
@@ -104,7 +104,8 @@
 (defclass foreign-library ()
   ((spec :initarg :spec)
    (options :initform nil :initarg :options)
-   (handle :initarg :handle :accessor foreign-library-handle)))
+   (handle :initform nil :initarg :handle
+           :accessor foreign-library-handle)))
 
 (defun get-foreign-library (lib)
   "Look up a library by NAME, signalling an error if not found."
@@ -129,16 +130,47 @@
   (append (cddr (%foreign-library-spec lib))
           (slot-value lib 'options)))
 
-;;; Warn about unkown options.
+(defun foreign-library-type (lib)
+  (getf (foreign-library-options (get-foreign-library lib)) :type))
+
+(defun foreign-library-search-path (lib)
+  (getf (foreign-library-options (get-foreign-library lib)) :search-path))
+
+(defun foreign-library-loaded-p (lib)
+  (not (null (foreign-library-handle (get-foreign-library lib)))))
+
+(defun list-foreign-libraries (&key (loaded-only t) type)
+  "Return a list of defined foreign libraries.
+If LOADED-ONLY is non-null only loaded libraries are returns.
+TYPE restricts the output to a specific library type(:SYSTEM or :WRAPPER).
+If NIL all libraries are returned."
+  (let ((libs (hash-table-values *foreign-libraries*)))
+    (remove-if-not (lambda (lib)
+                     (cond
+                       (type
+                        (eql type (getf (foreign-library-options lib) :type)))
+                       (loaded-only
+                        (foreign-library-loaded-p lib))
+                       (t t)))
+                   libs)))
+
 (defmethod initialize-instance :after ((lib foreign-library) &key)
-  (loop for (opt nil)
-        on (append (slot-value lib 'options)
-                   (mapcan (lambda (x) (copy-list (cddr x)))
-                           (slot-value lib 'spec)))
-        by #'cddr
-        when (not (member opt '(:cconv :calling-convention)))
-        do (warn "Unkown option: ~A" opt)))
+  (with-slots (options spec) lib
+    (destructuring-bind (&key type search-path &allow-other-keys)
+        (apply #'append options
+               (mapcar (lambda (x) (copy-list (cddr x)))
+                       spec))
+      (flet ((set-option (key value)
+               (if value (setf (getf options key) value) (remf options key))))
+        (assert (subsetp (loop for (key . nil) on options by #'cddr collect key)
+                         '(:cconv :calling-convention :type :search-path)))
+        (if type
+            (check-type type (member :system :wrapper))
+            (set-option :type :system))
+        (set-option :search-path (mapcar #'pathname search-path))))))
 
+;;; FIXME: re-evaluating DEFINE-FOREIGN-LIBRARY overwrites the current entry
+;;;        breaking FOREIGN-LIBRARY-LOADED-P if already loaded
 (defmacro define-foreign-library (name-and-options &body pairs)
   "Defines a foreign library NAME that can be posteriorly used with
 the USE-FOREIGN-LIBRARY macro."
@@ -189,14 +221,15 @@
 ;;; FIXME: haven't double checked whether all Lisps signal a
 ;;; SIMPLE-ERROR on %load-foreign-library failure.  In any case they
 ;;; should be throwing a more specific error.
-(defun load-foreign-library-path (name path)
+(defun load-foreign-library-path (name path &optional search-path)
   "Tries to load PATH using %LOAD-FOREIGN-LIBRARY which should try and
 find it using the OS's usual methods. If that fails we try to find it
 ourselves."
   (handler-case
       (%load-foreign-library name path)
     (error (error)
-      (if-let (file (find-file path *foreign-library-directories*))
+      (if-let (file (find-file path (append search-path
+                                            *foreign-library-directories*)))
               (handler-case
                   (%load-foreign-library name (native-namestring file))
                 (simple-error (error)
@@ -227,23 +260,26 @@
   (or (cdr (assoc-if #'featurep *cffi-feature-suffix-map*))
       (fl-error "Unable to determine the default library suffix on this OS.")))
 
-(defun load-foreign-library-helper (name thing)
+(defun load-foreign-library-helper (name thing &optional search-path)
   (etypecase thing
     (string
-     (load-foreign-library-path name thing))
+     (load-foreign-library-path name thing search-path))
     (pathname
-     (load-foreign-library-path name (namestring thing)))
+     (load-foreign-library-path name (namestring thing) search-path))
     (cons
      (ecase (first thing)
        (:framework (load-darwin-framework name (second thing)))
        (:default
         (unless (stringp (second thing))
           (fl-error "Argument to :DEFAULT must be a string."))
-        (load-foreign-library-path
-         name (concatenate 'string (second thing) (default-library-suffix))))
+        (load-foreign-library-path name
+                                   (concatenate 'string
+                                                (second thing)
+                                                (default-library-suffix))
+                                   search-path))
        (:or (try-foreign-library-alternatives name (rest thing)))))))
 
-(defun load-foreign-library (library)
+(defun load-foreign-library (library &key search-path)
   "Loads a foreign LIBRARY which can be a symbol denoting a library defined
 through DEFINE-FOREIGN-LIBRARY; a pathname or string in which case we try to
 load it directly first then search for it in *FOREIGN-LIBRARY-DIRECTORIES*;
@@ -255,11 +291,19 @@
                 (spec (foreign-library-spec lib)))
            (when spec
              (setf (foreign-library-handle lib)
-                   (load-foreign-library-helper library spec))
+                   (load-foreign-library-helper
+                    library spec (foreign-library-search-path lib)))
              lib)))
         (t
-         (make-instance 'foreign-library :spec (list (list library))
-                        :handle (load-foreign-library-helper nil library))))
+         (let* ((lib-name (gensym (string '#:library-)))
+                (lib
+                 (make-instance 'foreign-library :spec `((t ,library))
+                                :options `(:type :system
+                                           :search-path ,search-path)
+                                :handle (load-foreign-library-helper
+                                         lib-name library search-path))))
+           (setf (get-foreign-library lib-name) lib)
+           lib)))
     ;; Offer these restarts that will retry the call to
     ;; LOAD-FOREIGN-LIBRARY.
     (retry ()
diff -rN -u old-cffi/src/package.lisp new-cffi/src/package.lisp
--- old-cffi/src/package.lisp	2009-07-09 13:44:30.019302872 +0200
+++ new-cffi/src/package.lisp	2009-07-09 13:44:30.025972319 +0200
@@ -32,7 +32,8 @@
   (:import-from #:alexandria
                 #:ensure-list #:featurep #:format-symbol #:if-let
                 #:make-gensym-list #:once-only #:parse-body #:symbolicate
-                #:when-let #:with-unique-names #:lastcar)
+                #:when-let #:with-unique-names #:lastcar
+                #:hash-table-values #:make-keyword)
   (:export
    ;; Types.
    #:foreign-pointer
@@ -74,11 +75,16 @@
    ;; Foreign library operations.
    #:*foreign-library-directories*
    #:*darwin-framework-directories*
+   #:foreign-library
+   #:foreign-library-type
+   #:foreign-library-search-path
+   #:foreign-library-loaded-p
    #:define-foreign-library
    #:load-foreign-library
    #:load-foreign-library-error
    #:use-foreign-library
    #:close-foreign-library
+   #:list-foreign-libraries
 
    ;; Callbacks.
    #:callback

Attachment: signature.asc
Description: This is a digitally signed message part

_______________________________________________
cffi-devel mailing list
cffi-devel@common-lisp.net
http://common-lisp.net/cgi-bin/mailman/listinfo/cffi-devel

Reply via email to