[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.lisp

Loading "plugins" via ASDF

Frank GOENNINGER

1/2/2016 6:41:00 PM


Now that I know how to define config variables I am on to loading what I
call "plugins" during runtime for my bigger, real-world application.

Those plugins reside in separate directories, e.g.:

..../thingbone/transports/plugins/mqtt/
..../thingbone/transports/plugins/dds/
..../thingbone/transports/plugins/ibm-mqi/

Each plugin is a well-defined ASDF system with an .asd file, e.g.

..../thingbone/transports/plugins/mqtt:
defpackage.lisp
mqtt-transport.lisp
net.goenninger.transport.mqtt.asd

I am now trying to use ASDF's load-system facility to have each of the
plugins loaded. Functions implemented so far:

(defun add-directory-to-asdf-registry (dirname)
"Add the directory given by DIRNAME to ASDF's Central Registry if it is a valid directory and not already registered."
(if (cl-fad:directory-pathname-p dirname)
(let ((canonical-dirname (cl-fad:canonical-pathname dirname)))
(if (cl-fad:directory-exists-p canonical-dirname)
(let* ((before asdf:*central-registry*)
(after (pushnew canonical-dirname asdf:*central-registry* :test #'cl-fad:pathname-equal)))
(if (not (eql before after))
(log:debug "Directory ~A added (asdf:*cengtral-registry* now ~S." dirname after)))
(log:error "Directory ~A not accessible. Nothing added to ASDF Central Registry!")))
(log:error "Directory ~A is not a valid directory." dirname))
(values))

(defun ensure-directory-is-asdf-registered (dirname)
"Ensure the directory given by DIRNAME is in ASDF's Central Registry."
(add-directory-to-asdf-registry dirname))

(defun load-plugin-from-directory-by-plugin-name (dirname plugin-name)
"Load a plugin represented by an ASDF system in a directory given by DIRNAME. The plugin is named by PLUGIN-NAME (downcase string) as also found in the plugiun's ASDF system definition."
(ensure-directory-is-asdf-registered dirname)
(let ((result nil))
(handler-case
(let ((name (string-downcase plugin-name)))
(setq result (asdf:load-system name))
(log:info "Loaded plugin ~A from ~A." plugin-name dirname)
;;(register-plugin-by-name plugin-name result)
(values result nil))
(condition (c)
(log:warn "Could not load plugin ~A from ~A (ASDF error: ~S)!"
plugin-name dirname c)
(values result c)))))

The net.goenninger.thingbone.transport.mqtt.asd file has:

-X-X-X-

(in-package :cl-user)

(defpackage :net.goenninger.thingbone.transport.mqtt.asdf
(:use :cl :asdf))

(in-package :net.goenninger.thingbone.transport.mqtt.asdf)

(asdf:defsystem net.goenninger.thingbone.transport.mqtt
:name "net.goenninger.thingbone.transport.mqtt"
:version "0.0.1"

:depends-on (:alexandria
:babel
:closer-mop
:bordeaux-threads
:cells
:log4cl
:net.goenninger.lib.cellar
:net.goenninger.thingbone.common
:net.goenninger.thingbone.transport
)
:serial t

:components
((:module src
:pathname "."
:components
((:file "defpackage")
(:file "mqtt-transport"))))
)

(pushnew :net.goenninger.thingbone.transport.mqtt cl:*features*)

-X-X-X-

Now:

CL-USER> (gbt.tb.common::load-plugin-from-directory-by-plugin-name "/Users/frgo/swdev/thingbone/src/transport/plugins/mqtt/" "net.goenninger.thingbone.transport.mqtt")

==>

<WARN> [19:36:44] net.goenninger.thingbone.common plugin-handling.lisp () - Could not load plugin net.goenninger.thingbone.transport.mqtt from /Users/frgo/swdev/thingbone/src/transport/plugins/mqtt/ (ASDF error: #<CONDITIONS::SIMPLE-STYLE-WARNING 40201F84C3>)!

This made me think if my approach for loading "plugins" is viable in the
face of the requirements to be safe and stable ... Is there any other
proven approach for runtime loading of (compiled) code that is not just
a single file?

Any other comments also highly welcome!

Thx!

;; Frank