September 29th, 2008

Filing off life's little irritating corners

Sometimes asdf-install drives me crazy. Here's what I've been doing in my ~/.sbclrc so it doesn't ask me where I want to install all the time:

(require 'asdf)
(require 'asdf-install)

(setf asdf-install::*locations*
      (list (list "~/asdf/source/" "~/asdf/systems/" "ASDF")))

(push #p"~/asdf/systems/" asdf:*central-registry*)

(fmakunbound 'asdf-install::where)

(defun asdf-install::where ()
  (first asdf-install::*locations*))

On a related note, I can't live without tilde expansion in sbcl any more.

More irritant-reduction

In SBCL, ASDF hooks into the REQUIRE mechanism so you can type (require 'mysystem). On other systems you can also figure out a way to hook REQUIRE, so you can avoid typing (asdf:oos 'asdf:load-op 'mysystem).

I got tired of trying to figure out how to do this in different ways on different Lisp systems, so below is a file I've been loading from my init files to get consistent, concise ASDF loading across implementations. It also adds a crude registry maintenance system and a way to reload a system without using :FORCE. :FORCE has the downside of recompiling and reloading all other dependencies, which is never what I want.

It's a work in progress, but so far I've been pretty happy using (asdf:load* 'mysystem) and (asdf:reload 'mysystem). YMMV.

(require 'asdf)

(in-package #:asdf)

(export '(load* reload register register-permanently))

(defvar *registry-file*
  (merge-pathnames (make-pathname :directory '(:relative "asdf")
                                  :name "registry"
                                  :type "sexp")
                   (user-homedir-pathname)))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (let ((registry (probe-file *registry-file*)))
    (when registry
      (with-open-file (stream registry)
        (loop for form = (read stream nil)
              while form do (push form *central-registry*))
        (setf *central-registry*
              (remove-duplicates *central-registry* :test #'equalp))))))

(defun load* (system &key verbose)
  (oos 'load-op system :verbose verbose)
  t)

(defun reload (system)
  (let ((name (coerce-name system)))
    (remhash name *defined-systems*)
    (load* name)))

(defun register (form)
  (pushnew form *central-registry* :test #'equalp))

(defun register-permanently (form)
  (register form)
  (ensure-directories-exist *registry-file*)
  (with-open-file (stream *registry-file*
                   :direction :output
                   :if-exists :append
                   :if-does-not-exist :create)
    (prin1 form stream)
    (terpri stream)))

;;; Automatically recompile stale FASLs

(handler-bind ((style-warning #'muffle-warning))
  (defmethod perform :around ((o load-op) (c cl-source-file))
    (handler-case (call-next-method o c)
      (#+sbcl sb-ext:invalid-fasl
       #-sbcl error ()
       (perform (make-instance 'compile-op) c)
       (call-next-method)))))

Do you have any ugly local hacks that you think aren't polished enough to share, but that make your life much easier? Share them anyway, and let's clean them up and use them and improve life everywhere.

How to fix bugs in someone else's software

Tim Kerchmar has written an excellent article about working with a vendor to debug a problem. His specific context is working with Roger Corman, but the advice applies in many other situations. For example, I think Lisp library authors are in the same boat as one-man vendors, except you aren't paying them.

Here's a bit of it:

  1. If the software vendor is a one man shop, support is a distraction from other work. He is not sitting around hitting refresh on his email waiting for the next question to answer. Your good attitude about this frustrating bug in his product will go a long way towards his feelings of good will.
  2. You don't want to piss him off. He's probably the only guy in the world who knows this software product deeply, and if you couldn't trivially solve the bug from header files or documentation, you're going to need his help.
  3. When it comes to support, you get what you pay for, although the author's pride in his product can go a small ways.
  4. He is one person. The official term for you is "user". There are lots of you guys clamoring for his time.
  5. If you do your homework, he will do his.
  6. Don't distract him with your bad spelling or grammar.