From: Pascal Costanza
Subject: Separating compilation output
Date: 
Message-ID: <3pb5j4F9e07aU1@individual.net>
Hi,

I switch a lot between different CL implementations, and I would like to 
have my folders tidy. (I am German, you know. ;)

However by default, ASDF compiles everything into the same folder as the 
source files. In order to get around this, I have defined the following 
method:

(defmethod asdf:output-files :around
   ((op asdf:compile-op) (src asdf:source-file))
   (let ((paths (call-next-method)))
     (mapcar (lambda (path)
	      (merge-pathnames
	       (make-pathname
                 :directory
                 (append
                  (pathname-directory path)
                  (list #+allegro-v6.2 ".acl62"
                        #+allegro-v7.0 ".acl70"
                        #+clisp ".clisp"
                        #+cmu ".cmu"
                        #+lispworks4.3 ".lispworks4.3"
                        #+lispworks4.4 ".lispworks4.4"
                        #+(and mcl (not openmcl)) ".mcl"
                        #+openmcl ".openmcl"
                        #+sbcl ".sbcl")))
	       path))
	    paths)))

This works almost all of the time - only sometimes this bites me, as in 
my recent attempt to run the CFFI tests.

What do other people do to keep things organized?


Pascal

-- 
OOPSLA'05 tutorial on generic functions & the CLOS Metaobject Protocol
++++ see http://p-cos.net/oopsla05-tutorial.html for more details ++++

From: GP lisper
Subject: Re: Separating compilation output
Date: 
Message-ID: <1127260146.300c1b6a483b17df93246caa6564c437@teranews>
On Tue, 20 Sep 2005 21:17:55 +0200, <··@p-cos.net> wrote:
>
> I switch a lot between different CL implementations, and I would like to 
> have my folders tidy. (I am German, you know. ;)
>
> What do other people do to keep things organized?

I use different computers actually....but yesterday I had some
problems sharing CLSQL amongst multiple users.  Your post allowed me
to solve that nicely, well almost, outside of the hack of giving
everybody their own CLSQL.  At least the ASDF search remained generic,
thanks to reading your post (and again I avoided any learning of
pathnames!)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; find the ASDF files, CMUCL specific!

(defparameter *original-asdf-registry* ASDF:*CENTRAL-REGISTRY*)

(defun asdf-global-scanner ()
  (directory
   (make-pathname :directory
		  '(:absolute "usr" "local" "lib" "cmucl" "lib" "subsystems" :wild-inferiors)
		  :type "asd")))

(defun asdf-local-scanner ()
  (directory
   (make-pathname :directory
		  (append (pathname-directory "home:")
			  (list ".lisp" :wild-inferiors))
		  :type "asd")))

(defun update-asdf-registry ()
  (setf ASDF:*CENTRAL-REGISTRY*
	(nconc (asdf-global-scanner)
	       (asdf-local-scanner)
	       *original-asdf-registry*)))

(update-asdf-registry)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



-- 
In Common Lisp quite a few aspects of pathname semantics are left to the implementation.
From: Matthew D Swank
Subject: Re: Separating compilation output
Date: 
Message-ID: <pan.2005.09.21.00.35.54.69763@c.net>
On Tue, 20 Sep 2005 21:17:55 +0200, Pascal Costanza wrote:

> Hi,
> 
> I switch a lot between different CL implementations, and I would like to 
> have my folders tidy. (I am German, you know. ;)
> 
...

> What do other people do to keep things organized?
> 
> 
> Pascal

I submit to the discipline of the common-lisp-controller: it separates
fasl's by user name and implementation

-- 
"You do not really understand something unless you can
 explain it to your grandmother." — Albert Einstein.
From: Peter Seibel
Subject: Re: Separating compilation output
Date: 
Message-ID: <m2mzm7z2rj.fsf@gigamonkeys.com>
Pascal Costanza <··@p-cos.net> writes:

> Hi,
>
> I switch a lot between different CL implementations, and I would like
> to have my folders tidy. (I am German, you know. ;)
>
> However by default, ASDF compiles everything into the same folder as
> the source files. In order to get around this, I have defined the
> following method:
>
> (defmethod asdf:output-files :around
>    ((op asdf:compile-op) (src asdf:source-file))
>    (let ((paths (call-next-method)))
>      (mapcar (lambda (path)
> 	      (merge-pathnames
> 	       (make-pathname
>                  :directory
>                  (append
>                   (pathname-directory path)
>                   (list #+allegro-v6.2 ".acl62"
>                         #+allegro-v7.0 ".acl70"
>                         #+clisp ".clisp"
>                         #+cmu ".cmu"
>                         #+lispworks4.3 ".lispworks4.3"
>                         #+lispworks4.4 ".lispworks4.4"
>                         #+(and mcl (not openmcl)) ".mcl"
>                         #+openmcl ".openmcl"
>                         #+sbcl ".sbcl")))
> 	       path))
> 	    paths)))
>
> This works almost all of the time - only sometimes this bites me, as
> in my recent attempt to run the CFFI tests.
>
> What do other people do to keep things organized?

I put something in the Lispbox foo to do this using the function I
added to SLIME, UNIQUE-DIRECTORY-NAMES, to allow *it* to use multiple
lisps at the same time, to get the implementation-specific part of the
directory name:

;;; Build FASLs into a implementation specific directory.

(defparameter *fasl-directory* 
  (merge-pathnames
   (make-pathname
    :directory `(:relative ".lispbox" "fasl" ,(swank-loader::unique-directory-name)))
   (user-homedir-pathname)))

(defmethod output-files :around ((operation compile-op) (c source-file))
  (let ((defaults (merge-pathnames 
                   (make-relative (component-pathname c))
                   *fasl-directory*)))
    (flet ((relocate-fasl (file)
             (make-pathname
              :type (pathname-type file) :defaults defaults)))
      (mapcar #'relocate-fasl (call-next-method)))))

;; Static files

(defmethod output-files :around ((operation compile-op) (c static-file))
  (list
   (merge-pathnames (make-relative (component-pathname c)) *fasl-directory*)))

(defmethod perform :after ((operation compile-op) (c static-file))
  (let ((source-file (component-pathname c))
	(output-file (car (output-files operation c))))
    (ensure-directories-exist output-file)
    (with-open-file (in source-file :element-type '(unsigned-byte 8))
      (with-open-file (out output-file :element-type '(unsigned-byte 8) :direction :output :if-exists :supersede)
        (loop for octet = (read-byte in nil nil)
             while octet do (write-byte octet out))))))


(defun make-relative (pathname)
  (make-pathname
   :directory (cons :relative (rest (pathname-directory pathname)))
   :defaults pathname))




>
>
> Pascal
>
> -- 
> OOPSLA'05 tutorial on generic functions & the CLOS Metaobject Protocol
> ++++ see http://p-cos.net/oopsla05-tutorial.html for more details ++++

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Luis Oliveira
Subject: Re: Separating compilation output
Date: 
Message-ID: <m2fyrzp422.fsf@pomajxego.local>
Pascal Costanza <··@p-cos.net> writes:
> This works almost all of the time - only sometimes this bites me, as
> in my recent attempt to run the CFFI tests.

Your code is very useful not only to keep things tidy but also to avoid
the annoying problems between implementations that have the same
extension for FASL files. I'll probably place those per-implementation
directories under a common directory, say, ".fasls".

The problem with the CFFI test-suite is that it will attempt to load the
shared library in the same directory as the FASL file,
i.e. (pathname-directory *load-truename*). Since I'll be using this code
of yours I'm changing that to #.(or *compile-file-name* *load-truename*)
that way it should work. (Is there a better solution?)


> What do other people do to keep things organized?

make clean :-) (and, in my room, I throw things away)

Here's my version of your code plus slime's swank code to create unique
directories for each implementation:

(cl:defpackage #:org.kerno.asdf-addons
  (:use #:cl))

(in-package #:org.kerno.asdf-addons)

(defparameter *implementation-features*
  '(:allegro :lispworks :sbcl :openmcl :cmu :clisp :ccl :corman :cormanlisp
    :armedbear :gcl :ecl))

(defparameter *os-features*
  '(:macosx :macos :linux :windows :mswindows :win32 :solaris :darwin :sunos
    :unix))

(defparameter *architecture-features*
  '(:powerpc :ppc :x86 :x86-64 :i686 :pc386 :iapx386 :sparc))

(defun lisp-version-string ()
  #+cmu (substitute #\- #\/ (lisp-implementation-version))
  #+gcl (let ((s (lisp-implementation-version))) (subseq s 4))
  #+openmcl (format nil "~d.~d" ccl::*openmcl-major-version* 
                    ccl::*openmcl-minor-version*)
  #+allegro excl::*common-lisp-version-number*
  #+clisp (let ((s (lisp-implementation-version)))
            (subseq s 0 (position #\space s)))
  #+(or sbcl ecl lispworks armedbear cormanlisp)
  (lisp-implementation-version)
  #-(or cmu gcl openmcl allegro clisp sbcl ecl lispworks armedbear cormanlisp)
  "unknown")

(defun unique-directory-name ()
  "Return a name that can be used as a directory name that is
unique to a Lisp implementation, Lisp implementation version,
operating system, and hardware architecture."
  (flet ((first-of (features)
           (or (loop for f in features
                     when (find f *features*) return it)
               "unknown")))
    (format nil "~(·@{~A~^-~}~)"
            (first-of *implementation-features*)
            (first-of *os-features*)
            (first-of *architecture-features*)
            (lisp-version-string))))
  
(defmethod asdf:output-files :around
    ((op asdf:compile-op) (src asdf:source-file))
  (let ((paths (call-next-method)))
    (mapcar (lambda (path)
              (merge-pathnames
               (make-pathname :directory
                              (append
                               (pathname-directory path)
                               (list ".fasls" (unique-directory-name))))
               path))
            paths)))

(also pasted here: <http://paste.lisp.org/display/11853>)

Looks tidy:

pomajxego:~/hic/cffi-luis/src luis$ ls
cffi-allegro.lisp   cffi-gcl.lisp       enum.lisp           package.lisp
cffi-clisp.lisp     cffi-lispworks.lisp foreign-vars.lisp   strings.lisp
cffi-cmucl.lisp     cffi-openmcl.lisp   functions.lisp      types.lisp
cffi-corman.lisp    cffi-sbcl.lisp      libraries.lisp      utils.lisp
cffi-ecl.lisp       early-types.lisp    objects.lisp
pomajxego:~/hic/cffi-luis/src luis$ ls .fasls/
allegro-macosx-powerpc-7.0     lispworks-macosx-unknown-4.4.5
clisp-macos-unknown-2.33.83    openmcl-darwin-powerpc-0.14
cmu-darwin-ppc-19b-pre1 (19b)  sbcl-darwin-ppc-0.9.4.57

-- 
Luis Oliveira
luismbo (@) gmail (.) com
Equipa Portuguesa do Translation Project
http://www.iro.umontreal.ca/translation/registry.cgi?team=pt
From: Matthew D Swank
Subject: Re: Separating compilation output
Date: 
Message-ID: <pan.2005.09.21.07.25.45.950441@c.net>
On Wed, 21 Sep 2005 03:06:45 +0100, Luis Oliveira wrote:

> Pascal Costanza <··@p-cos.net> writes:
>> This works almost all of the time - only sometimes this bites me, as
>> in my recent attempt to run the CFFI tests.
> 
> Your code is very useful not only to keep things tidy but also to avoid
> the annoying problems between implementations that have the same
> extension for FASL files. I'll probably place those per-implementation
> directories under a common directory, say, ".fasls".
> 
> The problem with the CFFI test-suite is that it will attempt to load the
> shared library in the same directory as the FASL file,
> i.e. (pathname-directory *load-truename*). Since I'll be using this code
> of yours I'm changing that to #.(or *compile-file-name* *load-truename*)
> that way it should work. (Is there a better solution?)
> 
> 
>> What do other people do to keep things organized?
> 
> make clean :-) (and, in my room, I throw things away)
> 
> Here's my version of your code plus slime's swank code to create unique
> directories for each implementation:

...

It is very nice, but it doesn't get along well with lisp code stored in
directories with _no_ write access for the user.  I hacked something, but
it's not very robust:
-----------------------------------
--- fasl-org.lisp.orig	2005-09-21 02:22:42.000000000 -0500
+++ fasl-org.lisp	2005-09-21 01:59:55.000000000 -0500
@@ -18,6 +18,9 @@
 
 (in-package #:org.kerno.asdf-addons)
 
+(defparameter *fasl-prefix* (list :absolute "var" "cache" 
+                                  "common-lisp-controller" "user"))
+
 (defparameter *implementation-features*
   '(:allegro :lispworks :sbcl :openmcl :cmu :clisp :ccl :corman :cormanlisp
     :armedbear :gcl :ecl))
@@ -63,7 +66,8 @@
               (merge-pathnames
                (make-pathname :directory
                               (append
-                               (pathname-directory path)
+                               *fasl-prefix*
+                               (cdr (pathname-directory path))
                                (list ".fasls" (unique-directory-name))))
                path))
             paths)))
\ No newline at end of file


-- 
"You do not really understand something unless you can
 explain it to your grandmother." — Albert Einstein.
From: Pascal Costanza
Subject: Re: Separating compilation output
Date: 
Message-ID: <3pd406F9tafuU1@individual.net>
Matthew D Swank wrote:

> It is very nice, but it doesn't get along well with lisp code stored in
> directories with _no_ write access for the user.  I hacked something, but
> it's not very robust:
[...]

What's the problem (wrt robustness)?

Pascal

-- 
OOPSLA'05 tutorial on generic functions & the CLOS Metaobject Protocol
++++ see http://p-cos.net/oopsla05-tutorial.html for more details ++++
From: Matthew D Swank
Subject: Re: Separating compilation output
Date: 
Message-ID: <pan.2005.09.21.17.23.10.568574@c.net>
On Wed, 21 Sep 2005 15:03:02 +0200, Pascal Costanza wrote:

> Matthew D Swank wrote:
> 
>> It is very nice, but it doesn't get along well with lisp code stored in
>> directories with _no_ write access for the user.  I hacked something, but
>> it's not very robust:
> [...]
> 
> What's the problem (wrt robustness)?
> 
> Pascal

Maybe robust is not the right word. The asdf:output-files method interacts
strangely with systems already managed by the common-lisp-controller
(which provides its own fasl directories).  This, of course, is not a
problem for people who don't use the controller.  I need to find a way to
effectively say: "If you're managed by the common-lisp-controller, ignore
this around method.".

Matt

-- 
"You do not really understand something unless you can
 explain it to your grandmother." — Albert Einstein.
From: Pascal Costanza
Subject: Re: Separating compilation output
Date: 
Message-ID: <3pe1p3Fa0g6oU1@individual.net>
Matthew D Swank wrote:
> On Wed, 21 Sep 2005 15:03:02 +0200, Pascal Costanza wrote:
> 
> 
>>Matthew D Swank wrote:
>>
>>
>>>It is very nice, but it doesn't get along well with lisp code stored in
>>>directories with _no_ write access for the user.  I hacked something, but
>>>it's not very robust:
>>
>>[...]
>>
>>What's the problem (wrt robustness)?
>>
>>Pascal
> 
> 
> Maybe robust is not the right word. The asdf:output-files method interacts
> strangely with systems already managed by the common-lisp-controller
> (which provides its own fasl directories).  This, of course, is not a
> problem for people who don't use the controller.  I need to find a way to
> effectively say: "If you're managed by the common-lisp-controller, ignore
> this around method.".

This would actually be a good case for ContextL.

(deflayer fasl-manager)

(define-layered-method asdf:output-files
   :in-layer fasl-manager :around
   (...)
   ...)

...and then, whenever something is compiled that is not controlled by 
clc, do this:

(with-active-layers (fasl-manager)
   (asdf:oos 'asdf:compile-op ...))

...or something along these lines.

However, this would only work if #'asdf:output-files would be changed to 
be a layered generic function.


Pascal

-- 
OOPSLA'05 tutorial on generic functions & the CLOS Metaobject Protocol
++++ see http://p-cos.net/oopsla05-tutorial.html for more details ++++
From: Matthew D Swank
Subject: Re: Separating compilation output
Date: 
Message-ID: <pan.2005.09.22.01.45.00.254630@c.net>
On Wed, 21 Sep 2005 23:31:15 +0200, Pascal Costanza wrote:


> This would actually be a good case for ContextL.
> 

Yes it would.  I settled for the more prosaic:
-----------------------

--- fasl-org.lisp.orig	2005-09-21 20:36:43.000000000 -0500
+++ fasl-org.lisp	2005-09-21 20:42:07.000000000 -0500
@@ -18,6 +18,13 @@
 
 (in-package #:org.kerno.asdf-addons)
 
+(defparameter *exclude* (list (pathname-directory #p"/usr/lib/")
+                              (pathname-directory 
+                               #p"/usr/share/common-lisp/source/")))
+
+(defparameter *fasl-prefix* (list :absolute "var" "cache" 
+                                  "common-lisp-controller" "akopa"))
+
 (defparameter *implementation-features*
   '(:allegro :lispworks :sbcl :openmcl :cmu :clisp :ccl :corman :cormanlisp
     :armedbear :gcl :ecl))
@@ -42,6 +49,20 @@
   #-(or cmu gcl openmcl allegro clisp sbcl ecl lispworks armedbear cormanlisp)
   "unknown")
 
+;;inspired by common-lisp-controller::beneath-source-root?
+(defun beneath-excluded-p (asdf-src)
+  (unless (null asdf-src)
+    (let ((src-path (pathname-directory (asdf:component-pathname asdf-src)))) 
+      (reduce #'(lambda (result current-path)
+                  (or result
+                      (let ((len-current-path (length current-path)))
+                        (and (<= len-current-path (length src-path))
+                             (equalp current-path 
+                                     (subseq src-path 0 len-current-path))))))
+              *exclude* :initial-value nil))))
+                         
+  
+
 (defun unique-directory-name ()
   "Return a name that can be used as a directory name that is
 unique to a Lisp implementation, Lisp implementation version,
@@ -59,12 +80,16 @@
 (defmethod asdf:output-files :around
     ((op asdf:compile-op) (src asdf:source-file))
   (let ((paths (call-next-method)))
-    (mapcar (lambda (path)
-              (merge-pathnames
-               (make-pathname :directory
-                              (append
-                               (pathname-directory path)
-                               (list ".fasls" (unique-directory-name))))
-               path))
-            paths)))
+    (if (beneath-excluded-p src)
+        paths
+      (mapcar (lambda (path)
+                (merge-pathnames
+                 (make-pathname :directory
+                                (append
+                                 *fasl-prefix*
+                                 (cdr (pathname-directory path))
+                                 (list ".fasls" (unique-directory-name))))
+                 path))
+              paths))))
 
-- 
"You do not really understand something unless you can
 explain it to your grandmother." — Albert Einstein.
From: Tim X
Subject: Re: Separating compilation output
Date: 
Message-ID: <87fyrzrnl1.fsf@tiger.rapttech.com.au>
Pascal Costanza <··@p-cos.net> writes:

> Hi,
> 
> I switch a lot between different CL implementations, and I would like
> to have my folders tidy. (I am German, you know. ;)
> 

The Debian Linux distribution has nice support for keeping different
compiled versions from different lisp implementations separated using
the lisp controller. It is integrated with ASDF, so you get the
benefits of both. When you compile packages, the code is placed under
a user specific directory and a implementation specific
directory. i.e.

/var/cache/common-lisp-controller/<user>/<lisp-implementation>/<package>

Tim

 
-- 
Tim Cross
The e-mail address on this message is FALSE (obviously!). My real e-mail is
to a company in Australia called rapttech and my login is tcross - if you 
really need to send mail, you should be able to work it out!
From: Steven M. Haflich
Subject: Re: Separating compilation output
Date: 
Message-ID: <9HKYe.1232$Ur.268@newssvr29.news.prodigy.net>
Pascal:

I am disappointed that _none_ of the preceding answers to your
question have even considered the possibility of applying logical
pathnames to this problem.  It is exactly the kind of issue that
logical pathnames were designed to address.

On the other hand, logical pathnames are one of the ugliest and
least-well developed features in the entire language.  (Non-flame
translation: here was a lot of practical experience with logical
pathnames in LispMs, but the translation of those concepts into
_portable_ Common Lisp didn't survive the translation and had
essentially zero practical testing before adoption.)

However, for the simple need of rewriting compiled-file
pathnames into separate directories, logical pathnames should be
sufficient on any implementation that supports them.  And they
will work without needing to know anything further about the
internals or externals of asdf.
From: Pascal Bourguignon
Subject: Re: Separating compilation output
Date: 
Message-ID: <87ek7gqq53.fsf@thalassa.informatimago.com>
Pascal Costanza <··@p-cos.net> writes:

> Hi,
>
> I switch a lot between different CL implementations, and I would like
> to have my folders tidy. (I am German, you know. ;)
>
> However by default, ASDF compiles everything into the same folder as
> the source files. In order to get around this, I have defined the
> following method:
>
> (defmethod asdf:output-files :around
>    ((op asdf:compile-op) (src asdf:source-file))
>    (let ((paths (call-next-method)))
>      (mapcar (lambda (path)
> 	      (merge-pathnames
> 	       (make-pathname
>                  :directory
>                  (append
>                   (pathname-directory path)
>                   (list #+allegro-v6.2 ".acl62"
>                         #+allegro-v7.0 ".acl70"
>                         #+clisp ".clisp"
>                         #+cmu ".cmu"
>                         #+lispworks4.3 ".lispworks4.3"
>                         #+lispworks4.4 ".lispworks4.4"
>                         #+(and mcl (not openmcl)) ".mcl"
>                         #+openmcl ".openmcl"
>                         #+sbcl ".sbcl")))
> 	       path))
> 	    paths)))
>
> This works almost all of the time - only sometimes this bites me, as
> in my recent attempt to run the CFFI tests.
>
> What do other people do to keep things organized?

My output-files looks like the following.  
The same problems occur with some ASD.


(DEFMETHOD ASDF:OUTPUT-FILES
    ((OPERATION ASDF:COMPILE-OP) (C ASDF:CL-SOURCE-FILE))
  (FLET ((IMPLEMENTATION-ID ()
           (FLET ((FIRST-WORD (TEXT)
                    (LET ((POS (POSITION (CHARACTER " ") TEXT)))
                      (REMOVE (CHARACTER ".")
                              (IF POS (SUBSEQ TEXT 0 POS) TEXT)))))
             (FORMAT NIL
               "~A-~A-~A"
               (FIRST-WORD (LISP-IMPLEMENTATION-TYPE))
               (FIRST-WORD (LISP-IMPLEMENTATION-VERSION))
               (FIRST-WORD (MACHINE-TYPE))))))
    (LET* ((OBJECT (COMPILE-FILE-PATHNAME (ASDF:COMPONENT-PATHNAME C)))
           (PATH
            (MAKE-PATHNAME :DIRECTORY
                           (LIST :RELATIVE
                                 (FORMAT NIL
                                   ·······@(~A~)"
                                   (IMPLEMENTATION-ID)))
                           :NAME (PATHNAME-NAME OBJECT)
                           :TYPE (PATHNAME-TYPE OBJECT)
                           :DEFAULTS OBJECT)))
      (ENSURE-DIRECTORIES-EXIST PATH)
      (LIST PATH))))

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
In deep sleep hear sound,
Cat vomit hairball somewhere.
Will find in morning.