Common lisp 如何使用除霜系统;一切;?
我正在处理SBCL中的euler项目问题,并为每个解决方案保存一个简短的文件。每个问题都有一些基于上午5点的测试,这些测试是从“主”测试套件中引用的。这些测试在运行“tests.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
(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,就在我的计划中:-)