Hi, Felix-- Thanks for your reply. I have some clarifications and responses below ...
On Tue, Jan 15, 2013 at 12:42 PM, Felix < fe...@call-with-current-continuation.org> wrote: > > I am developing a project which I expect will involve a number of > extension > > libraries, or plugins (a large number, many of them provided by third > > parties, if my project ever becomes popular). For several reasons (which > I > > will explain on request if anyone is curious), I feel it is best *not* to > > implement these libraries as eggs. So I am trying to work out a > reasonable > > method for deploying the libraries and loading them at runtime. > > Sure. What does "plugin" mean, though? A dynamically loadable library? > I assume it is compiled code? Written in Scheme? > Actually, I have realized that my question conflates two similar but distinct issues. So here's what's going on, specifically: I am developing a web CMS that is intended to be somewhat like Drupal, only better. Yes, I'm probably quite insane, but at least you can't say I lack ambition ;-) The immediate problem I'm working on is a database layer. And although I am currently supporting just one database, that one is Redis, and I am anticipating that some users will be more comfortable with a traditional RDBS, say PostgresQL or SQLite (just don't say the M word to me, 'kay?). So I would like to be able to build in the capability to choose different backends. And since it is often not possible for people to compile code in a web hosting environment, it should be possible to make the choice at runtime. In any case, the database code will be compiled Chicken libraries installed in a known location. So there shouldn't be any problem finding the libraries; the issue with this component is how to load one or another implementation of a unified interface on demand, and how to manage the namespace. The ideal (which I know doesn't work and is not supposed to work), would be something like: (module sappari-lib ; main library for the framework .... ; various exports (let ((backend (string->symbol (or (get-environment-variable "SAPPARI_DB") "redis"))) (case backend ((redis) (import (prefix sappari-db-redis db:))) ((pgsql) (import (prefix sappari-db-pgsql db:))) ... [BTW .... my understanding of the module system is a bit vague, but I've seen that the docs say something like "modules are purely a syntactic construct" ... so am I right in thinking that means that modules really don't exist at runtime ... and thus, if conditional imports were possible at all, they would only be possible at compile time?] The other problem is loading the arbitrary extension libraries that users of my CMS can install at will from a huge online collection (there's my megalomania talking again ;). Although there would be a potentially infinite number of different extensions, [I think] they would really all be fancy HTTP request handlers. Here the main problem is just having a reliable way to find the appropriate library in the filesystem. Regarding compilation or lack thereof, my plan is to recommend compiling all libraries, but as mentioned above, I expect there are use cases where users would not be able to compile any code, so I would like to give them the option of installing a binary that could load the extensions as interpreted code--if it's not unreasonably difficult to do so. > > 1) Is there a way to set an arbitrary search path, such that REQUIRE (or > > LOAD, or some such thing) will work when the library is in a non-standard > > location? > > You could implement your own routine (probably based on "load"), which > scans a number of directories. "repository-path" is for eggs, and "require" > respects it. You can also add directories to "##sys#include-pathnames". > I think "require" will try this too. > I tried this, and on my system it only works for 'include', not for 'require'. BTW, I have Chicken 4.8.0 on Arch Linux. I compiled the package myself, but only in order to have the latest version; i.e. I didn't hack anything. There were no patches, and the build() function in the PKGBUILD script is: build() { cd ${pkgname}-${pkgver} # parallel builds are not supported.. export MAKEFLAGS="${MAKEFLAGS/-j?/}" # some yummy make options there. check out README in the tarball. make PLATFORM=linux PREFIX=/usr } Nothing unusual there, right? > > 2) Is it possible to load a library selected at runtime (via an > environment > > variable, config file, command-line argument ... the exact method isn't > > that important) AND have the symbols defined in that library included in > a > > module? > > You can compute arbitrary file-paths and pass them to "load". To make > the symbols available, you have to make sure the import-libraries for > the modules are available. How do you use the symbols in the > libraries? Do you evaluate code at runtime? > See above re: compilation/evaluation. As far as using symbols goes, I've haven't gotten to a detailed plan yet, but I think each plugin would register itself/its functions in a data structure established by the main library. With an open-ended collection of arbitrary components, I can't see any other sane way to do it. > > Hm. You can copy the "C_path_to_executable(argv[ 0 ])" in "chicken.h", > and use it via the foreign-function interface" to get the pathname > of an executable. Ah, thank you! I was planning to look for a function something like that, but had no idea what its name might be. I'll try it. Are there any non-obvious pitfalls I should be aware of in using this? > > 4) Is LOAD-RELATIVE broken? I wrote some test code to try to use that > > procedure, but as far as I can tell it behaves just like LOAD, i.e. any > > relative path I give it is determined relative to the current directory > > from which the program is invoked. Though I would note that the > > documentation isn't entirely clear to me: "loads FILE relative to the > path > > of the currently loaded file." ...? What does "the currently loaded file" > > mean? I will be happy to post my code if this is not a known issue. > > It means that if loading is chained, nested "load-relative" calls with > load files relative to the outer "load"/"load-relative" invocations. e.g. file a.scm: > > ... > (load "foo/b.scm") > ... > > file foo/b.scm: > > ... > (load-relative "c.scm") ; <- will load "foo/c.scm" > ... > Ohhhh, I see. This works for interpreted but not compiled code. At least that's how it is for me. Is that expected behavior? I didn't understand that from the docs. > Perhaps, if you describe the implementation of your plugins and the > way the code therein is invoked, we can give more detailed advice. > Okay, I'll be glad to describe it once I get to that stage, which should be within the next couple of months, if death or the short-term need for income don't get in the way. Thanks for all the info! -- Matt Gushee
_______________________________________________ Chicken-users mailing list Chicken-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-users