Can';t使用系统中定义的lisp包

Can';t使用系统中定义的lisp包,lisp,common-lisp,sbcl,quicklisp,asdf,Lisp,Common Lisp,Sbcl,Quicklisp,Asdf,我试图使用lisp代码生成可执行文件。但是我根本无法编译lisp文件,因为在加载helloworld系统之前没有helloworld包 ;; test.lisp (asdf:load-system :helloworld) (defun main() (helloworld:start)) 当然,我制作了helloworld系统并将其放入~/quicklisp/localprojects/中helloworld系统已成功加载,无错误。 我想编译test.lisp而不显式加载。我还尝

我试图使用lisp代码生成可执行文件。但是我根本无法编译lisp文件,因为在加载
helloworld
系统之前没有
helloworld

;; test.lisp
(asdf:load-system :helloworld)

(defun main()
  (helloworld:start))

当然,我制作了
helloworld
系统并将其放入
~/quicklisp/localprojects/
中<代码>helloworld系统已成功加载,无错误。


我想编译
test.lisp
而不显式加载。我还尝试了
use package
defpackage
,但失败了

;; test.lisp
(asdf:load-system :helloworld)
(use-package :helloworld)

(defun main()
  (helloworld:start))


;; test.lisp
(asdf:load-system :helloworld)

(defpackage :test
  (:use :cl :asdf)
  (:export :main))

(in-package :test)

(defun main()
  (helloworld:start))

如何使用
helloworld
系统中定义的
helloworld
包而不加载它?
我是否必须使用
helloworld
system创建一个新系统

在这段代码中,发生了一些有趣的事情:

您无法将其作为一个整体进行编译,因为正如您所指出的,尝试读取符号
helloworld:start
是一个问题,因为还没有helloworld包。要读取符号,至少需要定义包。但是,我们为什么不在
(asdf:load system:helloworld)
中遇到同样的问题呢?简单地说,ASDF包已经被定义(要么实现包含它,要么您已经加载了它,或者其他一些东西)。那么,您可以做的一件事就是在编译时确保您已经加载了helloworld系统:

;; test.lisp
(eval-when (:compile-toplevel)
  (asdf:load-system :helloworld))

(defun main()
  (helloworld:start))
这应该允许您编译文件;因为您将在编译时评估加载表单,然后在您定义
main
时定义包

当然,现在您将拥有一个已编译的文件,但是如果您将其加载到一个新的Lisp实例中,而helloworld系统尚未加载,那么会发生什么呢?您将遇到一个问题。因此,您确实希望在加载该文件时加载该系统,并且可能只是从该文件执行表单(例如,如果您一次阅读一个表单并对其进行评估),那么您可能希望在另外两个上下文中评估加载系统:

;; test.lisp
(eval-when (:compile-toplevel :load-toplevel :execute)
  (asdf:load-system :helloworld))

(defun main()
  (helloworld:start))

这一切,一定要考虑在这种情况下,这是否是最合适的加载系统的方法。如果出于某种原因,您试图将所有代码保存在一个文件中,或者生成一个传递脚本,这可能是有意义的。如果另一方面,您正在制作另一个ASDF可加载系统,那么您可能只包含HeloWord作为阿德。pendency并让ASDF处理加载依赖项。

如果您想编译二进制文件,可以使用一个简单的Lisp脚本,例如(假设为SBCL)

生成文件:

all:
    sbcl --load build.lisp
加载文件时,Lisp会执行其表单,因此当它到达
save Lisp and die
时,它已经知道
helloworld

还有专门用于制作可执行文件的工具,buildapp和cl launch。后者可以生成可执行脚本并使用保存的内核

UPD

是的,以这种方式构建的可执行文件将包含整个Lisp,因此1)它将是巨大的;2)有两个或更多这样的可执行文件意味着您拥有整个Lisp的副本(可能是多余的)

另一个实现可以生成更小的二进制文件,例如。GCLISP;他们说商业的更好

对于Lisp较少的目标计算机,这是唯一可能的解决方案。相反,如果目标计算机具有Lisp编译器,则还有两个其他选项:脚本和保存的核心

您可以创建一个调用
sbcl--load
的shell脚本,或者使用cl-launch获得一个复杂的shell包装器,它可以根据您的需要进行移植。SBCL和CLISP也支持shebang


然而,如果启动时间很重要,加载库将是一个瓶颈,即使它们只编译一次。在这种情况下,您可以使用自定义核心或图像来解决此问题。core可以被认为是Lisp世界的保存状态,保存core是
sb ext:save Lisp and die
及其对应程序的主要任务。加载内核很快,您可以立即在其中编译所有库。但是,它的大小也变得相当大,尽管没有独立可执行文件那么大。当然,一个内核可以用于多个应用程序。Cl launch也可以与内核一起工作;特别是,它允许方便地定义输入函数。

1-要获得既可编译又可加载的文件,请在需要时使用eval。见我的文章

2-我建议使用cl launch:

cl发布-sp helloworld-r启动-o helloworld-d


3-如果您不想在空间上浪费60MB,而是可以承受半秒到几秒的启动延迟,请使用#/usr/bin/cl脚本。

(ql:quickload'helloworld)工作正常吗?你犯了什么错误?这个问题重复了一次。但是在哪里?谢谢。但我还有一个问题。从代码生成的可执行文件似乎包含
REPL
。我指的是lisp解释器、环境和其他东西。大约~54MB。我应该在制作可执行文件时构建大文件吗?
;; test.lisp
(eval-when (:compile-toplevel :load-toplevel :execute)
  (asdf:load-system :helloworld))

(defun main()
  (helloworld:start))
;;;; build.lisp
(require "asdf")
(asdf:operate 'asdf:load-op "helloworld")
(sb-ext:save-lisp-and-die "helloworld"
                          :toplevel helloworld:start
                          :executable t)
all:
    sbcl --load build.lisp