Hi,
I'm posting this to the CFFI discussion group, I previously posted it to the Lisp Application Builder list.
Anyway, the L/AB people have made an SDL module that lets CFFI-supported Lisps use SDL (it's a very portable gaming library).
I use Clisp exclusively, so I wanted to see SDL work properly with it, just so I can develop my application using it. At first I wrote my own SDL header module using ah2cl.lisp, but later I came across the L/AB module, and used that instead.
What I'm getting to is, I read on comp.lang.lisp that the CFFI-based SDL module does not work on Windows 98 under Clisp. I just tested it on my Windows 98 laptop (P166 :-) and it says the same thing. "FFI: FOREIGN-LIBRARY-FUNCTION: No dynamic object named 'SDL_Init' in library :DEFAULT"
My hack that uses FFI (not CFFI) to run SDL works fine on Windows 98, so the issue is definitely part of CFFI.
I did a little bit of detective work:
Clisp's top-level view shows the scope, at the time of the above error as (from src/cffi-clisp.lisp):
`(funcall (load-time-value (ffi::foreign-library-function ,name (ffi::foreign-library :default) nil (ffi:parse-c-type ',ctype))) ,@fargs))))
The FFI documentation says nothing about a load-time-value, and ffi::foreign-library is not mentioned either. Strange!
My best guess is that CFFI is doing something strange with CLisp's FFI that has a better alternative. This feature of FFI that the CFFI developers chose may be broken on Windows 98.
For a comparison, here is my SDL header code, which does work on Windows 98:
(ffi:def-call-out SDL_Init (:name "SDL_Init") (:library "sdl.dll") (:return-type ffi:int) (:arguments (flags Uint32)))
Okay, I could say "it works this way, but CFFI does it another way that is broken", but I don't know the ins and outs of CFFI, and why the developers chose to use the load-time-vaue macro (or whatever it is), so I won't comment on a better way to do it. But maybe CFFI's CLisp module could use a different feature of FFI to do its run-time DLL calls.
Anyway, CFFI is a great project, and I had no headaches setting it up, so I'm very pleased with it. I don't even use Windows 98 (I'm on Windows XP), but it seems best to fix things so that my application and others will run on that platform, without people cursing Lisp.
Cheers,
Jeremy.
Jeremy Smith jeremy@decompiler.org writes:
I'm posting this to the CFFI discussion group, I previously posted it to the Lisp Application Builder list.
(Sorry for the delay in approving your message; the list gets so much spam I don't check it all that often.)
What I'm getting to is, I read on comp.lang.lisp that the CFFI-based SDL module does not work on Windows 98 under Clisp. I just tested it on my Windows 98 laptop (P166 :-) and it says the same thing. "FFI: FOREIGN-LIBRARY-FUNCTION: No dynamic object named 'SDL_Init' in library :DEFAULT"
My first guess is that you are using an older version of CLISP that is technically unsupported by CFFI. What CLISP version are you using, and do the SDL bindings work if you upgrade to the latest release?
IIRC, several releases ago, a feature was added to CLISP to look for foreign symbols globally when the library is :DEFAULT, instead of only in the C library. Perhaps this is not working on Win9x... does this work under NT/XP/whatever?
I did a little bit of detective work:
Clisp's top-level view shows the scope, at the time of the above error as (from src/cffi-clisp.lisp):
`(funcall (load-time-value (ffi::foreign-library-function ,name (ffi::foreign-library :default) nil (ffi:parse-c-type ',ctype))) ,@fargs))))
The FFI documentation says nothing about a load-time-value, and ffi::foreign-library is not mentioned either. Strange!
In the CFFI design, the lowest level operator for calling a foreign function is CFFI:FOREIGN-FUNCALL, which can be used for one-shot calls to any C function with argument types known at compile-time:
(foreign-funcall "puts" :string "Hello, world!" :void)
The DEFCFUN macro (in almost all Lisp implementations) expands into a normal Lisp DEFUN that uses FOREIGN-FUNCALL to effect the actual foreign function call.
The LOAD-TIME-VALUE in FOREIGN-FUNCALL is there to avoid resolving the foreign function each time it is called; instead it is done once when the fasl file is loaded.
(ffi:def-call-out SDL_Init (:name "SDL_Init") (:library "sdl.dll") (:return-type ffi:int) (:arguments (flags Uint32)))
If this works with (:library :default) using the CLISP FFI (as I understand it should, if sdl.dll has been loaded), then I would expect it to work in CFFI as well.
James