Am 04.01.2006 um 22:08 schrieb Luís Oliveira:
Hello,
There's been some discussion on IRC about what CFFI's "smarter" foreign library interface should look like. I put together some code and here's what my attempt looks like:
(define-foreign-library opengl
Is opengl then interned as a symbol (in which package) ? Or a keyword ?
(:darwin (:framework "OpenGL")) (:unix (:alternatives "libGL.so" "libGL.so.1" #p"/myhome/mylibGL.so")) (:windows "opengl32.dll") ;; and a hypothetical example of a particular platform ;; where the OpenGL library is split in two. ((:and :some-system :some-cpu) "libGL-support.lib" "libGL-
main.lib"))
I like this approach very much as it caters for every case I came across. I think I also would follow James Bielman's suggestion to drop the :alternatives think in favor for a :or approach. On Darwin, the :framework options is mandatory of course and should also handle bundles.
The library is then used with the following macro:
(use-foreign-library opengl)
So here's what's going on when loading this opengl library:
First, the proper clause is selected in a cond-like fashion. The symbols in there are tested against symbols in *features* that belong to the cffi-features[1] package. The :and, :or and :not operators are supported.
Then, the rest of the elements in the clause are handled. There
can be more than one. For example you could define GLUT and OpenGL in one define-foreign-library form and whatever support libraries those might need.
Each of the elements can be:
a) A string, eg. "libGL.so". In this case it's passed to load-foreign-library directly. What this means in e.g. unix-
like systems is that the library will be searched in:
1. the LD_LIBRARY_PATH environment variable. 2. the directories in /etc/ld.so.cache (or equivalent) 3. /usr/lib and /lib
This is completely platform dependant (as you probably know ;-) So, if you want to handle all the cases in CFFI then there are at least the following cases in addition:
HP-UX: - SHLIB_PATH env var - no cache file for the dynamic loader - same dirs, plus I'd recommend to include /usr/local/lib, /usr/ lib/X11 (this is true for all unix like systems)
Mac OS X (Darwin): - DYLIB_LIBRARY_PATH env var - I don't know of any cache file... - same dirs
General note on Darwin: It is required not to load any lib or framework twice. Also, order of loading matters. So, it should be defined that loading occurs left to right as stated in the define- foreign library call.
SUN anyone ???
If that fails, it tries to find it in the directories inside cffi:*foreign-library-directories* which is similar to asdf:*central-registry* in the sense that you can push stuff like '*default-pathname-defaults* or '(user-homedir-pathname) and they'll be "evaluated". b) A pathname, in which case CFFI doesn't try to find it and
simply passes its namestring to load-foreign-library.
c) A list of the form (:alternatives ...). Here we try to load
each of the alternatives in order until one is loaded successfully. If none of the alternatives are loaded we get an error.
d) A pair of the form (:framework "name"). CFFI will try to
load the "name" framework, looking at the directories in cffi:*darwin-framework-directories* which is similar to cffi:*foreign-library-directories*. This list contains the following paths by default:
1. ~/Library/Frameworks 2. /Library/Frameworks 3. /System/Library/Frameworks Obviously, the user can push more paths into this list.
There are some functions that I'm not sure are worth exporting: find-foreign-library, find-and-load-foreign-library and find-darwin-framework. Also, maybe a functional interface to use-foreign-library could be useful?
Comments?
What I am missing is the support for handling multiple versions of foreign libs. It should be possible to state which version to load if more than one version is installed or if a certain version is required. I know this no trivial task as the version naming of libs is not unified. Also, there has to some means of specifying what to do if the requested lib version is not available. Some fallback behaviour like :load-newest or :signal-error or :load-newest-if- higher-version ...
Did anyone else come across this requirement?
Cheers, Frank