4

我有一台开发机器和一台生产机器,它们是相同的(vm 映像的副本)。我想将应用程序与 asd 文件一起交付到生产机器,但我不想交付源代码。我想到了两种方法:

1.通过只提供生产机器中的 FASL 文件让 asdf 加载系统

优点:当我需要更改某些内容时,我只需在开发机器中编译文件并替换生产机器中的 fasl。

缺点:我不知道是否以及如何做到这一点。

2.使用 save-lisp-and-die,或者更喜欢Zachary Beane 的 builapp 工具(我正在使用 SBCL)来自动化这个过程。

优点:更容易自动化、更简洁,并且只需一个(虽然很大)文件交付。

缺点:先前解决方案的优点。

我知道我提到的那些利弊与彼此相比并不那么重要,但我想知道我没有看到的任何利弊可能会改变我的选择,或者我没有想到的任何其他解决方案。此外,无论我选择什么,我都想知道解决方案 1 是否可行以及如何。

4

4 回答 4

4

通常,这些系统工具应该允许这样做。您所需要的只是系统描述和 FASL 文件。然后系统工具应使用 FASL 文件进行加载。只需要确保它对某些源文件没有硬依赖。

这种方式软件已经在 Lisp 世界中交付了数十年(> 30 年)。这种方法没有错。如果某个特定工具(此处为 ASDF,但还有其他工具)存在问题,则应向作者投诉。

如果您对此有实际问题,您应该在 ASDF 邮件列表上讨论它或在此处发布问题。你有实际问题吗?

这不会直接帮助您,但它可能会为您提供一些系统工具通常如何工作的提示。

LispWorks 6 及其自己的 DEFSYSTEM 示例

我们在 FOO 目录中有三个文件:

RJMBA:foo joswig$ ls -l
-rw-r--r--  1 joswig  admin    13 22 Jul 20:42 a.lisp
-rw-r--r--  1 joswig  admin    14 22 Jul 20:42 b.lisp
-rw-r--r--  1 joswig  admin   331 22 Jul 20:41 system.lisp

system.lisp 包含以下系统描述:

(defvar *foo-directory*
   (make-pathname :name nil
                  :type nil
                  :directory (pathname-directory *load-pathname*)
                  :defaults *load-pathname*))

(defsystem foo (:default-pathname *foo-directory*)
   :members ("a" "b"))

上面*foo-directory*根据加载文件的路径名设置路径名。因此我们可以设置一个真正的绝对路径名,但不必手动指定它。或者,我们可以使用相对路径名——这取决于一个人想要使用什么。我选择这个来展示如何自动设置绝对路径名。

现在我将此文件加载到 LispWorks 中,然后编译系统:

CL-USER 12 > (compile-system 'foo)

;;; Compiling file /Lisp/foo/a.lisp ...
;;; Safety = 3, Speed = 1, Space = 1, Float = 1, Interruptible = 1
;;; Compilation speed = 1, Debug = 2, Fixnum safety = 3
;;; Source level debugging is on
;;; Source file recording is  on
;;; Cross referencing is on
; (TOP-LEVEL-FORM 0)
; (TOP-LEVEL-FORM 1)
;; Processing Cross Reference Information
;;; Compiling file /Lisp/foo/b.lisp ...
;;; Safety = 3, Speed = 1, Space = 1, Float = 1, Interruptible = 1
;;; Compilation speed = 1, Debug = 2, Fixnum safety = 3
;;; Source level debugging is on
;;; Source file recording is  on
;;; Cross referencing is on
; (TOP-LEVEL-FORM 0)
; (TOP-LEVEL-FORM 1)
;; Processing Cross Reference Information
(FOO)

我们创建了两个 fasl 文件。

现在我将 system.lisp 文件和 fasl 文件复制到一个新目录中:

RJMBA:Lisp joswig$ mkdir bar
RJMBA:Lisp joswig$ cp foo/system.lisp bar/system.lisp
RJMBA:Lisp joswig$ cp foo/a.64xfasl bar/a.64xfasl
RJMBA:Lisp joswig$ cp foo/b.64xfasl bar/b.64xfasl

现在我将在b目录中启动一个新的 LispWorks,加载 system.lisp 文件,然后加载系统:

RJMBA:Lisp joswig$ cd bar
RJMBA:bar joswig$ lispworks
LispWorks(R): The Common Lisp Programming Environment
Copyright (C) 1987-2009 LispWorks Ltd.  All rights reserved.
Version 6.0.0
User joswig on RJMBA.local
...
CL-USER 1 > (load "system.lisp")
; Loading text file /Lisp/bar/system.lisp
;; Creating system "FOO"
#P"/Lisp/bar/system.lisp"

CL-USER 2 > (load-system 'foo)

; Loading fasl file /Lisp/bar/a.64xfasl

"a" ; whatever the file does

; Loading fasl file /Lisp/bar/b.64xfasl

"b" ; whatever the file does

(FOO)

完成并工作。

此外,这可以通过相对目录或所谓的逻辑路径名来完成。逻辑路径名具有从某个路径名到物理路径名的映射,因此可以使用独立于系统的路径名——独立于体系结构、操作系统和目录结构。这为特定部署方案提供了额外的独立性。

于 2011-07-22T10:38:16.513 回答
4

我目前维护 ASDF。我不知道 ASDF 允许这样做。我不是为此而设计的。也就是说,我从来没有尝试过,也不能发誓它不会,或者一个简单的黑客不会让你这样做。我会欢迎这样的入侵 ASDF 和/或扩展。

在最坏的情况下,如果 ASDF 不允许您这样做,那么“简单”的 hack 将是创建包含 (eval-when (:compile-toplevel :load-toplevel :execute) (error "This is not the real source file")) 并给他们一个时间戳 1970-01-01 代替您的源文件。脚本可以为您做到这一点,并且巧妙地破解您的源注册表可以让您在真实源代码和假源代码之间切换。

祝你好运。

于 2011-07-22T10:49:57.970 回答
1

Faré 是对的 --- ASDF 中的逻辑使 aload-op依赖于 a compile-op,它会compile-op通过尝试将 fasl 上的文件写入日期与 .lisp 上的文件写入日期进行比较来检查是否有必要文件。

相信您应该能够通过定义 cl-source-file 的子类来完成这项工作,例如fasl-only,然后覆盖该operation-done-p方法fasl-onlycompile-op使其始终返回t

设置你的 defsystem 可能是最方便的,:default-component-class这样fasl-only你的 defsystem 就可以列出:file组件了。

重写on和return方法也可能是谨慎的,但我不确定这是必要的。input-filescompile-opfasl-onlynil

于 2011-07-26T03:29:38.637 回答
1

截至 2013 年 2 月,ASDF 3 现在提供了一种使用 FASL-OP 和 PRECOMPILED-SYSTEM 完全按照您的意愿行事的方法。

于 2013-02-20T07:10:15.613 回答