Previous: , Up: Defining systems with defsystem   [Contents][Index]


6.5 The package-inferred-system extension

Starting with release 3.1.2, ASDF supports a one-package-per-file style of programming, whereby each file is its own system, and dependencies are deduced from the defpackage form (or its variant uiop:define-package).

In this style, packages refer to a system with the same name (downcased); and if a system is defined with :class package-inferred-system, then system names that start with that name (using the slash / separator) refer to files under the filesystem hierarchy where the system is defined. For instance, if system my-lib is defined in /foo/bar/my-lib/my-lib.asd, then system my-lib/src/utility will be found in file /foo/bar/my-lib/src/utility.lisp.

This style was made popular by faslpath and quick-build before, and at the cost of a stricter package discipline, seems to make for more maintainable code. It is used by ASDF itself (starting with ASDF 3) and by lisp-interface-library.

To use this style, choose a toplevel system name, e.g. my-lib, and create a file my-lib.asd with the :class :package-inferred-system option in its defsystem. For instance:

#-asdf3 (error "my-lib requires ASDF 3")
(defsystem my-lib
  :class :package-inferred-system
  :defsystem-depends-on (:asdf-package-system)
  :depends-on (:my-lib/interface/all
               :my-lib/src/all
               :my-lib/extras/all)
  :in-order-to ((test-op (load-op :my-lib/test/all)))
  :perform (test-op (o c) (symbol-call :my-lib/test/all :test-suite)))

(defsystem :my-lib/test :depends-on (:my-lib/test/all))

(register-system-packages :my-lib/interface/all '(:my-lib-interface))
(register-system-packages :my-lib/src/all '(:my-lib-implementation))
(register-system-packages :my-lib/test/all '(:my-lib-test))

(register-system-packages
 :closer-mop
 '(:c2mop :closer-common-lisp :c2cl :closer-common-lisp-user :c2cl-user))

In the code above, the :defsystem-depends-on (:asdf-package-system) is for compatibility with older versions of ASDF 3 (ASDF 2 is not supported), and requires the asdf-package-system library to be present (it is implicitly provided by ASDF starting with release 3.1.2, which can be detected with the feature :asdf3.1).

The function register-system-packages has to be called to register packages used or provided by your system and its components where the name of the system that provides the package is not the downcase of the package name.

Then, file interface/order.lisp under the lil hierarchy, that defines abstract interfaces for order comparisons, starts with the following form, dependencies being trivially computed from the :use and :mix clauses:

(uiop:define-package :lil/interface/order
  (:use :closer-common-lisp
   :lil/interface/definition
   :lil/interface/base
   :lil/interface/eq :lil/interface/group)
  (:mix :fare-utils :uiop :alexandria)
  (:export ...))

ASDF can tell that this file depends on system closer-mop (registered above), lil/interface/definition, lil/interface/base, lil/interface/eq, and lil/interface/group (package and system names match, and they will be looked up hierarchically).

ASDF also detects dependencies from :import-from clauses. You may thus import a well-defined set of symbols from an existing package as loaded from suitably named system; or if you prefer to use any such symbol fully qualified by a package prefix, you may declare a dependency on such a package and its corresponding system via an :import-from clause with an empty list of symbols, as in:

(defpackage :foo/bar
  (:use :cl)
  (:import-from :foo/baz #:sym1 #:sym2)
  (:import-from :foo/quux)
  (:export ...))

The form uiop:define-package is supported as well as defpackage, and has many options that prove useful in this context, such as :use-reexport and :mix-reexport that allow for “inheritance” of symbols being exported.


Previous: , Up: Defining systems with defsystem   [Contents][Index]