~ubuntu-branches/ubuntu/trusty/cl-asdf/trusty

« back to all changes in this revision

Viewing changes to defsystem.lisp

  • Committer: Package Import Robot
  • Author(s): Francois-Rene Rideau
  • Date: 2013-05-27 22:44:50 UTC
  • mfrom: (1.1.28)
  • Revision ID: package-import@ubuntu.com-20130527224450-4bddztgqi7q1uzn7
Tags: 2:3.0.1.2-1
ASDF 3.0.1.2 fixes issues with the debian package itself.
It also includes fixes to run-program and run-shell-command.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
;;;; -------------------------------------------------------------------------
 
2
;;;; Defsystem
 
3
 
 
4
(asdf/package:define-package :asdf/defsystem
 
5
  (:recycle :asdf/defsystem :asdf)
 
6
  (:use :asdf/common-lisp :asdf/driver :asdf/upgrade
 
7
   :asdf/component :asdf/system :asdf/cache
 
8
   :asdf/find-system :asdf/find-component :asdf/lisp-action :asdf/operate
 
9
   :asdf/backward-internals)
 
10
  (:export
 
11
   #:defsystem #:register-system-definition
 
12
   #:class-for-type #:*default-component-class*
 
13
   #:determine-system-directory #:parse-component-form
 
14
   #:duplicate-names #:non-toplevel-system #:non-system-system
 
15
   #:sysdef-error-component #:check-component-input))
 
16
(in-package :asdf/defsystem)
 
17
 
 
18
;;; Pathname
 
19
(with-upgradability ()
 
20
  (defun determine-system-directory (pathname)
 
21
    ;; The defsystem macro calls this function to determine
 
22
    ;; the pathname of a system as follows:
 
23
    ;; 1. if the pathname argument is an pathname object (NOT a namestring),
 
24
    ;;    that is already an absolute pathname, return it.
 
25
    ;; 2. otherwise, the directory containing the LOAD-PATHNAME
 
26
    ;;    is considered (as deduced from e.g. *LOAD-PATHNAME*), and
 
27
    ;;    if it is indeed available and an absolute pathname, then
 
28
    ;;    the PATHNAME argument is normalized to a relative pathname
 
29
    ;;    as per PARSE-UNIX-NAMESTRING (with ENSURE-DIRECTORY T)
 
30
    ;;    and merged into that DIRECTORY as per SUBPATHNAME.
 
31
    ;;    Note: avoid *COMPILE-FILE-PATHNAME* because .asd is loaded,
 
32
    ;;    and may be from within the EVAL-WHEN of a file compilation.
 
33
    ;; If no absolute pathname was found, we return NIL.
 
34
    (check-type pathname (or null string pathname))
 
35
    (pathname-directory-pathname
 
36
     (resolve-symlinks*
 
37
      (ensure-absolute-pathname
 
38
       (parse-unix-namestring pathname :type :directory)
 
39
       #'(lambda () (ensure-absolute-pathname
 
40
                     (load-pathname) 'get-pathname-defaults nil))
 
41
       nil)))))
 
42
 
 
43
 
 
44
;;; Component class
 
45
(with-upgradability ()
 
46
  (defvar *default-component-class* 'cl-source-file)
 
47
 
 
48
  (defun class-for-type (parent type)
 
49
    (or (loop :for symbol :in (list
 
50
                               type
 
51
                               (find-symbol* type *package* nil)
 
52
                               (find-symbol* type :asdf/interface nil)
 
53
                               (and (stringp type) (safe-read-from-string type :package :asdf/interface)))
 
54
              :for class = (and symbol (symbolp symbol) (find-class* symbol nil))
 
55
              :when (and class
 
56
                         (#-cormanlisp subtypep #+cormanlisp cl::subclassp
 
57
                          class (find-class* 'component)))
 
58
                :return class)
 
59
        (and (eq type :file)
 
60
             (find-class*
 
61
              (or (loop :for p = parent :then (component-parent p) :while p
 
62
                        :thereis (module-default-component-class p))
 
63
                  *default-component-class*) nil))
 
64
        (sysdef-error "don't recognize component type ~A" type))))
 
65
 
 
66
 
 
67
;;; Check inputs
 
68
(with-upgradability ()
 
69
  (define-condition duplicate-names (system-definition-error)
 
70
    ((name :initarg :name :reader duplicate-names-name))
 
71
    (:report (lambda (c s)
 
72
               (format s (compatfmt "~@<Error while defining system: multiple components are given same name ~S~@:>")
 
73
                       (duplicate-names-name c)))))
 
74
 
 
75
  (define-condition non-system-system (system-definition-error)
 
76
    ((name :initarg :name :reader non-system-system-name)
 
77
     (class-name :initarg :class-name :reader non-system-system-class-name))
 
78
    (:report (lambda (c s)
 
79
               (format s (compatfmt "~@<Error while defining system ~S: class ~S isn't a subclass of ~S~@:>")
 
80
                       (non-system-system-name c) (non-system-system-class-name c) 'system))))
 
81
 
 
82
  (define-condition non-toplevel-system (system-definition-error)
 
83
    ((parent :initarg :parent :reader non-toplevel-system-parent)
 
84
     (name :initarg :name :reader non-toplevel-system-name))
 
85
    (:report (lambda (c s)
 
86
               (format s (compatfmt "~@<Error while defining system: component ~S claims to have a system ~S as a child~@:>")
 
87
                       (non-toplevel-system-parent c) (non-toplevel-system-name c)))))
 
88
 
 
89
  (defun sysdef-error-component (msg type name value)
 
90
    (sysdef-error (strcat msg (compatfmt "~&~@<The value specified for ~(~A~) ~A is ~S~@:>"))
 
91
                  type name value))
 
92
 
 
93
  (defun check-component-input (type name weakly-depends-on
 
94
                                depends-on components)
 
95
    "A partial test of the values of a component."
 
96
    (unless (listp depends-on)
 
97
      (sysdef-error-component ":depends-on must be a list."
 
98
                              type name depends-on))
 
99
    (unless (listp weakly-depends-on)
 
100
      (sysdef-error-component ":weakly-depends-on must be a list."
 
101
                              type name weakly-depends-on))
 
102
    (unless (listp components)
 
103
      (sysdef-error-component ":components must be NIL or a list of components."
 
104
                              type name components)))
 
105
 
 
106
  (defun* (normalize-version) (form &key pathname component parent)
 
107
    (labels ((invalid (&optional (continuation "using NIL instead"))
 
108
               (warn (compatfmt "~@<Invalid :version specifier ~S~@[ for component ~S~]~@[ in ~S~]~@[ from file ~S~]~@[, ~A~]~@:>")
 
109
                     form component parent pathname continuation))
 
110
             (invalid-parse (control &rest args)
 
111
               (unless (builtin-system-p (find-component parent component))
 
112
                 (apply 'warn control args)
 
113
                 (invalid))))
 
114
      (if-let (v (typecase form
 
115
                   ((or string null) form)
 
116
                   (real
 
117
                    (invalid "Substituting a string")
 
118
                    (format nil "~D" form)) ;; 1.0 becomes "1.0"
 
119
                   (cons
 
120
                    (case (first form)
 
121
                      ((:read-file-form)
 
122
                       (destructuring-bind (subpath &key (at 0)) (rest form)
 
123
                         (safe-read-file-form (subpathname pathname subpath) :at at :package :asdf-user)))
 
124
                      ((:read-file-line)
 
125
                       (destructuring-bind (subpath &key (at 0)) (rest form)
 
126
                         (read-file-lines (subpathname pathname subpath) :at at)))
 
127
                      (otherwise
 
128
                       (invalid))))
 
129
                   (t
 
130
                    (invalid))))
 
131
        (if-let (pv (parse-version v #'invalid-parse))
 
132
          (unparse-version pv)
 
133
          (invalid))))))
 
134
 
 
135
 
 
136
;;; Main parsing function
 
137
(with-upgradability ()
 
138
  (defun* (parse-component-form) (parent options &key previous-serial-component)
 
139
    (destructuring-bind
 
140
        (type name &rest rest &key
 
141
                                (builtin-system-p () bspp)
 
142
                                ;; the following list of keywords is reproduced below in the
 
143
                                ;; remove-plist-keys form.  important to keep them in sync
 
144
                                components pathname perform explain output-files operation-done-p
 
145
                                weakly-depends-on depends-on serial
 
146
                                do-first if-component-dep-fails version
 
147
                                ;; list ends
 
148
         &allow-other-keys) options
 
149
      (declare (ignorable perform explain output-files operation-done-p builtin-system-p))
 
150
      (check-component-input type name weakly-depends-on depends-on components)
 
151
      (when (and parent
 
152
                 (find-component parent name)
 
153
                 (not ;; ignore the same object when rereading the defsystem
 
154
                  (typep (find-component parent name)
 
155
                         (class-for-type parent type))))
 
156
        (error 'duplicate-names :name name))
 
157
      (when do-first (error "DO-FIRST is not supported anymore as of ASDF 3"))
 
158
      (let* ((name (coerce-name name))
 
159
             (args `(:name ,name
 
160
                     :pathname ,pathname
 
161
                     ,@(when parent `(:parent ,parent))
 
162
                     ,@(remove-plist-keys
 
163
                        '(:components :pathname :if-component-dep-fails :version
 
164
                          :perform :explain :output-files :operation-done-p
 
165
                          :weakly-depends-on :depends-on :serial)
 
166
                        rest)))
 
167
             (component (find-component parent name))
 
168
             (class (class-for-type parent type)))
 
169
        (when (and parent (subtypep class 'system))
 
170
          (error 'non-toplevel-system :parent parent :name name))
 
171
        (if component ; preserve identity
 
172
            (apply 'reinitialize-instance component args)
 
173
            (setf component (apply 'make-instance class args)))
 
174
        (component-pathname component) ; eagerly compute the absolute pathname
 
175
        (let ((sysfile (system-source-file (component-system component)))) ;; requires the previous
 
176
          (when (and (typep component 'system) (not bspp))
 
177
            (setf (builtin-system-p component) (lisp-implementation-pathname-p sysfile)))
 
178
          (setf version (normalize-version version :component name :parent parent :pathname sysfile)))
 
179
        ;; Don't use the accessor: kluge to avoid upgrade issue on CCL 1.8.
 
180
        ;; A better fix is required.
 
181
        (setf (slot-value component 'version) version)
 
182
        (when (typep component 'parent-component)
 
183
          (setf (component-children component)
 
184
                (loop
 
185
                  :with previous-component = nil
 
186
                  :for c-form :in components
 
187
                  :for c = (parse-component-form component c-form
 
188
                                                 :previous-serial-component previous-component)
 
189
                  :for name = (component-name c)
 
190
                  :collect c
 
191
                  :when serial :do (setf previous-component name)))
 
192
          (compute-children-by-name component))
 
193
        (when previous-serial-component
 
194
          (push previous-serial-component depends-on))
 
195
        (when weakly-depends-on
 
196
          ;; ASDF4: deprecate this feature and remove it.
 
197
          (appendf depends-on
 
198
                   (remove-if (complement #'(lambda (x) (find-system x nil))) weakly-depends-on)))
 
199
        ;; Used by POIU. ASDF4: rename to component-depends-on?
 
200
        (setf (component-sideway-dependencies component) depends-on)
 
201
        (%refresh-component-inline-methods component rest)
 
202
        (when if-component-dep-fails
 
203
          (%resolve-if-component-dep-fails if-component-dep-fails component))
 
204
        component)))
 
205
 
 
206
  (defun register-system-definition
 
207
      (name &rest options &key pathname (class 'system) (source-file () sfp)
 
208
                            defsystem-depends-on &allow-other-keys)
 
209
    ;; The system must be registered before we parse the body,
 
210
    ;; otherwise we recur when trying to find an existing system
 
211
    ;; of the same name to reuse options (e.g. pathname) from.
 
212
    ;; To avoid infinite recursion in cases where you defsystem a system
 
213
    ;; that is registered to a different location to find-system,
 
214
    ;; we also need to remember it in a special variable *systems-being-defined*.
 
215
    (with-system-definitions ()
 
216
      (let* ((name (coerce-name name))
 
217
             (source-file (if sfp source-file (resolve-symlinks* (load-pathname))))
 
218
             (registered (system-registered-p name))
 
219
             (registered! (if registered
 
220
                              (rplaca registered (get-file-stamp source-file))
 
221
                              (register-system
 
222
                               (make-instance 'system :name name :source-file source-file))))
 
223
             (system (reset-system (cdr registered!)
 
224
                                   :name name :source-file source-file))
 
225
             (component-options (remove-plist-key :class options))
 
226
             (defsystem-dependencies (loop :for spec :in defsystem-depends-on :collect
 
227
                                           (resolve-dependency-spec nil spec))))
 
228
        (setf (gethash name *systems-being-defined*) system)
 
229
        (apply 'load-systems defsystem-dependencies)
 
230
        ;; We change-class AFTER we loaded the defsystem-depends-on
 
231
        ;; since the class might be defined as part of those.
 
232
        (let ((class (class-for-type nil class)))
 
233
          (unless (subtypep class 'system)
 
234
            (error 'non-system-system :name name :class-name (class-name class)))
 
235
          (unless (eq (type-of system) class)
 
236
            (change-class system class)))
 
237
        (parse-component-form
 
238
         nil (list*
 
239
              :module name
 
240
              :pathname (determine-system-directory pathname)
 
241
              component-options)))))
 
242
 
 
243
  (defmacro defsystem (name &body options)
 
244
    `(apply 'register-system-definition ',name ',options)))