Hello.
The CFFI manual says [1] that cffi:use-foreign-library is intended to be the top-level form used idiomatically to go ahead and load the library.
And most developers follow this idiom.
I would argue that this is inconvenient.
My motivation is that cl-test-grid tests (ql:quickload) of every ASDF system in Quicklisp, and the presence of cffi:use-foreign-library as a top-level causes failures of system load if the foreign library is absent.
In other words, I can not test compilation of Common Lisp code until the foreign library is provided.
You may object that cl:compile-file does not execute top level forms. But by compilation I mean at least asdf:compile-op of ASDF system. ASDF systems consist often of several files which depend on each other, and in order to compile dependent files ASDF should not only compile, but also load the dependency files.
For example, (asdf:operate 'asdf:compile-op :cl+ssl) fails with:
Unable to load foreign library (LIBSSL). Error opening shared library libssl32.dll : %1 is not a Win32 executable . [Condition of type CFFI:LOAD-FOREIGN-LIBRARY-ERROR]
I think better idiom would be to not use top-lovel cffi:use-foreign-library, but instead have CL libraries to provide initialization routine which loads the foreign libraries.
A supporting argument against top-level cffi:use-foreign-library is that as far as I know when we save an image of lisp, many lisps will not reload the foreign libraries when we load the image next time. I.e. the lisp image does not contain information about loaded libraries. Here, even with the approach with top-level cffi:use-foreign-library the CL library anyway needs to provide a routine to load the foreign library. Therefore, we could avoid the top-level cffi:use-foreign-library at all.
I would like to know the opinion of CFFI developers. Do I miss anything? What are the reasons to support the top-level cffi:use-foreign-library?
Best regards, - Anton
[1] - http://common-lisp.net/project/cffi/manual/html_node/use_002dforeign_002dlib...
Hi Anton,
Am 22.10.2012 um 05:28 schrieb Anton Vodonosov avodonosov@yandex.ru:
Hello.
The CFFI manual says [1] that cffi:use-foreign-library is intended to be the top-level form used idiomatically to go ahead and load the library.
And most developers follow this idiom.
What makes you think so? I don't.
I would argue that this is inconvenient.
That's what led me to follow a simple two-step idiom:
(in-package :de.consequor.app.core)
;;; ------------------------------------------------------------------- ;;; C LIB FFI Definition ;;; -------------------------------------------------------------------
(eval-now! (define-foreign-library CCAGCORE_LIB (t (:default "libccagcore"))))
(defparameter *CCAGCORE-DEFAULT-LIBDIR* "Z:/var/data/consequor/swdev/ccagcore/lib/") (defparameter *CCAGCORE-LIBDIR* nil)
(defun set-ccagcore-libdir (&optional (libdir *CCAGCORE-DEFAULT-LIBDIR*)) (setq *CCAGCORE-LIBDIR* libdir))
(defun ensure-ccagcore-libdir-set () (unless *CCAGCORE-LIBDIR* (setq *CCAGCORE-LIBDIR* *CCAGCORE-DEFAULT-LIBDIR*)))
(defun push-ccagcore-libdir () (pushnew *CCAGCORE-LIBDIR* cffi:*foreign-library-directories* :test #'string=))
(let ((loaded nil))
(defun load-ccagcore-lib () (unless loaded (ensure-ccagcore-libdir-set) (push-ccagcore-libdir) (load-foreign-library 'CCAGCORE_LIB) (setq loaded t) (ccag-log :INFO "LOAD-CCAGCORE-LIB" 0 "CCAGCORE LIB loaded." )))
(defun unload-ccagcore-lib () (when loaded (close-foreign-library 'CCAGCORE_LIB) (setq loaded nil) (ccag-log :INFO "UNLOAD-CCAGCORE-LIB" 0 "CCAGCORE LIB unloaded." )))
(defun ensure-ccagcore-lib-loaded () (unless loaded (load-ccagcore-lib))) )
Simple. Works. No problems on any platform.
Cheers Frank
On Mon, Oct 22, 2012 at 4:28 AM, Anton Vodonosov avodonosov@yandex.ru wrote:
I think better idiom would be to not use top-lovel cffi:use-foreign-library, but instead have CL libraries to provide initialization routine which loads the foreign libraries.
That might work, but it's definitely not idiomatic amongst Lisp libraries (using CFFI or other FFIs). I guess, it's much more convenient to be able to just load some ASDF system and be start using the API right away.
A supporting argument against top-level cffi:use-foreign-library is that as far as I know when we save an image of lisp, many lisps will not reload the foreign libraries when we load the image next time. I.e. the lisp image does not contain information about loaded libraries. Here, even with the approach with top-level cffi:use-foreign-library the CL library anyway needs to provide a routine to load the foreign library. Therefore, we could avoid the top-level cffi:use-foreign-library at all.
As a solution for that, CFFI keeps track of what foreign libraries have been loaded. (See CFFI:LIST-FOREIGN-LIBRARIES and CFFI:RELOAD-FOREIGN-LIBRARIES.) It would be nice if CFFI helped with setting up proper hooks to load the foreign libraries when an image is loaded.
Regarding your use case, if CFFI added an IGNORE restart for LOAD-FOREIGN-LIBRARY-ERROR conditions, would that help?
31.10.2012, 03:34, "Luís Oliveira" luismbo@gmail.com:
On Mon, Oct 22, 2012 at 4:28 AM, Anton Vodonosov avodonosov@yandex.ru wrote:
I think better idiom would be to not use top-lovel cffi:use-foreign-library, but instead have CL libraries to provide initialization routine which loads the foreign libraries.
That might work, but it's definitely not idiomatic amongst Lisp libraries (using CFFI or other FFIs). I guess, it's much more convenient to be able to just load some ASDF system and be start using the API right away.
I recently found this article: http://random-state.net/log/3311080770.html It means, some time ago SBCL was unable to define foreign functions until the foreign library is loaded.
Despite it is fixed in SBCL years ago, maybe other lisps can't define foreign functions/variables until the library is not loaded? Do you remember details about other lisps? Are they all now capable to compile and load lisp code with foreign definitions without loading the foreign library?
A supporting argument against top-level cffi:use-foreign-library is that as far as I know when we save an image of lisp, many lisps will not reload the foreign libraries when we load the image next time. I.e. the lisp image does not contain information about loaded libraries. Here, even with the approach with top-level cffi:use-foreign-library the CL library anyway needs to provide a routine to load the foreign library. Therefore, we could avoid the top-level cffi:use-foreign-library at all.
As a solution for that, CFFI keeps track of what foreign libraries have been loaded. (See CFFI:LIST-FOREIGN-LIBRARIES and CFFI:RELOAD-FOREIGN-LIBRARIES.) It would be nice if CFFI helped with setting up proper hooks to load the foreign libraries when an image is loaded.
Regarding your use case, if CFFI added an IGNORE restart for LOAD-FOREIGN-LIBRARY-ERROR conditions, would that help?
Thanks for the suggestion, I am not sure, need to think about it.
Best regards, - Anton