如何让defsystem使用"一切"?

Ste*_*edl 5 common-lisp asdf

我正在研究SBCL中的项目euler问题,并为每个解决方案保留一个简短的文件.每个问题都有一些基于5 am的测试,这些测试是从"主要"测试套件中引用的.运行"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+))))
Run Code Online (Sandbox Code Playgroud)

简而言之,defsystem euler使用所有e ????.lisp文件作为组件,tests.lisp依赖于所有这些文件.

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

我觉得我失去了一些东西基本在这里,尤其是阅读一些后ELS在github幻灯片关于"更具声明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")))))
Run Code Online (Sandbox Code Playgroud)

感谢您的反馈.

Far*_*aré 6

对于目录部分,我建议使用相对路径名.你可以用几种方法做到这一点.

1-你不能使用绝对路径名.像这样使用相对路径名,可能通过变量:(subpathname (current-file-pathname) #p"e????.lisp")

2-我不确定它?是否具有通配符的可移植性- 如果你可以忍受它,*便携性更强.

3- uiop:在这个和许多上下文中,目录文件比cl:目录更安全.

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")))))
Run Code Online (Sandbox Code Playgroud)

6-您可以使用辅助系统代替模块,此时system-relative-pathname可以使用:

(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")))
Run Code Online (Sandbox Code Playgroud)

7-在上面我假设asdf3,你使用uiop没有前缀:

(defpackage :euler-system (:use :cl :uiop :asdf))
(in-package :euler-system)
Run Code Online (Sandbox Code Playgroud)

如果您没有定义任何函数或变量或类,您可以直接 (in-package :asdf)

我很高兴你喜欢我在ELS 2013上的演讲.我在ELS 2014上又在同一个存储库中给了另一个.