Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Common lisp 如何使用除霜系统;一切;?_Common Lisp_Asdf - Fatal编程技术网

Common lisp 如何使用除霜系统;一切;?

Common lisp 如何使用除霜系统;一切;?,common-lisp,asdf,Common Lisp,Asdf,我正在处理SBCL中的euler项目问题,并为每个解决方案保存一个简短的文件。每个问题都有一些基于上午5点的测试,这些测试是从“主”测试套件中引用的。这些测试在运行“tests.lisp”时运行。因为我厌倦了手工维护文件列表,所以我写了一些代码来帮我完成: (defpackage #:euler/asdf (:use :cl :asdf)) (in-package #:euler/asdf) ;; directory containing the problem files (defpar

我正在处理SBCL中的euler项目问题,并为每个解决方案保存一个简短的文件。每个问题都有一些基于上午5点的测试,这些测试是从“主”测试套件中引用的。这些测试在运行“tests.lisp”时运行。因为我厌倦了手工维护文件列表,所以我写了一些代码来帮我完成:

(defpackage #:euler/asdf
  (:use :cl :asdf))
(in-package #:euler/asdf)

;; directory containing the problem files
(defparameter +dir+ "/home/stefan/quicklisp/local-projects/euler")

;; build file list for package components
(defun files-for-problems (dir)
  (mapcar #'(lambda (p) (list :file (pathname-name p) :depends-on '("package")))
      (directory (concatenate 'string dir "/e????.lisp"))))

;; build dependency list for all tests component
(defun depends-on-problems (dir)
  (mapcar #'pathname-name
      (directory (concatenate 'string dir "/e????.lisp"))))

;; define euler system
(defsystem euler
    :name "euler"
    :author "Stefan Schmiedl"
    :description "Solutions to problems at http://projecteuler.net"
    :depends-on ("iterate" "fiveam" "cl-csv")
    :components #.`((:file "package")
            ,@(files-for-problems +dir+)
         #.`(:file "tests" :depends-on ,(depends-on-problems +dir+))))
简而言之,
defsystem euler
使用所有e???.lisp文件作为组件和测试。lisp依赖于所有这些文件

这是个好主意吗?是否有一种“官方”方法使
defsystem
使用目录中的所有文件或与给定文件名模式匹配的所有文件

我觉得我在这里遗漏了一些基本的东西,尤其是在阅读了一些关于“更具声明性的defsystem”的文章之后,我在上面所做的事情可能会遭到反对


在对Fare的建议进行了一些修改之后,我现在得到了:

;; define private package for defsystem
(defpackage #:euler-system
  (:use :cl :uiop :asdf))
(in-package #:euler-system)


;; define euler system
(defsystem "euler"
  :author "Stefan Schmiedl"
  :description "Solutions to problems at http://projecteuler.net"
  :depends-on ("iterate" "fiveam" "cl-csv")
  :components ((:module "package"
                        :pathname ""
                        :components ((:file "package")))
               (:module "problems"
                        :pathname ""
                        :depends-on ("package")
                        :components #.(mapcar #'(lambda (p) (list :file (pathname-name p)))
                                              (directory-files (pathname-directory-pathname
                                                                (uiop/lisp-build:current-lisp-file-pathname))
                                                               "e*.lisp")))
               (:module "tests"
                        :pathname ""
                        :depends-on ("package" "problems")
                        :components ((:file "tests")))))

感谢您的反馈。

ASDF提供了三种内置组件类型,您仅在系统定义中使用简单的
:文件
组件类型。通常,对于将一些文件分组在一起,会引入单独的模块(这些模块几乎直接转换为不同的目录),但模块仍然需要您指定(子)组件,然后返回到开始的位置。我简单地看了一下是否会有一个ASDF扩展支持您构建的功能,但没有发现任何东西。因此,虽然您的代码可能存在一些小问题(例如通配符语法可能无法跨实现移植),但我认为您的通用方法很好


为了回答你关于这是否是个好主意的第二个问题:看看make的隐式规则,我认为这样做可能会有用。但是,通常情况下,各种文件之间存在依赖关系,一旦需要指定这些文件,基本上就可以重新列出组件及其依赖关系。defsystem的整个思想是能够指定依赖项和所需的序列化。因此,您的用例可能不太常见,这可能解释了为什么您找不到一个易于提供的解决方案。

对于目录部分,我建议使用相对路径名。你可以用几种方法

1-不应使用绝对路径名。像这样使用相对路径名,可能通过变量:
(子路径名(当前文件路径名)#p“e???.lisp”)

2-我不确定
作为通配符的可移植性如何-如果你能接受它,
*
的可移植性要高得多

3-uiop:directory文件在这种和许多上下文中比cl:directory更安全

4-用于处理不带#的通配符模式的“官方”方式。或者(eval`…),从asdf/contrib/wild-modules.lisp获得灵感——也就是说,对于一次性的,#。是完全可以接受的,特别是因为我们远离纯粹的声明性.asd文件

5-对于分组依赖项,可以使用

(defsystem "euler"
  :depends-on ("iterate" "fiveam" "cl-csv")
  :serial t
  :components
   ((:module "package" :pathname ""
       :components ((:file "package")))
    (:module "problems" :pathname "" :depends-on ("package")
       :components #.(mapcar ...))
    (:module "tests" :pathname ""
       :components ((:file "tests")))))
6-您可以使用辅助系统而不是模块,此时
系统相对路径名
将可用:

(defsystem "euler" :depends-on ("euler/tests"))
(defsystem "euler/tests"
  :depends-on ("euler/package")
  :components ((:file "package")))
(defsystem "euler/problems"
  :depends-on ("euler/package")
  :components
    #.(mapcar ... (directory-files (system-relative-pathname "euler" #p"e*.lisp")))))
(defsystem "euler/tests"
  :depends-on ("euler/problems")
  :components ((:file "tests")))
7-在上述情况下,我假设
asdf3
,并且您使用的
uiop
没有前缀:

(defpackage :euler-system (:use :cl :uiop :asdf))
(in-package :euler-system)
如果不定义任何函数、变量或类,可以直接
(在包中:asdf)


我很高兴你喜欢我在ELS 2013的演讲。在ELS 2014上,我在同一个存储库中提供了另一个。

计划是制作一个“库”模块,并使解决方案文件依赖于此。我不认为这个实践项目有必要对依赖关系进行微调。2014年的演讲是我获得回购URL的地方,我观看了你演讲的视频,扩展版非常接近我阅读列表的顶部。感谢您的工作。我将切换到模块(您的#5),因为它消除了代码中的重复。此外,您的#6中的第二个defsystem似乎患有复制性巴氏杆菌炎;-)如果一个模块只有一个文件,实际上它不需要是一个模块——只需使用:文件即可。我的错。此外,如果您已经使用了:ing:uiop,则不需要使用uiop/foo:限定某些内容。最后,由于您没有定义任何函数或变量,您可以(在package:asdf中)而不是创建您自己的package.FWIW,我一般不建议将您的测试放在您的系统中:使用您的Euler系统的人可能希望在不必安装和加载您的测试库的情况下运行它。(我意识到对于project Euler练习,这种担心可能不适用,这就是为什么我说“一般”)对于这种情况,我将添加一个“Euler/test”系统来替换您的模块,并添加一个,为了在Euler上运行测试操作,您需要在Euler/test上运行测试操作。我们有一个FiveAM asdf附加组件,可以更容易地指定此类测试操作。事实上,一旦我遇到问题100,就在我的计划中:-)