Re: How do I replace my broken ':perform' forms?

Robert Goldman <[email protected]> Mon, 08 Dec 2008 10:47:55 -0600
Newsgroups gmane.lisp.cclan.general
Message-ID <[email protected]>
Thom Goodsell wrote:
> Sorry if this has been covered, or if it's just really obvious, but I  
> couldn't find anything helpful in the archives.
> 
> I recently (i.e., about 15 minutes ago) got a new version of asdf.lisp  
> when I updated my copy of ccl, and it broke a behavior I've been  
> using. I *believe* that I was using the behavior incorrectly, and that  
> the change was a bugfix, though I could be misunderstanding the svn  
> logs.
> 
> In my defsystem, I have the following bit of code:
> 
>    :perform (load-op :before (op c)
> 		    ;; the before method runs after dependencies are loaded,
> 		    ;; but before the components are loaded, so clsql-mysql is  
> available
> 		    (pushnew #p"/usr/local/mysql/lib/"      ; local development
> 			     (symbol-value (find-symbol "*FOREIGN-LIBRARY-SEARCH-PATHS*"
> 							:clsql-sys)))
> 		    (asdf:oos 'asdf:load-op 'clsql-mysql))
> 
> It appears, now, that my comment is not correct. The idea is that I  
> want to load all the systems from :depends-on, which includes clsql.  
> Then I want to set up clsql-sys:*foreign-library-search-paths* to  
> include the correct version of the MySQL libraries. Finally, I want to  
> load the mysql components of clsql.
> 
> Does anyone have advice on the Right Way (or even just a good way) to  
> do this?
> 

If I understand correctly, this won't work because the system itself
undergoes the perform operation only /after/ all of its components
undergo that operation.  I.e., if you have a system S with components A
and B, you'll see something like

(perform <op> A) (perform <op> B) (perform <op> C)

This has been a perpetual source of friction in using ASDF to do
non-standard things.  For example, this is why I can't write an :around
method to dynamically bind a variable over the entire set of operations
on a system.

What would be nice would be if the ASDF plan were to include a
hierarchical structure something like:

(perform <composite-op> S
   :children
   ((perform <op> A)
   (perform <op> B)
   (perform <op> C)))

It's not obvious how to do this, though, since I think one could end up
with complex plans where the loading operations for a single component
(S) are non-contiguous.

There are various unpleasant kludges around this.  For your case, I
would suggest making a faux system something like

(defsystem clsql-version-identifier
   :depends-on (:clsql)
   :perform ... generalization of your :before method here...
)

Then make your *real* system depend on clsql-version-identifier.

Note that I have NOT tried this, and I have a vague memory that ASDF may
behave oddly when given a system that has no components.  You'll have to
investigate this yourself.

Alternatively, can't you just define a method like

(defmethod perform :after ((op load-op) (c (find-system 'clsql-mysql)))
   ....)

This may be tricky, though, to get the find-system to work properly when
this perform method definition is read...

Best,
r

------------------------------------------------------------------------------
SF.Net email is Sponsored by MIX09, March 18-20, 2009 in Las Vegas, Nevada.
The future of the web can't happen without you.  Join us at MIX09 to help
pave the way to the Next Web now. Learn more and register at
http://ad.doubleclick.net/clk;208669438;13503038;i?http://2009.visitmix.com/