Generic lisp: got different result with SBCL after saving image
(This is the first time I posed a question here, I searched but couldn't find any useful information ....)
I found it interesting (which confused me all the damn morning), something common lisp.
I am using SBCL 1.1.18 running on Gentoo / Linux. Here's my problem:
Suppose there is a package named eql-test that has an asd file, package.lisp and main.lisp (a fairly common configuration). There is only one function inside main.lisp:
(defun main ()
(format t "~a~%" (eql 'hello (read-from-string "hello"))))
Now if we run:
sbcl --eval "(progn (load \"main.lisp\") \
(sb-ext:save-lisp-and-die \"eql-test\" :toplevel #'main \
:executable t))"
and then run the "eql-test" binary, we get a nice T.
However, if we use another file named "make.lisp" which contains:
(asdf:load-system 'eql-test)
(sb-ext:save-lisp-and-die "eql-test2"
:toplevel #'eql-test:main
:executable t)
and then run:
sbcl --load "make.lisp"
then run the binary "eql-test2" it will give NIL.
I don't understand why the same code gives a different result (definitely the second is wrong). Because it is an implicit ASDF error? Or is there something wrong with my code?
Thanks for any help! :)
source to share
Rule of thumb: When in doubt, always monitor which package is used in the source code, in I / O operations, when creating new characters when looking for characters, ...
If you are reading a line, you have to make sure that any generated symbol will be in the correct package. You can link *package*
:
CL-USER 1 > *package*
#<The COMMON-LISP-USER package, 155/256 internal, 0/4 external>
CL-USER 2 > (read-from-string "FOO")
FOO
3
Above: FOO
found in the package CL-USER
.
Create a new package:
CL-USER 3 > (defpackage "BAR" (:use "CL"))
#<The BAR package, 0/16 internal, 0/16 external>
The global has *package*
n't changed:
CL-USER 4 > *package*
#<The COMMON-LISP-USER package, 155/256 internal, 0/4 external>
Bind variable:
CL-USER 5 > (let ((*package* (find-package "BAR")))
(read-from-string "FOO"))
BAR::FOO
3
Above: FOO
found in the package BAR
.
Also make sure any source code is a package specific ... make sure the package is not modified in various ways to download the code ...
source to share
Finally I got an answer that seems to be correct ... the post is here to help.
Suppose you want to (eq 'foo (read-from-string "foo"))
return the T which "foo is in MY-PACKAGE
.
First, and most IMPORTANT, if we are doing (read-from-string "foo")
either or (intern "foo")
or (find-symbol "foo")
or whatever, the real character readable by the reader |foo|
, which means "foo" in lowercase as the name of the character, but not FOO
what we want. As these functions will exactly read the character you give as a string. So, (read-from-string "foo")
will return a character FOO
. - This is exactly what we want.
Second, and also importantly, when we are (save-lisp-and-die ...)
in SBCL (use "buildapp" instead) and run the generated image executable, we are in the package COMMON-LISP-USER
, but not something else. So actually LISP is trying eq
MY-PACKAGE::FOO
and COMMON-LISP::FOO
what will be NIL.
FIX: (intern "FOO" :my-package)
must do the trick.
Note: the "name"
argument in the function "intern"
will be NAME as the name of the symbol, including case.
source to share