This example builds a dynamic library which in principle could be loaded by any application and called to calculate square numbers.
For illustrative purposes, we show how to load the dynamic library into the LispWorks development image. This illustrates some platform-specific initialization. Then we use the library, ensure it exits cleanly, and finally delete the dynamic library file.
Note that on Linux/Macintosh/FreeBSD, to deliver a dynamic library, the build machine must have a C compiler installed.
For convenience the code is presented without external files. To run it, copy each form in turn and enter it at the Listener prompt.
(defvar *dynamic-library-path*
(merge-pathnames (make-pathname :name "CalculateSquareExample"
:type scm::*object-file-suffix*)
(get-temp-directory)))
(defun save-dynamic-library ()
(let* ((file (make-temp-file t "lisp"))
(ns (namestring file)))
(format file
"
(fli:define-foreign-callable (calculate-square :result-type :int)
((arg :int))
(* arg arg))
(deliver nil ~s 5 :dll-exports '(\"calculate_square\"))"
(namestring *dynamic-library-path*))
(close file)
(sys:call-system-showing-output (list (lisp-image-name)
"-build"
ns ))
(delete-file file nil)))
(save-dynamic-library)
(fli:define-foreign-function (my-quit-lispworks "QuitLispWorks")
((force :int)
(milli-timeout :int))
:result-type :int
;; specifying :module ensures the foreign function finds
;; the function in our module
:module 'my-dynamic-library)
(fli:define-foreign-function (my-init-lispworks "InitLispWorks")
((milli-timeout :int)
(base-address (:pointer-integer :int))
(reserve-size (:pointer-integer :int)) ; really size_t
)
:result-type :int
:module 'my-dynamic-library)
(fli:define-foreign-function calculate-square
((arg :int))
:result-type :int
:module 'my-dynamic-library)
(defun run-the-dynamic-library ()
(fli:register-module 'my-dynamic-library
:connection-style :immediate
:file-name *dynamic-library-path*)
;; Windows and Mac OS X can detect and resolve memory clashes.
;; On other platforms, tell the library to load at different
;; address (that is, relocate) because otherwise it will use
;; the same address as the running LispWorks development image.
;; Relocation may be needed when loading a LispWorks dynamic
;; library in other applications.
#-(or mswindows darwin)
(my-init-lispworks 0
#+lispworks-64bit #x5000000000
#+lispworks-32bit #x50000000
0)
(dotimes (x 4)
(format t "square of ~d = ~d~%" x
(calculate-square x)))
(my-quit-lispworks 0 1000)
(fli:disconnect-module 'my-dynamic-library))
(run-the-dynamic-library)
Check the output to see that it computed square numbers.
(delete-file *dynamic-library-path* nil)