Loading quicklisp package for use in another lisp file

793 views Asked by At

I have downloaded a large software project FriCAS which I have compiled from source and using SBCL. This was just a matter of using GNU .configure - I am a complete Lisp newbie.

However, in order to add some further functionality I have - by very carefully following directions - installed quicklisp and a few extra packages. So far so good.

Here's my issue: I am trying to compile an external lisp file for use in the system. I need to make quicklisp and its packages visible to the compiler. So I've copied my .sbclrc file to the top of my lisp file:

#-quicklisp
(let ((quicklisp-init (merge-pathnames "quicklisp/setup.lisp"
                                       (user-homedir-pathname))))
  (when (probe-file quicklisp-init)
    (load quicklisp-init)))

I have followed this with

(eval-when (:compile-toplevel)
  (ql:quickload "f2cl-lib"))

I have already installed f2cl-lib with quicklisp. However, my compiler (within FriCAS) immediately aborts with

; caught ERROR:
;   READ error during COMPILE-FILE:
;   
;     Package QL does not exist.

I'm a bit stumped here - there's probably something trivial and obvious which is missing, but as I say from a newbie perspective I don't know what it is.

1

There are 1 answers

3
Rainer Joswig On

Looks like a FAQ. See also the documentation for eval-when.

The File Compiler

Remember, a file compiler compiles forms and does not execute them. It just generates code for later execution. Generally. Though, in Common Lisp there are some exceptions to this rule: for example a macro, used in the source code, will be run by the file compiler. But Common Lisp also allows us to tell the file compiler to execute code at compile time, that's one of the use cases of eval-when.

Your example simplified

If you have a file:

(load "file-which-creates-package-foo")

(eval-when (:compile-toplevel)
  (foo:bar)) 

Then the file compiler will generate code for loading the file, but it will not load the file.

Next, the file compiler sees a second form, where the file compiler is instructed to execute a statement at compile time (and only at compile time), so (foo:bar) will be executed at compile time. But it is worse: Since the loading code has not been executed yet, the package FOO is unknown, and the form (foo:bar) will be read at compile time, the reader already complains at compile time that the package FOO does not exist.

The use of EVAL-WHEN

What you need to do, is to tell the file compiler to actually load the stuff it needs during compilation. The file already contains an eval-when form, so that should give you a hint: use eval-when. It has three situations:

  • :compile-toplevel -> the file compiler executes the enclosed forms
  • :load-toplevel -> the file compiler generates code so that the code will be executed when loading the code
  • :execute

Make sure that those situations are mentioned, when the code should be executed.

Possible solutions

So there are possible solutions:

  • as above, use EVAL-WHEN to be able to execute forms by the file compiler
  • write the loading code into a separate file and compile/load this file before you use the package. One could also add this file to a system such that it will be loaded by the compiling the system, before the using code will be compiled.