This is a tech post and the intended audience is the few people who will bash their heads against a piece of software until it gets installed. I’ve just gone through one of these “sessions”, so I thought I’d document it here for the next person.
Zach Beane created quicklisp, which is a great way to load up common lisp libraries without a headache.
To give an example of this, to load my favorite web programming framework, all I need to do is type the following: (ql:quickload 'weblocks)
It loads everything I need and I can instantly get started working. Very cool! Now after a bit of programming I find that I’d like to customise the storage layer to use a mysql database, but that’s when it gets hairy…
First of all, weblocks’ clsql interface depends on clsql-fluid, which as a project doesn’t package anything… so this doesn’t give quicklisp an opportunity to distribute it. I guess someone could make a package, but I assume Zach would like to have the project maintainers do this instead of himself.
Secondly quicklisp already had installed the clsql library for me and I couldn’t find a command to remove it. So after looking through the documentation and the source I went and deleted things under my quicklisp directory (and ~/.cache) to remove quicklisp’s version of clsql. A remove command in quicklisp would be a nice touch. It would also be nice to get some like functionality for quicklisp in managing software beyond installing & searching. Maybe Zach already has plans for these for when the code goes out of beta…
Thirdly, I fetched clsql-fluid as described on the website and linked it in and loaded it up… but got errors:
"The name NIL does not designate any package."
What is happening here is that clsql-uffi tests that it’s properly loaded by looking for a defined symbol (atol64) to have an associated function. If that function doesn’t exist then we havn’t loaded the foreign libraries and therefore haven’t successfully loaded. The problem with this is that the clsql-uffi package doesn’t exist yet, so we get the error when the test code tries to (find-package #:clsql-uffi)
.
Since this test is a predicate of sorts I decided that instead of erroring it should just return nil, so I wrapped those probing statements in an: (ignore-errors ...)
statement. Once I’d done this it allowed me to get to the next level of errors :)
Fourthly, the syntax used in the uffi calls seems different than what the uffi installed via quicklisp expects. After getting beyond the “nil package” problem above, I encountered this error:
caught ERROR:
; (in macroexpansion of (UFFI:CONVERT-FROM-FOREIGN-STRING CHAR-PTR
:LOCALE ...))
; (hint: For more precise location, try *BREAK-ON-SIGNALS*.)
; error while parsing arguments to DEFMACRO CONVERT-FROM-FOREIGN-STRING:
; unknown keyword: :LOCALE; expected one of :NULL-TERMINATED-P,
:LENGTH
After looking around a bit I got the tip that cffi-uffi-compat might be more compatible than quicklisp’s version of uffi, so I edited clsq.asd, clsql-mysql.asd, clsql-uffi.asd, and uffi/clsql-uffi-package.lisp and edited them to use the uffi compatibility layer from cffi. After all that was done I did another (ql:quickload 'clsql-mysql)
and the clsql-fluid version loaded. whew
I hope this helps others stuck in a similar situation and here is the result of a git diff
in the root of the clsql-fluid source:
diff --git a/clsql-mysql.asd b/clsql-mysql.asd index a176f85..1263457 100644 --- a/clsql-mysql.asd +++ b/clsql-mysql.asd @@ -20,8 +20,8 @@ (in-package #:clsql-mysql-system) (eval-when (:compile-toplevel :load-toplevel :execute) - (unless (find-package 'uffi) - (asdf:operate 'asdf:load-op 'uffi))) + (unless (find-package 'cffi-uffi-compat) + (asdf:operate 'asdf:load-op 'cffi-uffi-compat))) (defvar *library-file-dir* (append (pathname-directory *load-truename*) (list "db-mysql"))) @@ -48,8 +48,8 @@ t) (defmethod operation-done-p ((o load-op) (c clsql-mysql-source-file)) - (and (symbol-function (intern (symbol-name '#:mysql-get-client-info) - (find-package '#:mysql))) + (and (ignore-errors (symbol-function (intern (symbol-name '#:mysql-get-client-info) + (find-package '#:mysql)))) t)) (defmethod perform ((o compile-op) (c clsql-mysql-source-file)) @@ -80,7 +80,7 @@ :description "Common Lisp SQL MySQL Driver" :long-description "cl-sql-mysql package provides a database driver to the MySQL database system." - :depends-on (uffi clsql clsql-uffi) + :depends-on (cffi-uffi-compat clsql clsql-uffi) :components diff --git a/clsql-mysql.asd b/clsql-mysql.asd index a176f85..1263457 100644 --- a/clsql-mysql.asd +++ b/clsql-mysql.asd @@ -20,8 +20,8 @@ (in-package #:clsql-mysql-system) (eval-when (:compile-toplevel :load-toplevel :execute) - (unless (find-package 'uffi) - (asdf:operate 'asdf:load-op 'uffi))) + (unless (find-package 'cffi-uffi-compat) + (asdf:operate 'asdf:load-op 'cffi-uffi-compat))) (defvar *library-file-dir* (append (pathname-directory *load-truename*) (list "db-mysql"))) @@ -48,8 +48,8 @@ t) (defmethod operation-done-p ((o load-op) (c clsql-mysql-source-file)) - (and (symbol-function (intern (symbol-name '#:mysql-get-client-info) - (find-package '#:mysql))) + (and (ignore-errors (symbol-function (intern (symbol-name '#:mysql-get-client-info) + (find-package '#:mysql)))) t)) (defmethod perform ((o compile-op) (c clsql-mysql-source-file)) @@ -80,7 +80,7 @@ :description "Common Lisp SQL MySQL Driver" :long-description "cl-sql-mysql package provides a database driver to the MySQL database system." - :depends-on (uffi clsql clsql-uffi) + :depends-on (cffi-uffi-compat clsql clsql-uffi) :components ((:module :db-mysql :components diff --git a/clsql-uffi.asd b/clsql-uffi.asd index e5a75f6..e78f09e 100644 --- a/clsql-uffi.asd +++ b/clsql-uffi.asd @@ -50,8 +50,8 @@ nil) ;;; library will be loaded by a loader file (defmethod operation-done-p ((o load-op) (c clsql-uffi-source-file)) - (and (symbol-function (intern (symbol-name '#:atol64) - (find-package '#:clsql-uffi))) + (and (ignore-errors (symbol-function (intern (symbol-name '#:atol64) + (find-package '#:clsql-uffi)))) t)) (defmethod perform ((o compile-op) (c clsql-uffi-source-file)) @@ -79,7 +79,7 @@ :description "Common UFFI Helper functions for Common Lisp SQL Interface Library" :long-description "cl-sql-uffi package provides common helper functions using the UFFI for the CLSQL package." - :depends-on (uffi clsql) + :depends-on (cffi-uffi-compat clsql) :components ((:module :uffi diff --git a/clsql.asd b/clsql.asd index 35e172a..51da309 100644 --- a/clsql.asd +++ b/clsql.asd @@ -26,8 +26,8 @@ ;; need to load uffi for below perform :after method (eval-when (:compile-toplevel :load-toplevel :execute) - (unless (find-package 'uffi) - (asdf:operate 'asdf:load-op 'uffi))) + (unless (find-package 'cffi-uffi-compat) + (asdf:operate 'asdf:load-op 'cffi-uffi-compat))) (defsystem clsql :name "CLSQL" diff --git a/uffi/clsql-uffi-package.lisp b/uffi/clsql-uffi-package.lisp index be5abf5..153ca1f 100644 --- a/uffi/clsql-uffi-package.lisp +++ b/uffi/clsql-uffi-package.lisp @@ -19,7 +19,7 @@ (in-package #:cl-user) (defpackage #:clsql-uffi - (:use #:cl #:uffi) + (:use #:cl #:cffi-uffi-compat) (:export #:find-and-load-foreign-library #:canonicalize-type-list
I do need to add more project management commands to Quicklisp. For reference, any system that is visible via asdf:find-system through its central registry will take precedence over anything present in Quicklisp.
Regarding UFFI, UFFI and CLSQL are developed by the same author, and when CFFI-UFFI-COMPAT is incompatible with UFFI, it’s a bug in CFFI-UFFI-COMPAT. What project and file gave you the UFFI error?
clsql-uffi was giving the above error about the use of :locale in a call to UFFI:CONVERT-FROM-FOREIGN-STRING
What would be really great is if someone fixed Weblocks to use CLSQL connection pools properly (http://clsql.b9.com/manual/with-database.html) so there would be no need for clsql-fluid.
Yes, this link emphasizes this fact: http://www.cliki.net/clsql-fluid
I’m unsure of what’s involved since I’m just involved with weblocks on the surface. This weekend I have 8 hours of train travel, so I’ll pop open the source to look at the issue.