From: Christopher Browne
Subject: The Packaging Struggle...
Date: 
Message-ID: <c26est$1pknm1$4@ID-125932.news.uni-berlin.de>
The thing that _regularly_ infuriates me is every time I try to build
some CL packages to partition my code.

I set up a file containing the package "MAILCLASS," which exports the
various objects I want published, thus:

---------------------------------------------------------------------
;;; mailclass.lisp
(defpackage "MAILCLASS"
    (:use "COMMON-LISP")
  (:export word folder wordstats message *words* *folders* *num-words*))

(in-package "MAILCLASS")
(defclass word ()
  ;;; stuff...
(defclass folder ()
  ;;; stuff...
(defclass wordstats ()
  ;;; stuff...
(defclass message ()
  ;;; stuff...
(defvar *words* (make-hash-table :test 'equal))
(defvar *folders* (make-hash-table :test 'equal))
(defvar *num-words* nil)
---------------------------------------------------------------------

That compiles fine, and loads fine.

Then, I want to use it as part of another package:
---------------------------------------------------------------------
(defpackage "SCOREMESSAGE"     ;;; Define another package...
    (:use "COMMON-LISP")
  (:export score-message))

(require 'mailclass "bayes:mailclass") 
(use-package 'mailclass)

(in-package "SCOREMESSAGE")
(defmethod score-message ((message message))
  ;;; stuff...

But then things get odd...

* (compile-file "bayes:scoremessage")

; Python version 1.1, VM version Intel x86 on 04 MAR 04 12:04:37 am.
; Compiling: /brownes/wolfe/home/cbbrowne/Lisp/bayes/scoremessage.lisp 03 MAR 04 11:49:49 pm

; Byte Compiling Top-Level Form: 

Type-error in COMMON-LISP::PACKAGE-OR-LOSE:  "MAILCLASS" is not of type PACKAGE

Hmm.  Apparently having the (require 'mailclass "mailclass") doesn't
do anything at compile time.

Well, if I _start_ by loading mailclass first, and then compiling
scoremessage, it works.

0] (load "bayes:mailclass")
; Loading #p"/brownes/wolfe/home/cbbrowne/Lisp/bayes/mailclass.fasl".
T
0] (compile-file "bayes:scoremessage")
; Compiling: /brownes/wolfe/home/cbbrowne/Lisp/bayes/scoremessage.lisp 03 MAR 04 11:49:49 pm
; /home/cbbrowne/Lisp/bayes/scoremessage.fasl written.
#p"/brownes/wolfe/home/cbbrowne/Lisp/bayes/scoremessage.fasl"

Great!  But loading scoremessage doesn't turn out quite well:

0] (load "bayes:scoremessage")
; Loading #p"/brownes/wolfe/home/cbbrowne/Lisp/bayes/scoremessage.fasl".
; Warning: Loading object file /brownes/wolfe/home/cbbrowne/Lisp/bayes/mailclass.fasl,
; which is older than the presumed source:
;   /brownes/wolfe/home/cbbrowne/Lisp/bayes/mailclass.lisp.
;; Loading #p"/brownes/wolfe/home/cbbrowne/Lisp/bayes/mailclass.fasl".

Error in function PCL::FIND-CLASS-FROM-CELL:  No class named: MESSAGE.
Error flushed ...

Is there some sort of tutorial on modern usage of packages alongside
load/compile/require/such?  I suppose that I ought to ultimately
figure out ASDF, but I'd think that understanding underlying
components would be better, right?
-- 
(reverse (concatenate 'string "gro.mca" ·@" "enworbbc"))
http://cbbrowne.com/info/sgml.html
When I die, I'd like to go peacefully in my sleep like my grandfather,
not screaming in terror like his passengers...

From: Barry Margolin
Subject: Re: The Packaging Struggle...
Date: 
Message-ID: <barmar-2D0785.00584004032004@comcast.ash.giganews.com>
In article <···············@ID-125932.news.uni-berlin.de>,
 Christopher Browne <········@acm.org> wrote:

> The thing that _regularly_ infuriates me is every time I try to build
> some CL packages to partition my code.
> 
> I set up a file containing the package "MAILCLASS," which exports the
> various objects I want published, thus:
> 
> ---------------------------------------------------------------------
> ;;; mailclass.lisp
> (defpackage "MAILCLASS"
>     (:use "COMMON-LISP")
>   (:export word folder wordstats message *words* *folders* *num-words*))
> 
> (in-package "MAILCLASS")
> (defclass word ()
>   ;;; stuff...
> (defclass folder ()
>   ;;; stuff...
> (defclass wordstats ()
>   ;;; stuff...
> (defclass message ()
>   ;;; stuff...
> (defvar *words* (make-hash-table :test 'equal))
> (defvar *folders* (make-hash-table :test 'equal))
> (defvar *num-words* nil)
> ---------------------------------------------------------------------
> 
> That compiles fine, and loads fine.
> 
> Then, I want to use it as part of another package:
> ---------------------------------------------------------------------
> (defpackage "SCOREMESSAGE"     ;;; Define another package...
>     (:use "COMMON-LISP")
>   (:export score-message))
> 
> (require 'mailclass "bayes:mailclass") 
> (use-package 'mailclass)

Why isn't this in the DEFPACKAGE?  This USE-PACKAGE will modify the 
package that's current at the time the user loads this file, not the 
SCOREMESSAGE package.

> 
> (in-package "SCOREMESSAGE")
> (defmethod score-message ((message message))
>   ;;; stuff...
> 
> But then things get odd...
> 
> * (compile-file "bayes:scoremessage")
> 
> ; Python version 1.1, VM version Intel x86 on 04 MAR 04 12:04:37 am.
> ; Compiling: /brownes/wolfe/home/cbbrowne/Lisp/bayes/scoremessage.lisp 03 MAR 
> 04 11:49:49 pm
> 
> ; Byte Compiling Top-Level Form: 
> 
> Type-error in COMMON-LISP::PACKAGE-OR-LOSE:  "MAILCLASS" is not of type 
> PACKAGE
> 
> Hmm.  Apparently having the (require 'mailclass "mailclass") doesn't
> do anything at compile time.

Why should it?  REQUIRE is just an ordinary function, and they don't 
cause compile-time side effects.  If you want it executed at compile 
time and run time, use:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (require 'mailclass "bayes:mailclass"))

> 
> Well, if I _start_ by loading mailclass first, and then compiling
> scoremessage, it works.
> 
> 0] (load "bayes:mailclass")
> ; Loading #p"/brownes/wolfe/home/cbbrowne/Lisp/bayes/mailclass.fasl".
> T
> 0] (compile-file "bayes:scoremessage")
> ; Compiling: /brownes/wolfe/home/cbbrowne/Lisp/bayes/scoremessage.lisp 03 MAR 
> 04 11:49:49 pm
> ; /home/cbbrowne/Lisp/bayes/scoremessage.fasl written.
> #p"/brownes/wolfe/home/cbbrowne/Lisp/bayes/scoremessage.fasl"
> 
> Great!  But loading scoremessage doesn't turn out quite well:
> 
> 0] (load "bayes:scoremessage")
> ; Loading #p"/brownes/wolfe/home/cbbrowne/Lisp/bayes/scoremessage.fasl".
> ; Warning: Loading object file 
> /brownes/wolfe/home/cbbrowne/Lisp/bayes/mailclass.fasl,
> ; which is older than the presumed source:
> ;   /brownes/wolfe/home/cbbrowne/Lisp/bayes/mailclass.lisp.
> ;; Loading #p"/brownes/wolfe/home/cbbrowne/Lisp/bayes/mailclass.fasl".
> 
> Error in function PCL::FIND-CLASS-FROM-CELL:  No class named: MESSAGE.
> Error flushed ...

You need to ensure that the package state is the same at load time as it 
was at compile time.

The most common solution to this is to put all the package-manipulating 
code in separate source files from everything else.  Make sure they're 
compiled and loaded before compiling and/or loading the files that 
depend on them.  A MAKE-SYSTEM facility can be very helpful in 
automating this.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Willy
Subject: Re: The Packaging Struggle...
Date: 
Message-ID: <66401d34.0403040732.588bd07e@posting.google.com>
Having run into this sort of problem myself, I think it would be very
useful to people new to lisp to be able to point to a canonical
open-source project that uses modules, packages, and defsystem or
mksystem properly. Ideally this would be a small project (but not too
small that it doesn't flesh out the obvious cases). Can anyone point
me to a project that meets these requirements?
From: Matthew Danish
Subject: Re: The Packaging Struggle...
Date: 
Message-ID: <20040304154456.GO31147@mapcar.org>
On Thu, Mar 04, 2004 at 07:32:28AM -0800, Willy wrote:
> Having run into this sort of problem myself, I think it would be very
> useful to people new to lisp to be able to point to a canonical
> open-source project that uses modules, packages, and defsystem or
> mksystem properly. Ideally this would be a small project (but not too
> small that it doesn't flesh out the obvious cases). Can anyone point
> me to a project that meets these requirements?

http://www.cliki.net/Library

Lots of real-world examples there.  Particularly look at the ones with
an ASDF install link (and perhaps try out the ASDF-INSTALL package
http://www.cliki.net/asdf-install).

-- 
; Matthew Danish <·······@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."
From: R. Scott McIntire
Subject: Re: The Packaging Struggle...
Date: 
Message-ID: <L9KdnQDpx_US_trdRVn-hw@comcast.com>
I have an open source project that is composed of small to medium projects
that I think meets these needs. It is hosted at SourceForge, the URL is
http://sourceforge.net/projects/com-lisp-utils

"Willy" <·········@sbcglobal.net> wrote in message
·································@posting.google.com...
> Having run into this sort of problem myself, I think it would be very
> useful to people new to lisp to be able to point to a canonical
> open-source project that uses modules, packages, and defsystem or
> mksystem properly. Ideally this would be a small project (but not too
> small that it doesn't flesh out the obvious cases). Can anyone point
> me to a project that meets these requirements?
From: Joe Marshall
Subject: Re: The Packaging Struggle...
Date: 
Message-ID: <ishk52jy.fsf@comcast.net>
Christopher Browne <········@acm.org> writes:

[package woes snipped]

I agree, the package system is a pain in the ass.  But packages and I
have made an uneasy peace with each other.  The trick is this:

  "The important point is that the packages setup when you compile a
  file must be identical to the packages setup when you load the
  file....  What will help, 100%, is to have a file which issues all
  the necessary `defpackage' forms, and make sure this file is loaded
  before anything else and before any `compile-file'."
      -- Bruno Haible

So I put *all* the package definitions in one file separate from all
the other code and *no* other file manipulates the packages.  Each
file begins with the appropriate (in-package ...) form.

Additionally, I have come to the conclusion that `require' and
`provide' are `meta-level' functions and have no business being in the
source code.  (Actually I have found no use for them at all.)  The
system configuration and definition lives in a separate file as well.

Having done this, I rarely get the kinds of errors you are talking
about.

-- 
~jrm
From: Marco Antoniotti
Subject: Re: The Packaging Struggle...
Date: 
Message-ID: <_rI1c.78$IJ5.52766@typhoon.nyu.edu>
Well, there are a few gotchas that are avoided with a different code 
organization.  Using MK:DESFSYSTEM or ASDF is the way to go and avoid 
relying on the deprecated and underspecified REQUIRE/PROVIDE.

Christopher Browne wrote:

> The thing that _regularly_ infuriates me is every time I try to build
> some CL packages to partition my code.
> 
> I set up a file containing the package "MAILCLASS," which exports the
> various objects I want published, thus:
> 
> ---------------------------------------------------------------------
> ;;; mailclass.lisp
> (defpackage "MAILCLASS"
>     (:use "COMMON-LISP")
>   (:export word folder wordstats message *words* *folders* *num-words*))
> 
> (in-package "MAILCLASS")
> (defclass word ()
>   ;;; stuff...
> (defclass folder ()
>   ;;; stuff...
> (defclass wordstats ()
>   ;;; stuff...
> (defclass message ()
>   ;;; stuff...
> (defvar *words* (make-hash-table :test 'equal))
> (defvar *folders* (make-hash-table :test 'equal))
> (defvar *num-words* nil)
> ---------------------------------------------------------------------

I would break this up in mailclass-pkg.lisp and mailclass.lisp


> 
> That compiles fine, and loads fine.
> 
> Then, I want to use it as part of another package:
> ---------------------------------------------------------------------
> (defpackage "SCOREMESSAGE"     ;;; Define another package...
>     (:use "COMMON-LISP")
>   (:export score-message))
> 
> (require 'mailclass "bayes:mailclass") 
> (use-package 'mailclass)
> 
> (in-package "SCOREMESSAGE")
> (defmethod score-message ((message message))
>   ;;; stuff...
> 

Well....  If the SCOREMESSAGE uses MAILCLASS then you should do

(defpackage "SCOREMESSAGE" (:use "CL" "MAILCLASS") ....)


> But then things get odd...
> 
> * (compile-file "bayes:scoremessage")
> 
> ; Python version 1.1, VM version Intel x86 on 04 MAR 04 12:04:37 am.
> ; Compiling: /brownes/wolfe/home/cbbrowne/Lisp/bayes/scoremessage.lisp 03 MAR 04 11:49:49 pm
> 
> ; Byte Compiling Top-Level Form: 
> 
> Type-error in COMMON-LISP::PACKAGE-OR-LOSE:  "MAILCLASS" is not of type PACKAGE
> 
> Hmm.  Apparently having the (require 'mailclass "mailclass") doesn't
> do anything at compile time.

Well, you can try to wrap things in

	(eval-when (:load-toplevel :compile-toplevel)
	   (require 'mailclass ....))




> 
> Well, if I _start_ by loading mailclass first, and then compiling
> scoremessage, it works.
> 
> 0] (load "bayes:mailclass")
> ; Loading #p"/brownes/wolfe/home/cbbrowne/Lisp/bayes/mailclass.fasl".
> T
> 0] (compile-file "bayes:scoremessage")
> ; Compiling: /brownes/wolfe/home/cbbrowne/Lisp/bayes/scoremessage.lisp 03 MAR 04 11:49:49 pm
> ; /home/cbbrowne/Lisp/bayes/scoremessage.fasl written.
> #p"/brownes/wolfe/home/cbbrowne/Lisp/bayes/scoremessage.fasl"
> 
> Great!  But loading scoremessage doesn't turn out quite well:
> 
> 0] (load "bayes:scoremessage")
> ; Loading #p"/brownes/wolfe/home/cbbrowne/Lisp/bayes/scoremessage.fasl".
> ; Warning: Loading object file /brownes/wolfe/home/cbbrowne/Lisp/bayes/mailclass.fasl,
> ; which is older than the presumed source:
> ;   /brownes/wolfe/home/cbbrowne/Lisp/bayes/mailclass.lisp.
> ;; Loading #p"/brownes/wolfe/home/cbbrowne/Lisp/bayes/mailclass.fasl".
> 
> Error in function PCL::FIND-CLASS-FROM-CELL:  No class named: MESSAGE.
> Error flushed ...

Looking at the sequence of messages, this is an interesting error.  What 
is the backtrace?

> Is there some sort of tutorial on modern usage of packages alongside
> load/compile/require/such?  I suppose that I ought to ultimately
> figure out ASDF, but I'd think that understanding underlying
> components would be better, right?

The DEFSYSTEM I'd set up (in a file named "mymail.system") would look 
like this

(mk:defsystem "MYMAIL"
    :components ("mailclass-pkg"
                 (:file "mailclass"
                        :depends-on ("mailclass-pkg"))
                 "scoremessage-pkg"
                 (:file "scoremessage"
                        :depends-on ("mailclass" "scoremessage-pkg"))))


Cheers
--
Marco
From: Dave Roberts
Subject: Re: The Packaging Struggle...
Date: 
Message-ID: <yHg2c.125991$4o.165417@attbi_s52>
Marco Antoniotti wrote:

> Well, there are a few gotchas that are avoided with a different code
> organization.  Using MK:DESFSYSTEM or ASDF is the way to go and avoid
> relying on the deprecated and underspecified REQUIRE/PROVIDE.

So, I have been trying to figure out ASDF for the past night or two. It
seems like a cross between Make and CPAN, which has me totally confused.

In general, I'm also confused about the role of basic package definitions
versus whatever is provided by ASDF or another makesystem. Is it the case
that ASDF basically provides a dependency/compilation system similar to
make, and that you still have to use standard package definitions too? That
is, ASDF will make sure that things load and compile in the correct order
so you don't get a bunch of references to things that aren't defined, but
you still need all the various package definitions to keep things in
various namespaces?

Is there a good tutorial on ASDF anywhere? I read a textfile of docs on
sf.net, but they went right over my head. I'm looking for a basic newbie
intro.

Thanks,

-- Dave

-- 
Dave Roberts
·············@re-move.droberts.com
From: Rudi Schlatte
Subject: Re: The Packaging Struggle...
Date: 
Message-ID: <m2n06u7xm2.fsf@Rudi-Schlattes-Computer.local>
Dave Roberts <·············@re-move.droberts.com> writes:

> Is there a good tutorial on ASDF anywhere? I read a textfile of docs on
> sf.net, but they went right over my head. I'm looking for a basic newbie
> intro.

I've put together a small `hello-lisp' package, with source, package
file and defsystem.  This is a typical package layout for my projects.
You can find it at http://constantly.at/lisp/hello-lisp-0.2.tar.gz

Since it's so simple, its system definition has no dependencies.  For
inter-system dependencies, you would add a
(:depends-on :name-of-a-system :another-system)
clause in the defsystem form in hello-lisp.asd so the depended-upon
systems are automatically loaded.

Hope it helps,

Rudi
From: Dave Roberts
Subject: Re: The Packaging Struggle...
Date: 
Message-ID: <rjx2c.128634$Xp.555184@attbi_s54>
Rudi Schlatte wrote:

> Dave Roberts <·············@re-move.droberts.com> writes:
 
> I've put together a small `hello-lisp' package, with source, package
> file and defsystem.  This is a typical package layout for my projects.
> You can find it at http://constantly.at/lisp/hello-lisp-0.2.tar.gz

Okay, this helped, but I have a few questions. In particular, I'm trying to
put together a library using UFFI to access the more generic DNS resolver
functions in Linux. I have to include such stuff as:

(push (make-pathname :directory 
                     '(:absolute "home" "dave" "lispstuff" "uffi-1.4.6")) 
      asdf:*central-registry*)

(asdf:operate 'asdf:load-op :uffi)

(uffi:load-foreign-library #p"/usr/lib/libresolv.so" 
                           :supporting-libraries '("c"))

(uffi:def-function ("res_query" res-query)
                   ((dname (:cstring))
                    (class :int)
                    (type :int)
                    (answer (* :unsigned-char))
                    (anslen :int))
                   :returning :int)


Now, where would I put this sort of stuff? It's basically load-time stuff
that all needs to be done first. Would I put this stuff in a separate file
and then tell ASDF that it's basically the root of the dependency tree?

-- 
Dave Roberts
·············@re-move.droberts.com
From: Rudi Schlatte
Subject: Re: The Packaging Struggle...
Date: 
Message-ID: <m27jxx86ty.fsf@Rudi-Schlattes-Computer.local>
Dave Roberts <·············@re-move.droberts.com> writes:

> Rudi Schlatte wrote:
> 
> > Dave Roberts <·············@re-move.droberts.com> writes:
>  
> > I've put together a small `hello-lisp' package, with source, package
> > file and defsystem.  This is a typical package layout for my projects.
> > You can find it at http://constantly.at/lisp/hello-lisp-0.2.tar.gz
> 
> Okay, this helped, but I have a few questions. In particular, I'm trying to
> put together a library using UFFI to access the more generic DNS resolver
> functions in Linux. I have to include such stuff as:
> 
> (push (make-pathname :directory 
>                      '(:absolute "home" "dave" "lispstuff" "uffi-1.4.6")) 
>       asdf:*central-registry*)
> 
> (asdf:operate 'asdf:load-op :uffi)
> 

No need to do that every time.

Put a symlink to /home/dave/lispstuff/uffi-1.4.6/uffi.asd in a
directory that's in your *central-registry*.  Then, you can say

(asdf:defsystem :my-system
   :components (...)
   :depends-on (:uffi))

and asdf will, upon loading your system, follow the symlink, locate
the uffi sources and load uffi before your system.


> (uffi:load-foreign-library #p"/usr/lib/libresolv.so" 
>                            :supporting-libraries '("c"))
> 
> (uffi:def-function ("res_query" res-query)
>                    ((dname (:cstring))
>                     (class :int)
>                     (type :int)
>                     (answer (* :unsigned-char))
>                     (anslen :int))
>                    :returning :int)
> 
> 

I'd put something like

(eval-when (:compile-toplevel :load-toplevel :execute)
  (uffi:load-foreign-library #p"/usr/lib/libresolv.so" 
                             :supporting-libraries '("c")))

(uffi:def-function ...)

in a file foreign-calls.lisp and make other files depend on it.
(Perhaps the eval-when is superfluous, I haven't checked.)

(asdf:defsystem :my-system
   :components ((:file "packages")
                (:file "foreign-calls" :depends-on ("packages"))
                (:file "doesnt-use-foreign-calls" :depends-on ("packages"))
                (:file "uses-foreign-calls" :depends-on ("foreign-calls")))
   :depends-on (:uffi))

There's also

(asdf:defsystem :my-system
   :serial t
   :components ((:file "packages")
                (:file "foreign-calls")
                (:file "doesnt-use-foreign-calls")
                (:file "uses-foreign-calls"))
   :depends-on (:uffi))

Here, all files depend on all files above them in the definition
form; i.e. editing foreign-calls and evaluating
(asdf:operate 'asdf:load-op :my-system)
causes foreign-calls, doesnt-use-foreign-calls and uses-foreign-calls
to be compiled and loaded in sequence.  There are also more
fine-grained ways of expressing dependencies than :depends-on; I'd
suggest checking the asdf README (the asdf documentation is being
worked on, but the README will do for now).

HTH,

Rudi
From: Rudi Schlatte
Subject: Re: The Packaging Struggle...
Date: 
Message-ID: <m2znat6ihv.fsf@Rudi-Schlattes-Computer.local>
Rudi Schlatte <····@constantly.at> writes:
>
> There are also more fine-grained ways of expressing dependencies
> than :depends-on; I'd suggest checking the asdf README (the asdf
> documentation is being worked on, but the README will do for now).
> 

On second thought -- could you have a look at
http://constantly.at/lisp/asdf/ and see if it helps?  The document is
still in very rough shape (please disregard anything after the third
chapter), but it could be helpful, and I'd be grateful for any
comments.

Thanks,

Rudi
From: Marco Antoniotti
Subject: Re: The Packaging Struggle...
Date: 
Message-ID: <kM03c.90$IJ5.70072@typhoon.nyu.edu>
Dave Roberts wrote:

> Marco Antoniotti wrote:
> 
> 
>>Well, there are a few gotchas that are avoided with a different code
>>organization.  Using MK:DESFSYSTEM or ASDF is the way to go and avoid
>>relying on the deprecated and underspecified REQUIRE/PROVIDE.
> 
> 
> So, I have been trying to figure out ASDF for the past night or two. It
> seems like a cross between Make and CPAN, which has me totally confused.

A defsystem utility is the (restricted) equivalent of make.  The 
CPAN-like extras you may find, are, well, extras.  So, do not think of 
the CPAN-like stuff.  A defsystem is just a defsystem.

> 
> In general, I'm also confused about the role of basic package definitions
> versus whatever is provided by ASDF or another makesystem. Is it the case
> that ASDF basically provides a dependency/compilation system similar to
> make, and that you still have to use standard package definitions too?

Packages is CL are like namespaces in C++.  The "tool" you use to ensure 
semantic dependencies is another thing altogether, as 'make' is in the 
C/C++ world.

  That
> is, ASDF will make sure that things load and compile in the correct order
> so you don't get a bunch of references to things that aren't defined, but
> you still need all the various package definitions to keep things in
> various namespaces?
> 
> Is there a good tutorial on ASDF anywhere? I read a textfile of docs on
> sf.net, but they went right over my head. I'm looking for a basic newbie
> intro.
> 

Looking at the CLOCC will give you an idea about how to package up 
something relatively complicated.

Cheers
--
Marco