Define closeto (again) and use it for the li tests
[maxima.git] / lisp-utils / defsystem.lisp
blob668d88d05b612dd16941d4465c826ce4ba1b136e
1 ;;; -*- Mode: Lisp; Package: make -*-
2 ;;; -*- Mode: CLtL; Syntax: Common-Lisp -*-
4 ;;; DEFSYSTEM 3.4 Interim 3.
6 ;;; defsystem.lisp --
8 ;;; ****************************************************************
9 ;;; MAKE -- A Portable Defsystem Implementation ********************
10 ;;; ****************************************************************
12 ;;; This is a portable system definition facility for Common Lisp.
13 ;;; Though home-grown, the syntax was inspired by fond memories of the
14 ;;; defsystem facility on Symbolics 3600's. The exhaustive lists of
15 ;;; filename extensions for various lisps and the idea to have one
16 ;;; "operate-on-system" function instead of separate "compile-system"
17 ;;; and "load-system" functions were taken from Xerox Corp.'s PCL
18 ;;; system.
20 ;;; This system improves on both PCL and Symbolics defsystem utilities
21 ;;; by performing a topological sort of the graph of file-dependency
22 ;;; constraints. Thus, the components of the system need not be listed
23 ;;; in any special order, because the defsystem command reorganizes them
24 ;;; based on their constraints. It includes all the standard bells and
25 ;;; whistles, such as not recompiling a binary file that is up to date
26 ;;; (unless the user specifies that all files should be recompiled).
28 ;;; Originally written by Mark Kantrowitz, School of Computer Science,
29 ;;; Carnegie Mellon University, October 1989.
31 ;;; MK:DEFSYSTEM 3.4 Interim 3
32 ;;;
33 ;;; Copyright (c) 1989 - 1999 Mark Kantrowitz. All rights reserved.
34 ;;; 1999 - 2004 Mark Kantrowitz and Marco Antoniotti. All
35 ;;; rights reserved.
37 ;;; Use, copying, modification, merging, publishing, distribution
38 ;;; and/or sale of this software, source and/or binary files and
39 ;;; associated documentation files (the "Software") and of derivative
40 ;;; works based upon this Software are permitted, as long as the
41 ;;; following conditions are met:
43 ;;; o this copyright notice is included intact and is prominently
44 ;;; visible in the Software
45 ;;; o if modifications have been made to the source code of the
46 ;;; this package that have not been adopted for inclusion in the
47 ;;; official version of the Software as maintained by the Copyright
48 ;;; holders, then the modified package MUST CLEARLY identify that
49 ;;; such package is a non-standard and non-official version of
50 ;;; the Software. Furthermore, it is strongly encouraged that any
51 ;;; modifications made to the Software be sent via e-mail to the
52 ;;; MK-DEFSYSTEM maintainers for consideration of inclusion in the
53 ;;; official MK-DEFSYSTEM package.
55 ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
56 ;;; EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
57 ;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
58 ;;; IN NO EVENT SHALL M. KANTROWITZ AND M. ANTONIOTTI BE LIABLE FOR ANY
59 ;;; CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
60 ;;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
61 ;;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
63 ;;; Except as contained in this notice, the names of M. Kantrowitz and
64 ;;; M. Antoniotti shall not be used in advertising or otherwise to promote
65 ;;; the sale, use or other dealings in this Software without prior written
66 ;;; authorization from M. Kantrowitz and M. Antoniotti.
69 ;;; Please send bug reports, comments and suggestions to <marcoxa@cons.org>.
71 ;;; ********************************
72 ;;; Change Log *********************
73 ;;; ********************************
74 ;;;
75 ;;; Note: Several of the fixes from 30-JAN-91 and 31-JAN-91 were done in
76 ;;; September and October 1990, but not documented until January 1991.
77 ;;;
78 ;;; akd = Abdel Kader Diagne <diagne@dfki.uni-sb.de>
79 ;;; as = Andreas Stolcke <stolcke@ICSI.Berkeley.EDU>
80 ;;; bha = Brian Anderson <bha@atc.boeing.com>
81 ;;; brad = Brad Miller <miller@cs.rochester.edu>
82 ;;; bw = Robert Wilhelm <wilhelm@rpal.rockwell.com>
83 ;;; djc = Daniel J. Clancy <clancy@cs.utexas.edu>
84 ;;; fdmm = Fernando D. Mato Mira <matomira@di.epfl.ch>
85 ;;; gc = Guillaume Cartier <cartier@math.uqam.ca>
86 ;;; gi = Gabriel Inaebnit <inaebnit@research.abb.ch>
87 ;;; gpw = George Williams <george@hsvaic.boeing.com>
88 ;;; hkt = Rick Taube <hkt@cm-next-8.stanford.edu>
89 ;;; ik = Ik Su Yoo <ik@ctt.bellcore.com>
90 ;;; jk = John_Kolojejchick@MORK.CIMDS.RI.CMU.EDU
91 ;;; kt = Kevin Thompson <kthompso@ptolemy.arc.nasa.gov>
92 ;;; kc = Kaelin Colclasure <kaelin@bridge.com>
93 ;;; kmr = Kevin M. Rosenberg <kevin@rosenberg.net>
94 ;;; lmh = Liam M. Healy <Liam.Healy@nrl.navy.mil>
95 ;;; mc = Matthew Cornell <cornell@unix1.cs.umass.edu>
96 ;;; oc = Oliver Christ <oli@adler.ims.uni-stuttgart.de>
97 ;;; rs = Ralph P. Sobek <ralph@vega.laas.fr>
98 ;;; rs2 = Richard Segal <segal@cs.washington.edu>
99 ;;; sb = Sean Boisen <sboisen@bbn.com>
100 ;;; ss = Steve Strassman <straz@cambridge.apple.com>
101 ;;; tar = Thomas A. Russ <tar@isi.edu>
102 ;;; toni = Anton Beschta <toni%l4@ztivax.siemens.com>
103 ;;; yc = Yang Chen <yangchen%iris.usc.edu@usc.edu>
105 ;;; Thanks to Steve Strassmann <straz@media-lab.media.mit.edu> and
106 ;;; Sean Boisen <sboisen@BBN.COM> for detailed bug reports and
107 ;;; miscellaneous assistance. Thanks also to Gabriel Inaebnit
108 ;;; <inaebnit@research.abb.ch> for help with VAXLisp bugs.
110 ;;; 05-NOV-90 hkt Changed canonicalize-system-name to make system
111 ;;; names package independent. Interns them in the
112 ;;; keyword package. Thus either strings or symbols may
113 ;;; be used to name systems from the user's point of view.
114 ;;; 05-NOV-90 hkt Added definition FIND-SYSTEM to allow OOS to
115 ;;; work on systems whose definition hasn't been loaded yet.
116 ;;; 05-NOV-90 hkt Added definitions COMPILE-SYSTEM and LOAD-SYSTEM
117 ;;; as alternates to OOS for naive users.
118 ;;; 05-NOV-90 hkt Shadowing-import of 'defsystem in Allegro CL 3.1 [NeXT]
119 ;;; into USER package instead of import.
120 ;;; 15-NOV-90 mk Changed package name to "MAKE", eliminating "DEFSYSTEM"
121 ;;; to avoid conflicts with allegro, symbolics packages
122 ;;; named "DEFSYSTEM".
123 ;;; 30-JAN-91 mk Modified append-directories to work with the
124 ;;; logical-pathnames system.
125 ;;; 30-JAN-91 mk Append-directories now works with Sun CL4.0. Also, fixed
126 ;;; bug wrt Lucid 4.0's pathnames (which changed from lcl3.0
127 ;;; -- 4.0 uses a list for the directory slot, whereas
128 ;;; 3.0 required a string). Possible fix to symbolics bug.
129 ;;; 30-JAN-91 mk Defined NEW-REQUIRE to make redefinition of REQUIRE
130 ;;; cleaner. Replaced all calls to REQUIRE in this file with
131 ;;; calls to NEW-REQUIRE, which should avoid compiler warnings.
132 ;;; 30-JAN-91 mk In VAXLisp, when we redefine lisp:require, the compiler
133 ;;; no longer automatically executes require forms when it
134 ;;; encounters them in a file. The user can always wrap an
135 ;;; (eval-when (compile load eval) ...) around the require
136 ;;; form. Alternately, see commented out code near the
137 ;;; redefinition of lisp:require which redefines it as a
138 ;;; macro instead.
139 ;;; 30-JAN-91 mk Added parameter :version to operate-on-system. If it is
140 ;;; a number, that number is used as part of the binary
141 ;;; directory name as the place to store and load files.
142 ;;; If NIL (the default), uses regular binary directory.
143 ;;; If T, tries to find the most recent version of the
144 ;;; binary directory.
145 ;;; 30-JAN-91 mk Added global variable *use-timeouts* (default: t), which
146 ;;; specifies whether timeouts should be used in
147 ;;; Y-OR-N-P-WAIT. This is provided for users whose lisps
148 ;;; don't handle read-char-no-hang properly, so that they
149 ;;; can set it to NIL to disable the timeouts. Usually the
150 ;;; reason for this is the lisp is run on top of UNIX,
151 ;;; which buffers input LINES (and provides input editing).
152 ;;; To get around this we could always turn CBREAK mode
153 ;;; on and off, but there's no way to do this in a portable
154 ;;; manner.
155 ;;; 30-JAN-91 mk Fixed bug where in :test t mode it was actually providing
156 ;;; the system, instead of faking it.
157 ;;; 30-JAN-91 mk Changed storage of system definitions to a hash table.
158 ;;; Changed canonicalize-system-name to coerce the system
159 ;;; names to uppercase strings. Since we're no longer using
160 ;;; get, there's no need to intern the names as symbols,
161 ;;; and strings don't have packages to cause problems.
162 ;;; Added UNDEFSYSTEM, DEFINED-SYSTEMS, and DESCRIBE-SYSTEM.
163 ;;; Added :delete-binaries command.
164 ;;; 31-JAN-91 mk Franz Allegro CL has a defsystem in the USER package,
165 ;;; so we need to do a shadowing import to avoid name
166 ;;; conflicts.
167 ;;; 31-JAN-91 mk Fixed bug in compile-and-load-operation where it was
168 ;;; only loading newly compiled files.
169 ;;; 31-JAN-91 mk Added :load-time slot to components to record the
170 ;;; file-write-date of the binary/source file that was loaded.
171 ;;; Now knows "when" (which date version) the file was loaded.
172 ;;; Added keyword :minimal-load and global *minimal-load*
173 ;;; to enable defsystem to avoid reloading unmodified files.
174 ;;; Note that if B depends on A, but A is up to date and
175 ;;; loaded and the user specified :minimal-load T, then A
176 ;;; will not be loaded even if B needs to be compiled. So
177 ;;; if A is an initializations file, say, then the user should
178 ;;; not specify :minimal-load T.
179 ;;; 31-JAN-91 mk Added :load-only slot to components. If this slot is
180 ;;; specified as non-NIL, skips over any attempts to compile
181 ;;; the files in the component. (Loading the file satisfies
182 ;;; the need to recompile.)
183 ;;; 31-JAN-91 mk Eliminated use of set-alist-lookup and alist-lookup,
184 ;;; replacing it with hash tables. It was too much bother,
185 ;;; and rather brittle too.
186 ;;; 31-JAN-91 mk Defined #@ macro character for use with AFS @sys
187 ;;; feature simulator. #@"directory" is then synonymous
188 ;;; with (afs-binary-directory "directory").
189 ;;; 31-JAN-91 mk Added :private-file type of module. It is similar to
190 ;;; :file, but has an absolute pathname. This allows you
191 ;;; to specify a different version of a file in a system
192 ;;; (e.g., if you're working on the file in your home
193 ;;; directory) without completely rewriting the system
194 ;;; definition.
195 ;;; 31-JAN-91 mk Operations on systems, such as :compile and :load,
196 ;;; now propagate to subsystems the system depends on
197 ;;; if *operations-propagate-to-subsystems* is T (the default)
198 ;;; and the systems were defined using either defsystem
199 ;;; or as a :system component of another system. Thus if
200 ;;; a system depends on another, it can now recompile the
201 ;;; other.
202 ;;; 01-FEB-91 mk Added default definitions of PROVIDE/REQUIRE/*MODULES*
203 ;;; for lisps that have thrown away these definitions in
204 ;;; accordance with CLtL2.
205 ;;; 01-FEB-91 mk Added :compile-only slot to components. Analogous to
206 ;;; :load-only. If :compile-only is T, will not load the
207 ;;; file on operation :compile. Either compiles or loads
208 ;;; the file, but not both. In other words, compiling the
209 ;;; file satisfies the demand to load it. This is useful
210 ;;; for PCL defmethod and defclass definitions, which wrap
211 ;;; an (eval-when (compile load eval) ...) around the body
212 ;;; of the definition -- we save time by not loading the
213 ;;; compiled code, since the eval-when forces it to be
214 ;;; loaded. Note that this may not be entirely safe, since
215 ;;; CLtL2 has added a :load keyword to compile-file, and
216 ;;; some lisps may maintain a separate environment for
217 ;;; the compiler. This feature is for the person who asked
218 ;;; that a :COMPILE-SATISFIES-LOAD keyword be added to
219 ;;; modules. It's named :COMPILE-ONLY instead to match
220 ;;; :LOAD-ONLY.
221 ;;; 11-FEB-91 mk Now adds :mk-defsystem to features list, to allow
222 ;;; special cased loading of defsystem if not already
223 ;;; present.
224 ;;; 19-FEB-91 duff Added filename extension for hp9000/300's running Lucid.
225 ;;; 26-FEB-91 mk Distinguish between toplevel systems (defined with
226 ;;; defsystem) and systems defined as a :system module
227 ;;; of a defsystem. The former can depend only on systems,
228 ;;; while the latter can depend on anything at the same
229 ;;; level.
230 ;;; 12-MAR-91 mk Added :subsystem component type to be a system with
231 ;;; pathnames relative to its parent component.
232 ;;; 12-MAR-91 mk Uncommented :device :absolute for CMU pathnames, so
233 ;;; that the leading slash is included.
234 ;;; 12-MAR-91 brad Patches for Allegro 4.0.1 on Sparc.
235 ;;; 12-MAR-91 mk Changed definition of format-justified-string so that
236 ;;; it no longer depends on the ~<~> format directives,
237 ;;; because Allegro 4.0.1 has a bug which doesn't support
238 ;;; them. Anyway, the new definition is twice as fast
239 ;;; and conses half as much as FORMAT.
240 ;;; 12-MAR-91 toni Remove nils from list in expand-component-components.
241 ;;; 12-MAR-91 bw If the default-package and system have the same name,
242 ;;; and the package is not loaded, this could lead to
243 ;;; infinite loops, so we bomb out with an error.
244 ;;; Fixed bug in default packages.
245 ;;; 13-MAR-91 mk Added global *providing-blocks-load-propagation* to
246 ;;; control whether system dependencies are loaded if they
247 ;;; have already been provided.
248 ;;; 13-MAR-91 brad In-package is a macro in CLtL2 lisps, so we change
249 ;;; the package manually in operate-on-component.
250 ;;; 15-MAR-91 mk Modified *central-registry* to be either a single
251 ;;; directory pathname, or a list of directory pathnames
252 ;;; to be checked in order.
253 ;;; 15-MAR-91 rs Added afs-source-directory to handle versions when
254 ;;; compiling C code under lisp. Other minor changes to
255 ;;; translate-version and operate-on-system.
256 ;;; 21-MAR-91 gi Fixed bug in defined-systems.
257 ;;; 22-MAR-91 mk Replaced append-directories with new version that works
258 ;;; by actually appending the directories, after massaging
259 ;;; them into the proper format. This should work for all
260 ;;; CLtL2-compliant lisps.
261 ;;; 09-APR-91 djc Missing package prefix for lp:pathname-host-type.
262 ;;; Modified component-full-pathname to work for logical
263 ;;; pathnames.
264 ;;; 09-APR-91 mk Added *dont-redefine-require* to control whether
265 ;;; REQUIRE is redefined. Fixed minor bugs in redefinition
266 ;;; of require.
267 ;;; 12-APR-91 mk (pathname-host nil) causes an error in MCL 2.0b1
268 ;;; 12-APR-91 mc Ported to MCL2.0b1.
269 ;;; 16-APR-91 mk Fixed bug in needs-loading where load-time and
270 ;;; file-write-date got swapped.
271 ;;; 16-APR-91 mk If the component is load-only, defsystem shouldn't
272 ;;; tell you that there is no binary and ask you if you
273 ;;; want to load the source.
274 ;;; 17-APR-91 mc Two additional operations for MCL.
275 ;;; 21-APR-91 mk Added feature requested by ik. *files-missing-is-an-error*
276 ;;; new global variable which controls whether files (source
277 ;;; and binary) missing cause a continuable error or just a
278 ;;; warning.
279 ;;; 21-APR-91 mk Modified load-file-operation to allow compilation of source
280 ;;; files during load if the binary files are old or
281 ;;; non-existent. This adds a :compile-during-load keyword to
282 ;;; oos, and load-system. Global *compile-during-load* sets
283 ;;; the default (currently :query).
284 ;;; 21-APR-91 mk Modified find-system so that there is a preference for
285 ;;; loading system files from disk, even if the system is
286 ;;; already defined in the environment.
287 ;;; 25-APR-91 mk Removed load-time slot from component defstruct and added
288 ;;; function COMPONENT-LOAD-TIME to store the load times in a
289 ;;; hash table. This is safer than the old definition because
290 ;;; it doesn't wipe out load times every time the system is
291 ;;; redefined.
292 ;;; 25-APR-91 mk Completely rewrote load-file-operation. Fixed some bugs
293 ;;; in :compile-during-load and in the behavior of defsystem
294 ;;; when multiple users are compiling and loading a system
295 ;;; instead of just a single user.
296 ;;; 16-MAY-91 mk Modified FIND-SYSTEM to do the right thing if the system
297 ;;; definition file cannot be found.
298 ;;; 16-MAY-91 mk Added globals *source-pathname-default* and
299 ;;; *binary-pathname-default* to contain default values for
300 ;;; :source-pathname and :binary-pathname. For example, set
301 ;;; *source-pathname-default* to "" to avoid having to type
302 ;;; :source-pathname "" all the time.
303 ;;; 27-MAY-91 mk Fixed bug in new-append-directories where directory
304 ;;; components of the form "foo4.0" would appear as "foo4",
305 ;;; since pathname-name truncates the type. Changed
306 ;;; pathname-name to file-namestring.
307 ;;; 3-JUN-91 gc Small bug in new-append-directories; replace (when
308 ;;; abs-name) with (when (not (null-string abs-name)))
309 ;;; 4-JUN-91 mk Additional small change to new-append-directories for
310 ;;; getting the device from the relative pname if the abs
311 ;;; pname is "". This is to fix a small behavior in CMU CL old
312 ;;; compiler. Also changed (when (not (null-string abs-name)))
313 ;;; to have an (and abs-name) in there.
314 ;;; 8-JAN-92 sb Added filename extension for defsystem under Lucid Common
315 ;;; Lisp/SGO 3.0.1+.
316 ;;; 8-JAN-92 mk Changed the definition of prompt-string to work around an
317 ;;; AKCL bug. Essentially, AKCL doesn't default the colinc to
318 ;;; 1 if the colnum is provided, so we hard code it.
319 ;;; 8-JAN-92 rs (pathname-directory (pathname "")) returns '(:relative) in
320 ;;; Lucid, instead of NIL. Changed new-append-directories and
321 ;;; test-new-append-directories to reflect this.
322 ;;; 8-JAN-92 mk Fixed problem related to *load-source-if-no-binary*.
323 ;;; compile-and-load-source-if-no-binary wasn't checking for
324 ;;; the existence of the binary if this variable was true,
325 ;;; causing the file to not be compiled.
326 ;;; 8-JAN-92 mk Fixed problem with null-string being called on a pathname
327 ;;; by returning NIL if the argument isn't a string.
328 ;;; 3-NOV-93 mk In Allegro 4.2, pathname device is :unspecific by default.
329 ;;; 11-NOV-93 fdmm Fixed package definition lock problem when redefining
330 ;;; REQUIRE on ACL.
331 ;;; 11-NOV-93 fdmm Added machine and software types for SGI and IRIX. It is
332 ;;; important to distinguish the OS version and CPU type in
333 ;;; SGI+ACL, since ACL 4.1 on IRIX 4.x and ACL 4.2 on IRIX 5.x
334 ;;; have incompatible .fasl files.
335 ;;; 01-APR-94 fdmm Fixed warning problem when redefining REQUIRE on LispWorks.
336 ;;; 01-NOV-94 fdmm Replaced (software-type) call in ACL by code extracting
337 ;;; the interesting parts from (software-version) [deleted
338 ;;; machine name and id].
339 ;;; 03-NOV-94 fdmm Added a hook (*compile-file-function*), that is funcalled
340 ;;; by compile-file-operation, so as to support other languages
341 ;;; running on top of Common Lisp.
342 ;;; The default is to compile Common Lisp.
343 ;;; 03-NOV-94 fdmm Added SCHEME-COMPILE-FILE, so that defsystem can now
344 ;;; compile Pseudoscheme files.
345 ;;; 04-NOV-94 fdmm Added the exported generic function SET-LANGUAGE, to
346 ;;; have a clean, easy to extend interface for telling
347 ;;; defsystem which language to assume for compilation.
348 ;;; Currently supported arguments: :common-lisp, :scheme.
349 ;;; 11-NOV-94 kc Ported to Allegro CL for Windows 2.0 (ACLPC) and CLISP.
350 ;;; 18-NOV-94 fdmm Changed the entry *filename-extensions* for LispWorks
351 ;;; to support any platform.
352 ;;; Added entries for :mcl and :clisp too.
353 ;;; 16-DEC-94 fdmm Added and entry for CMU CL on SGI to *filename-extensions*.
354 ;;; 16-DEC-94 fdmm Added OS version identification for CMU CL on SGI.
355 ;;; 16-DEC-94 fdmm For CMU CL 17 : Bypassed make-pathnames call fix
356 ;;; in NEW-APPEND-DIRECTORIES.
357 ;;; 16-DEC-94 fdmm Added HOME-SUBDIRECTORY to fix CMU's ignorance about `~'
358 ;;; when specifying registries.
359 ;;; 16-DEC-94 fdmm For CMU CL 17 : Bypassed :device fix in make-pathnames call
360 ;;; in COMPONENT-FULL-PATHNAME. This fix was also reported
361 ;;; by kc on 12-NOV-94. CMU CL 17 now supports CLtL2 pathnames.
362 ;;; 16-DEC-94 fdmm Removed a quote before the call to read in the readmacro
363 ;;; #@. This fixes a really annoying misfeature (couldn't do
364 ;;; #@(concatenate 'string "foo/" "bar"), for example).
365 ;;; 03-JAN-95 fdmm Do not include :pcl in *features* if :clos is there.
366 ;;; 2-MAR-95 mk Modified fdmm's *central-registry* change to use
367 ;;; user-homedir-pathname and to be a bit more generic in the
368 ;;; pathnames.
369 ;;; 2-MAR-95 mk Modified fdmm's updates to *filename-extensions* to handle
370 ;;; any CMU CL binary extensions.
371 ;;; 2-MAR-95 mk Make kc's port to ACLPC a little more generic.
372 ;;; 2-MAR-95 mk djc reported a bug, in which GET-SYSTEM was not returning
373 ;;; a system despite the system's just having been loaded.
374 ;;; The system name specified in the :depends-on was a
375 ;;; lowercase string. I am assuming that the system name
376 ;;; in the defsystem form was a symbol (I haven't verified
377 ;;; that this was the case with djc, but it is the only
378 ;;; reasonable conclusion). So, CANONICALIZE-SYSTEM-NAME
379 ;;; was storing the system in the hash table as an
380 ;;; uppercase string, but attempting to retrieve it as a
381 ;;; lowercase string. This behavior actually isn't a bug,
382 ;;; but a user error. It was intended as a feature to
383 ;;; allow users to use strings for system names when
384 ;;; they wanted to distinguish between two different systems
385 ;;; named "foo.system" and "Foo.system". However, this
386 ;;; user error indicates that this was a bad design decision.
387 ;;; Accordingly, CANONICALIZE-SYSTEM-NAME now uppercases
388 ;;; even strings for retrieving systems, and the comparison
389 ;;; in *modules* is now case-insensitive. The result of
390 ;;; this change is if the user cannot have distinct
391 ;;; systems in "Foo.system" and "foo.system" named "Foo" and
392 ;;; "foo", because they will clobber each other. There is
393 ;;; still case-sensitivity on the filenames (i.e., if the
394 ;;; system file is named "Foo.system" and you use "foo" in
395 ;;; the :depends-on, it won't find it). We didn't take the
396 ;;; further step of requiring system filenames to be lowercase
397 ;;; because we actually find this kind of case-sensitivity
398 ;;; to be useful, when maintaining two different versions
399 ;;; of the same system.
400 ;;; 7-MAR-95 mk Added simplistic handling of logical pathnames. Also
401 ;;; modified new-append-directories so that it'll try to
402 ;;; split up pathname directories that are strings into a
403 ;;; list of the directory components. Such directories aren't
404 ;;; ANSI CL, but some non-conforming implementations do it.
405 ;;; 7-MAR-95 mk Added :proclamations to defsystem form, which can be used
406 ;;; to set the compiler optimization level before compilation.
407 ;;; For example,
408 ;;; :proclamations '(optimize (safety 3) (speed 3) (space 0))
409 ;;; 7-MAR-95 mk Defsystem now tells the user when it reloads the system
410 ;;; definition.
411 ;;; 7-MAR-95 mk Fixed problem pointed out by yc. If
412 ;;; *source-pathname-default* is "" and there is no explicit
413 ;;; :source-pathname specified for a file, the file could
414 ;;; wind up with an empty file name. In other words, this
415 ;;; global default shouldn't apply to :file components. Added
416 ;;; explicit test for null strings, and when present replaced
417 ;;; them with NIL (for binary as well as source, and also for
418 ;;; :private-file components).
419 ;;; 7-MAR-95 tar Fixed defsystem to work on TI Explorers (TI CL).
420 ;;; 7-MAR-95 jk Added machine-type-translation for Decstation 5000/200
421 ;;; under Allegro 3.1
422 ;;; 7-MAR-95 as Fixed bug in AKCL-1-615 in which defsystem added a
423 ;;; subdirectory "RELATIVE" to all filenames.
424 ;;; 7-MAR-95 mk Added new test to test-new-append-directories to catch the
425 ;;; error fixed by as. Essentially, this error occurs when the
426 ;;; absolute-pathname has no directory (i.e., it has a single
427 ;;; pathname component as in "foo" and not "foo/bar"). If
428 ;;; RELATIVE ever shows up in the Result, we now know to
429 ;;; add an extra conditionalization to prevent abs-keyword
430 ;;; from being set to :relative.
431 ;;; 7-MAR-95 ss Miscellaneous fixes for MCL 2.0 final.
432 ;;; *compile-file-verbose* not in MCL, *version variables
433 ;;; need to occur before AFS-SOURCE-DIRECTORY definition,
434 ;;; and certain code needed to be in the CCL: package.
435 ;;; 8-MAR-95 mk Y-OR-N-P-WAIT uses a busy-waiting. On Lisp systems where
436 ;;; the time functions cons, such as CMU CL, this can cause a
437 ;;; lot of ugly garbage collection messages. Modified the
438 ;;; waiting to include calls to SLEEP, which should reduce
439 ;;; some of the consing.
440 ;;; 8-MAR-95 mk Replaced fdmm's SET-LANGUAGE enhancement with a more
441 ;;; general extension, along the lines suggested by akd.
442 ;;; Defsystem now allows components to specify a :language
443 ;;; slot, such as :language :lisp, :language :scheme. This
444 ;;; slot is inherited (with the default being :lisp), and is
445 ;;; used to obtain compilation and loading functions for
446 ;;; components, as well as source and binary extensions. The
447 ;;; compilation and loading functions can be overridden by
448 ;;; specifying a :compiler or :loader in the system
449 ;;; definition. Also added :documentation slot to the system
450 ;;; definition.
451 ;;; Where this comes in real handy is if one has a
452 ;;; compiler-compiler implemented in Lisp, and wants the
453 ;;; system to use the compiler-compiler to create a parser
454 ;;; from a grammar and then compile parser. To do this one
455 ;;; would create a module with components that looked
456 ;;; something like this:
457 ;;; ((:module cc :components ("compiler-compiler"))
458 ;;; (:module gr :compiler 'cc :loader #'ignore
459 ;;; :source-extension "gra"
460 ;;; :binary-extension "lisp"
461 ;;; :depends-on (cc)
462 ;;; :components ("sample-grammar"))
463 ;;; (:module parser :depends-on (gr)
464 ;;; :components ("sample-grammar")))
465 ;;; Defsystem would then compile and load the compiler, use
466 ;;; it (the function cc) to compile the grammar into a parser,
467 ;;; and then compile the parser. The only tricky part is
468 ;;; cc is defined by the system, and one can't include #'cc
469 ;;; in the system definition. However, one could include
470 ;;; a call to mk:define-language in the compiler-compiler file,
471 ;;; and define :cc as a language. This is the prefered method.
472 ;;; 8-MAR-95 mk New definition of topological-sort suggested by rs2. This
473 ;;; version avoids the call to SORT, but in practice isn't
474 ;;; much faster. However, it avoids the need to maintain a
475 ;;; TIME slot in the topsort-node structure.
476 ;;; 8-MAR-95 mk rs2 also pointed out that the calls to MAKE-PATHNAME and
477 ;;; NAMESTRING in COMPONENT-FULL-PATHNAME are a major reason
478 ;;; why defsystem is slow. Accordingly, I've changed
479 ;;; COMPONENT-FULL-PATHNAME to include a call to NAMESTRING
480 ;;; (and removed all other calls to NAMESTRING), and also made
481 ;;; a few changes to minimize the number of calls to
482 ;;; COMPONENT-FULL-PATHNAME, such as memoizing it. See To Do
483 ;;; below for other related comments.
484 ;;; 8-MAR-95 mk Added special hack requested by Steve Strassman, which
485 ;;; allows one to specify absolute pathnames in the shorthand
486 ;;; for a list of components, and have defsystem recognize
487 ;;; which are absolute and which are relative.
488 ;;; I actually think this would be a good idea, but I haven't
489 ;;; tested it, so it is disabled by default. Search for
490 ;;; *enable-straz-absolute-string-hack* to enable it.
491 ;;; 8-MAR-95 kt Fixed problem with EXPORT in AKCL 1.603, in which it wasn't
492 ;;; properly exporting the value of the global export
493 ;;; variables.
494 ;;; 8-MAR-95 mk Added UNMUNGE-LUCID to fix nasty problem with COMPILE-FILE
495 ;;; in Lucid. Lucid apparently tries to merge the :output-file
496 ;;; with the source file when the :output-file is a relative
497 ;;; pathname. Wierd, and definitely non-standard.
498 ;;; 9-MAR-95 mk Changed ALLEGRO-MAKE-SYSTEM-FASL to also include the files
499 ;;; in any systems the system depends on, as per a
500 ;;; request of oc.
501 ;;; 9-MAR-95 mk Some version of CMU CL couldn't hack a call to
502 ;;; MAKE-PATHNAME with :host NIL. I'm not sure which version
503 ;;; it is, but the current version doesn't have this problem.
504 ;;; If given :host nil, it defaults the host to
505 ;;; COMMON-LISP::*UNIX-HOST*. So I haven't "fixed" this
506 ;;; problem.
507 ;;; 9-MAR-95 mk Integrated top-level commands for Allegro designed by bha
508 ;;; into the code, with slight modifications.
509 ;;; 9-MAR-95 mk Instead of having COMPUTE-SYSTEM-PATH check the current
510 ;;; directory in a hard-coded fashion, include the current
511 ;;; directory in the *central-registry*, as suggested by
512 ;;; bha and others.
513 ;;; 9-MAR-95 bha Support for Logical Pathnames in Allegro.
514 ;;; 9-MAR-95 mk Added modified version of bha's DEFSYSPATH idea.
515 ;;; 13-MAR-95 mk Added a macro for the simple serial case, where a system
516 ;;; (or module) is simple a list of files, each of which
517 ;;; depends on the previous one. If the value of :components
518 ;;; is a list beginning with :serial, it expands each
519 ;;; component and makes it depend on the previous component.
520 ;;; For example, (:serial "foo" "bar" "baz") would create a
521 ;;; set of components where "baz" depended on "bar" and "bar"
522 ;;; on "foo".
523 ;;; 13-MAR-95 mk *** Now version 3.0. This version is a interim bug-fix and
524 ;;; update, since I do not have the time right now to complete
525 ;;; the complete overhaul and redesign.
526 ;;; Major changes in 3.0 include CMU CL 17, CLISP, ACLPC, TI,
527 ;;; LispWorks and ACL(SGI) support, bug fixes for ACL 4.1/4.2.
528 ;;; 14-MAR-95 fdmm Finally added the bit of code to discriminate cleanly
529 ;;; among different lisps without relying on (software-version)
530 ;;; idiosyncracies.
531 ;;; You can now customize COMPILER-TYPE-TRANSLATION so that
532 ;;; AFS-BINARY-DIRECTORY can return a different value for
533 ;;; different lisps on the same platform.
534 ;;; If you use only one compiler, do not care about supporting
535 ;;; code for multiple versions of it, and want less verbose
536 ;;; directory names, just set *MULTIPLE-LISP-SUPPORT* to nil.
537 ;;; 17-MAR-95 lmh Added EVAL-WHEN for one of the MAKE-PACKAGE calls.
538 ;;; CMU CL's RUN-PROGRAM is in the extensions package.
539 ;;; ABSOLUTE-FILE-NAMESTRING-P was missing :test keyword
540 ;;; Rearranged conditionalization in DIRECTORY-TO-LIST to
541 ;;; suppress compiler warnings in CMU CL.
542 ;;; 17-MAR-95 mk Added conditionalizations to avoid certain CMU CL compiler
543 ;;; warnings reported by lmh.
544 ;;; 19990610 ma Added shadowing of 'HARDCOPY-SYSTEM' for LW Personal Ed.
546 ;;; 19991211 ma NEW VERSION 4.0 started.
547 ;;; 19991211 ma Merged in changes requested by T. Russ of
548 ;;; ISI. Please refer to the special "ISI" comments to
549 ;;; understand these changes
550 ;;; 20000228 ma The symbols FIND-SYSTEM, LOAD-SYSTEM, DEFSYSTEM,
551 ;;; COMPILE-SYSTEM and HARDCOPY-SYSTEM are no longer
552 ;;; imported in the COMMON-LISP-USER package.
553 ;;; Cfr. the definitions of *EXPORTS* and
554 ;;; *SPECIAL-EXPORTS*.
555 ;;; 2000-07-21 rlt Add COMPILER-OPTIONS to defstruct to allow user to
556 ;;; specify special compiler options for a particular
557 ;;; component.
558 ;;; 2002-01-08 kmr Changed allegro symbols to lowercase to support
559 ;;; case-sensitive images
561 ;;;---------------------------------------------------------------------------
562 ;;; ISI Comments
564 ;;; 19991211 Marco Antoniotti
565 ;;; These comments come from the "ISI Branch". I believe I did
566 ;;; include the :load-always extension correctly. The other commets
567 ;;; seem superseded by other changes made to the system in the
568 ;;; following years. Some others are now useless with newer systems
569 ;;; (e.g. filename truncation for new Windows based CL
570 ;;; implementations.)
572 ;;; 1-OCT-92 tar Fixed problem with TI Lisp machines and append-directory.
573 ;;; 1-OCT-92 tar Made major modifications to compile-file-operation and
574 ;;; load-file-operation to reduce the number of probe-file
575 ;;; and write-date inquiries. This makes the system run much
576 ;;; faster through slow network connections.
577 ;;; 13-OCT-92 tar Added :load-always slot to components. If this slot is
578 ;;; specified as non-NIL, always loads the component.
579 ;;; This does not trigger dependent compilation.
580 ;;; (This can be useful when macro definitions needed
581 ;;; during compilation are changed by later files. In
582 ;;; this case, not reloading up-to-date files can
583 ;;; cause different results.)
584 ;;; 28-OCT-93 tar Allegro 4.2 causes an error on (pathname-device nil)
585 ;;; 14-SEP-94 tar Disable importing of symbols into (CL-)USER package
586 ;;; to minimize conflicts with other defsystem utilities.
587 ;;; 10-NOV-94 tar Added filename truncation code to support Franz Allegro
588 ;;; PC with it's 8 character filename limitation.
589 ;;; 15-MAY-98 tar Changed host attribute for pathnames to support LispWorks
590 ;;; (Windows) pathnames which reference other Drives. Also
591 ;;; updated file name convention.
592 ;;; 9-NOV-98 tar Updated new-append-directories for Lucid 5.0
596 ;;; ********************************
597 ;;; Ports **************************
598 ;;; ********************************
600 ;;; DEFSYSTEM has been tested (successfully) in the following lisps:
601 ;;; CMU Common Lisp (M2.9 15-Aug-90, Compiler M1.8 15-Aug-90)
602 ;;; CMU Common Lisp (14-Dec-90 beta, Python Compiler 0.0 PMAX/Mach)
603 ;;; CMU Common Lisp 17f (Python 1.0)
604 ;;; Franz Allegro Common Lisp 3.1.12 (ExCL 3/30/90)
605 ;;; Franz Allegro Common Lisp 4.0/4.1/4.2
606 ;;; Franz Allegro Common Lisp for Windows (2.0)
607 ;;; Lucid Common Lisp (Version 2.1 6-DEC-87)
608 ;;; Lucid Common Lisp (3.0 [SPARC,SUN3])
609 ;;; Lucid Common Lisp (4.0 [SPARC,SUN3])
610 ;;; VAXLisp (v2.2) [VAX/VMS]
611 ;;; VAXLisp (v3.1)
612 ;;; Harlequin LispWorks
613 ;;; CLISP (CLISP3 [SPARC])
614 ;;; Symbolics XL12000 (Genera 8.3)
615 ;;; Scieneer Common Lisp (SCL) 1.1
616 ;;; Macintosh Common Lisp
617 ;;; ECL
619 ;;; DEFSYSTEM needs to be tested in the following lisps:
620 ;;; OpenMCL
621 ;;; Symbolics Common Lisp (8.0)
622 ;;; KCL (June 3, 1987 or later)
623 ;;; AKCL (1.86, June 30, 1987 or later)
624 ;;; TI (Release 4.1 or later)
625 ;;; Ibuki Common Lisp (01/01, October 15, 1987)
626 ;;; Golden Common Lisp (3.1 IBM-PC)
627 ;;; HP Common Lisp (same as Lucid?)
628 ;;; Procyon Common Lisp
630 ;;; ********************************
631 ;;; To Do **************************
632 ;;; ********************************
634 ;;; COMPONENT-FULL-PATHNAME is a major source of slowness in the system
635 ;;; because of all the calls to the expensive operations MAKE-PATHNAME
636 ;;; and NAMESTRING. To improve performance, DEFSYSTEM should be reworked
637 ;;; to avoid any need to call MAKE-PATHNAME and NAMESTRING, as the logical
638 ;;; pathnames package does. Unfortunately, I don't have the time to do this
639 ;;; right now. Instead, I installed a temporary improvement by memoizing
640 ;;; COMPONENT-FULL-PATHNAME to cache previous calls to the function on
641 ;;; a component by component and type by type basis. The cache is
642 ;;; cleared before each call to OOS, in case filename extensions change.
643 ;;; But DEFSYSTEM should really be reworked to avoid this problem and
644 ;;; ensure greater portability and to also handle logical pathnames.
646 ;;; Also, PROBE-FILE and FILE-WRITE-DATE are other sources of slowness.
647 ;;; Perhaps by also memoizing FILE-WRITE-DATE and reimplementing PROBE-FILE
648 ;;; in terms of FILE-WRITE-DATE, can achieve a further speed-up. This was
649 ;;; suggested by Steven Feist (feist@ils.nwu.edu).
651 ;;; True CLtL2 logical pathnames support -- can't do it, because CLtL2
652 ;;; doesn't have all the necessary primitives, and even in Allegro CL 4.2
653 ;;; (namestring #l"foo:bar;baz.lisp")
654 ;;; does not work properly.
656 ;;; Create separate stand-alone documentation for defsystem, and also
657 ;;; a test suite.
659 ;;; Change SYSTEM to be a class instead of a struct, and make it a little
660 ;;; more generic, so that it permits alternate system definitions.
661 ;;; Replace OPERATE-ON-SYSTEM with MAP-SYSTEM (args: function, system-name,
662 ;;; &rest options)
664 ;;; Add a patch directory mechanism. Perhaps have several directories
665 ;;; with code in them, and the first one with the specified file wins?
666 ;;; LOAD-PATCHES function.
668 ;;; Need way to load old binaries even if source is newer.
670 ;;; Allow defpackage forms/package definitions in the defsystem? If
671 ;;; a package not defined, look for and load a file named package.pkg?
673 ;;; need to port for GNU CL (ala kcl)?
675 ;;; Someone asked whether one can have :file components at top-level. I believe
676 ;;; this is the case, but should double-check that it is possible (and if
677 ;;; not, make it so).
679 ;;; A common error/misconception seems to involve assuming that :system
680 ;;; components should include the name of the system file, and that
681 ;;; defsystem will automatically load the file containing the system
682 ;;; definition and propagate operations to it. Perhaps this would be a
683 ;;; nice feature to add.
685 ;;; If a module is :load-only t, then it should not execute its :finally-do
686 ;;; and :initially-do clauses during compilation operations, unless the
687 ;;; module's files happen to be loaded during the operation.
689 ;;; System Class. Customizable delimiters.
691 ;;; Load a system (while not loading anything already loaded)
692 ;;; and inform the user of out of date fasls with the choice
693 ;;; to load the old fasl or recompile and then load the new
694 ;;; fasl?
696 ;;; modify compile-file-operation to handle a query keyword....
698 ;;; Perhaps systems should keep around the file-write-date of the system
699 ;;; definition file, to prevent excessive reloading of the system definition?
701 ;;; load-file-operation needs to be completely reworked to simplify the
702 ;;; logic of when files get loaded or not.
704 ;;; Need to revamp output: Nesting and indenting verbose output doesn't
705 ;;; seem cool, especially when output overflows the 80-column margins.
707 ;;; Document various ways of writing a system. simple (short) form
708 ;;; (where :components is just a list of filenames) in addition to verbose.
709 ;;; Put documentation strings in code.
711 ;;; :load-time for modules and systems -- maybe record the time the system
712 ;;; was loaded/compiled here and print it in describe-system?
714 ;;; Make it easy to define new functions that operate on a system. For
715 ;;; example, a function that prints out a list of files that have changed,
716 ;;; hardcopy-system, edit-system, etc.
718 ;;; If a user wants to have identical systems for different lisps, do we
719 ;;; force the user to use logical pathnames? Or maybe we should write a
720 ;;; generic-pathnames package that parses any pathname format into a
721 ;;; uniform underlying format (i.e., pull the relevant code out of
722 ;;; logical-pathnames.lisp and clean it up a bit).
724 ;;; Verify that Mac pathnames now work with append-directories.
726 ;;; A common human error is to violate the modularization by making a file
727 ;;; in one module depend on a file in another module, instead of making
728 ;;; one module depend on the other. This is caught because the dependency
729 ;;; isn't found. However, is there any way to provide a more informative
730 ;;; error message? Probably not, especially if the system has multiple
731 ;;; files of the same name.
733 ;;; For a module none of whose files needed to be compiled, have it print out
734 ;;; "no files need recompilation".
736 ;;; Write a system date/time to a file? (version information) I.e., if the
737 ;;; filesystem supports file version numbers, write an auxiliary file to
738 ;;; the system definition file that specifies versions of the system and
739 ;;; the version numbers of the associated files.
741 ;;; Add idea of a patch directory.
743 ;;; In verbose printout, have it log a date/time at start and end of
744 ;;; compilation:
745 ;;; Compiling system "test" on 31-Jan-91 21:46:47
746 ;;; by Defsystem version v2.0 01-FEB-91.
748 ;;; Define other :force options:
749 ;;; :query allows user to specify that a file not normally compiled
750 ;;; should be. OR
751 ;;; :confirm allows user to specify that a file normally compiled
752 ;;; shouldn't be. AND
754 ;;; We currently assume that compilation-load dependencies and if-changed
755 ;;; dependencies are identical. However, in some cases this might not be
756 ;;; true. For example, if we change a macro we have to recompile functions
757 ;;; that depend on it (except in lisps that automatically do this, such
758 ;;; as the new CMU Common Lisp), but not if we change a function. Splitting
759 ;;; these apart (with appropriate defaulting) would be nice, but not worth
760 ;;; doing immediately since it may save only a couple of file recompilations,
761 ;;; while making defsystem much more complex than it already is.
763 ;;; Current dependencies are limited to siblings. Maybe we should allow
764 ;;; nephews and uncles? So long as it is still a DAG, we can sort it.
765 ;;; Answer: No. The current setup enforces a structure on the modularity.
766 ;;; Otherwise, why should we have modules if we're going to ignore it?
768 ;;; Currently a file is recompiled more or less if the source is newer
769 ;;; than the binary or if the file depends on a file that has changed
770 ;;; (i.e., was recompiled in this session of a system operation).
771 ;;; Neil Goldman <goldman@isi.edu> has pointed out that whether a file
772 ;;; needs recompilation is really independent of the current session of
773 ;;; a system operation, and depends only on the file-write-dates of the
774 ;;; source and binary files for a system. Thus a file should require
775 ;;; recompilation in the following circumstances:
776 ;;; 1. If a file's source is newer than its binary, or
777 ;;; 2. If a file's source is not newer than its binary, but the file
778 ;;; depends directly or indirectly on a module (or file) that is newer.
779 ;;; For a regular file use the file-write-date (FWD) of the source or
780 ;;; binary, whichever is more recent. For a load-only file, use the only
781 ;;; available FWD. For a module, use the most recent (max) FWD of any of
782 ;;; its components.
783 ;;; The impact of this is that instead of using a boolean CHANGED variable
784 ;;; throughout the code, we need to allow CHANGED to be NIL/T/<FWD> or
785 ;;; maybe just the FWD timestamp, and to use the value of CHANGED in
786 ;;; needs-compilation decisions. (Use of NIL/T as values is an optimization.
787 ;;; The FWD timestamp which indicates the most recent time of any changes
788 ;;; should be sufficient.) This will affect not just the
789 ;;; compile-file-operation, but also the load-file-operation because of
790 ;;; compilation during load. Also, since FWDs will be used more prevalently,
791 ;;; we probably should couple this change with the inclusion of load-times
792 ;;; in the component defstruct. This is a tricky and involved change, and
793 ;;; requires more thought, since there are subtle cases where it might not
794 ;;; be correct. For now, the change will have to wait until the DEFSYSTEM
795 ;;; redesign.
797 ;;; ********************************************************************
798 ;;; How to Use this System *********************************************
799 ;;; ********************************************************************
801 ;;; To use this system,
802 ;;; 1. If you want to have a central registry of system definitions,
803 ;;; modify the value of the variable *central-registry* below.
804 ;;; 2. Load this file (defsystem.lisp) in either source or compiled form,
805 ;;; 3. Load the file containing the "defsystem" definition of your system,
806 ;;; 4. Use the function "operate-on-system" to do things to your system.
808 ;;; For more information, see the documentation and examples in
809 ;;; lisp-utilities.ps.
811 ;;; ********************************
812 ;;; Usage Comments *****************
813 ;;; ********************************
815 ;;; If you use symbols in the system definition file, they get interned in
816 ;;; the COMMON-LISP-USER package, which can lead to name conflicts when
817 ;;; the system itself seeks to export the same symbol to the COMMON-LISP-USER
818 ;;; package. The workaround is to use strings instead of symbols for the
819 ;;; names of components in the system definition file. In the major overhaul,
820 ;;; perhaps the user should be precluded from using symbols for such
821 ;;; identifiers.
823 ;;; If you include a tilde in the :source-pathname in Allegro, as in "~/lisp",
824 ;;; file name expansion is much slower than if you use the full pathname,
825 ;;; as in "/user/USERID/lisp".
829 ;;; ****************************************************************
830 ;;; Lisp Code ******************************************************
831 ;;; ****************************************************************
833 ;;; ********************************
834 ;;; Massage CLtL2 onto *features* **
835 ;;; ********************************
836 ;;; Let's be smart about CLtL2 compatible Lisps:
837 (eval-when (compile load eval)
838 #+(or (and allegro-version>= (version>= 4 0)) :mcl :sbcl)
839 (pushnew :cltl2 *features*))
841 ;;; ********************************
842 ;;; Provide/Require/*modules* ******
843 ;;; ********************************
845 ;;; Since CLtL2 has dropped require and provide from the language, some
846 ;;; lisps may not have the functions PROVIDE and REQUIRE and the
847 ;;; global *MODULES*. So if lisp::provide and user::provide are not
848 ;;; defined, we define our own.
850 ;;; Hmmm. CMU CL old compiler gives bogus warnings here about functions
851 ;;; and variables not being declared or bound, apparently because it
852 ;;; sees that (or (fboundp 'lisp::require) (fboundp 'user::require)) returns
853 ;;; T, so it doesn't really bother when compiling the body of the unless.
854 ;;; The new compiler does this properly, so I'm not going to bother
855 ;;; working around this.
857 ;;; Some Lisp implementations return bogus warnings about assuming
858 ;;; *MODULE-FILES* and *LIBRARY* to be special, and CANONICALIZE-MODULE-NAME
859 ;;; and MODULE-FILES being undefined. Don't worry about them.
861 ;;; Now that ANSI CL includes PROVIDE and REQUIRE again, is this code
862 ;;; necessary?
864 #-(or :CMU
865 :vms
866 :mcl
867 :lispworks
868 :clisp
869 :gcl
870 :sbcl
871 :cormanlisp
872 :scl
873 :abcl
874 :ccl
875 :ecl
876 (and allegro-version>= (version>= 4 1)))
877 (eval-when #-(or :lucid)
878 (:compile-toplevel :load-toplevel :execute)
879 #+(or :lucid)
880 (compile load eval)
882 (unless (or (fboundp 'lisp::require)
883 (fboundp 'user::require)
885 #+(and :excl (and allegro-version>= (version>= 4 0)))
886 (fboundp 'cltl1::require)
888 #+:lispworks
889 (fboundp 'system::require))
891 #-:lispworks
892 (in-package :lisp)
893 #+:lispworks
894 (in-package :system)
896 (export '(*modules* provide require))
898 ;; Documentation strings taken almost literally from CLtL1.
900 (defvar *modules* ()
901 "List of names of the modules that have been loaded into Lisp so far.
902 It is used by PROVIDE and REQUIRE.")
904 ;; We provide two different ways to define modules. The default way
905 ;; is to put either a source or binary file with the same name
906 ;; as the module in the library directory. The other way is to define
907 ;; the list of files in the module with defmodule.
909 ;; The directory listed in *library* is implementation dependent,
910 ;; and is intended to be used by Lisp manufacturers as a place to
911 ;; store their implementation dependent packages.
912 ;; Lisp users should use systems and *central-registry* to store
913 ;; their packages -- it is intended that *central-registry* is
914 ;; set by the user, while *library* is set by the lisp.
916 (defvar *library* nil ; "/usr/local/lisp/Modules/"
917 "Directory within the file system containing files, where the name
918 of a file is the same as the name of the module it contains.")
920 (defvar *module-files* (make-hash-table :test #'equal)
921 "Hash table mapping from module names to list of files for the
922 module. REQUIRE loads these files in order.")
924 (defun canonicalize-module-name (name)
925 ;; if symbol, string-downcase the printrep to make nicer filenames.
926 (if (stringp name) name (string-downcase (string name))))
928 (defmacro defmodule (name &rest files)
929 "Defines a module NAME to load the specified FILES in order."
930 `(setf (gethash (canonicalize-module-name ,name) *module-files*)
931 ',files))
932 (defun module-files (name)
933 (gethash name *module-files*))
935 (defun provide (name)
936 "Adds a new module name to the list of modules maintained in the
937 variable *modules*, thereby indicating that the module has been
938 loaded. Name may be a string or symbol -- strings are case-senstive,
939 while symbols are treated like lowercase strings. Returns T if
940 NAME was not already present, NIL otherwise."
941 (let ((module (canonicalize-module-name name)))
942 (unless (find module *modules* :test #'string=)
943 ;; Module not present. Add it and return T to signify that it
944 ;; was added.
945 (push module *modules*)
946 t)))
948 (defun require (name &optional pathname)
949 "Tests whether a module is already present. If the module is not
950 present, loads the appropriate file or set of files. The pathname
951 argument, if present, is a single pathname or list of pathnames
952 whose files are to be loaded in order, left to right. If the
953 pathname is nil, the system first checks if a module was defined
954 using defmodule and uses the pathnames so defined. If that fails,
955 it looks in the library directory for a file with name the same
956 as that of the module. Returns T if it loads the module."
957 (let ((module (canonicalize-module-name name)))
958 (unless (find module *modules* :test #'string=)
959 ;; Module is not already present.
960 (when (and pathname (not (listp pathname)))
961 ;; If there's a pathname or pathnames, ensure that it's a list.
962 (setf pathname (list pathname)))
963 (unless pathname
964 ;; If there's no pathname, try for a defmodule definition.
965 (setf pathname (module-files module)))
966 (unless pathname
967 ;; If there's still no pathname, try the library directory.
968 (when *library*
969 (setf pathname (concatenate 'string *library* module))
970 ;; Test if the file exists.
971 ;; We assume that the lisp will default the file type
972 ;; appropriately. If it doesn't, use #+".fasl" or some
973 ;; such in the concatenate form above.
974 (if (probe-file pathname)
975 ;; If it exists, ensure we've got a list
976 (setf pathname (list pathname))
977 ;; If the library file doesn't exist, we don't want
978 ;; a load error.
979 (setf pathname nil))))
980 ;; Now that we've got the list of pathnames, let's load them.
981 (dolist (pname pathname t)
982 (load pname :verbose nil))))))
983 ) ; eval-when
985 ;;; ********************************
986 ;;; Set up Package *****************
987 ;;; ********************************
990 ;;; Unfortunately, lots of lisps have their own defsystems, some more
991 ;;; primitive than others, all uncompatible, and all in the DEFSYSTEM
992 ;;; package. To avoid name conflicts, we've decided to name this the
993 ;;; MAKE package. A nice side-effect is that the short nickname
994 ;;; MK is my initials.
996 #+abcl (defpackage make (:use "COMMON-LISP") (:nicknames "MK"))
998 #+(or clisp cormanlisp ecl (and gcl defpackage) sbcl ccl)
999 (defpackage "MAKE" (:use "COMMON-LISP") (:nicknames "MK"))
1001 #-(or :sbcl :cltl2 :lispworks :ecl :scl :abcl :ccl)
1002 (in-package :make :nicknames '("MK"))
1004 ;;; For CLtL2 compatible lisps...
1005 #+(and :excl :allegro-v4.0 :cltl2)
1006 (defpackage "MAKE" (:nicknames "MK" "make" "mk") (:use :common-lisp)
1007 (:import-from cltl1 *modules* provide require))
1009 ;;; *** Marco Antoniotti <marcoxa@icsi.berkeley.edu> 19970105
1010 ;;; In Allegro 4.1, 'provide' and 'require' are not external in
1011 ;;; 'CLTL1'. However they are in 'COMMON-LISP'. Hence the change.
1012 #+(and :excl :allegro-v4.1 :cltl2)
1013 (defpackage "MAKE" (:nicknames "MK" "make" "mk") (:use :common-lisp) )
1015 #+(and :excl :allegro-version>= (version>= 4 2))
1016 (defpackage "MAKE" (:nicknames "MK" "make" "mk") (:use :common-lisp))
1018 #+:lispworks
1019 (defpackage "MAKE" (:nicknames "MK") (:use "COMMON-LISP")
1020 (:import-from system *modules* provide require)
1021 (:export "DEFSYSTEM" "COMPILE-SYSTEM" "LOAD-SYSTEM"
1022 "DEFINE-LANGUAGE" "*MULTIPLE-LISP-SUPPORT*"))
1024 #+:mcl
1025 (defpackage "MAKE" (:nicknames "MK") (:use "COMMON-LISP")
1026 (:import-from ccl *modules* provide require))
1028 ;;; *** Marco Antoniotti <marcoxa@icsi.berkeley.edu> 19951012
1029 ;;; The code below, is originally executed also for CMUCL. However I
1030 ;;; believe this is wrong, since CMUCL comes with its own defpackage.
1031 ;;; I added the extra :CMU in the 'or'.
1032 #+(and :cltl2 (not (or :cmu :scl :clisp :sbcl :abcl
1033 (and :excl (or :allegro-v4.0 :allegro-v4.1))
1034 :mcl)))
1035 (eval-when (compile load eval)
1036 (unless (find-package "MAKE")
1037 (make-package "MAKE" :nicknames '("MK") :use '("COMMON-LISP"))))
1039 ;;; *** Marco Antoniotti <marcoxa@icsi.berkeley.edu> 19951012
1040 ;;; Here I add the proper defpackage for CMU
1041 #+:CMU
1042 (defpackage "MAKE" (:use "COMMON-LISP" "CONDITIONS")
1043 (:nicknames "MK"))
1045 #+:sbcl
1046 (defpackage "MAKE" (:use "COMMON-LISP")
1047 (:nicknames "MK"))
1049 #+:scl
1050 (defpackage :make (:use :common-lisp)
1051 (:nicknames :mk))
1053 #+(or :cltl2 :lispworks :scl)
1054 (eval-when (compile load eval)
1055 (in-package :make))
1057 #+(or ecl abcl ccl)
1058 (in-package :make)
1060 ;;; *** Marco Antoniotti <marcoxa@icsi.berkeley.edu> 19970105
1061 ;;; 'provide' is not esternal in 'CLTL1' in Allegro v 4.1
1062 #+(and :excl :allegro-v4.0 :cltl2)
1063 (cltl1:provide 'make)
1064 #+(and :excl :allegro-v4.0 :cltl2)
1065 (provide 'make)
1067 #+:openmcl
1068 (cl:provide 'make)
1070 #+(and :mcl (not :openmcl))
1071 (ccl:provide 'make)
1073 #+(and :cltl2 (not (or (and :excl (or :allegro-v4.0 :allegro-v4.1)) :mcl)))
1074 (provide 'make)
1076 #+:lispworks
1077 (provide 'make)
1079 #-(or :cltl2 :lispworks)
1080 (provide 'make)
1082 (pushnew :mk-defsystem *features*)
1084 ;;; Some compatibility issues. Mostly for CormanLisp.
1085 ;;; 2002-02-20 Marco Antoniotti
1087 #+cormanlisp
1088 (defun compile-file-pathname (pathname-designator)
1089 (merge-pathnames (make-pathname :type "fasl")
1090 (etypecase pathname-designator
1091 (pathname pathname-designator)
1092 (string (parse-namestring pathname-designator))
1093 ;; We need FILE-STREAM here as well.
1096 #+cormanlisp
1097 (defun file-namestring (pathname-designator)
1098 (let ((p (etypecase pathname-designator
1099 (pathname pathname-designator)
1100 (string (parse-namestring pathname-designator))
1101 ;; We need FILE-STREAM here as well.
1103 (namestring (make-pathname :directory ()
1104 :name (pathname-name p)
1105 :type (pathname-type p)
1106 :version (pathname-version p)))))
1108 ;;; The external interface consists of *exports* and *other-exports*.
1110 ;;; AKCL (at least 1.603) grabs all the (export) forms and puts them up top in
1111 ;;; the compile form, so that you can't use a defvar with a default value and
1112 ;;; then a succeeding export as well.
1114 (eval-when (compile load eval)
1115 (defvar *special-exports* nil)
1116 (defvar *exports* nil)
1117 (defvar *other-exports* nil)
1119 (export (setq *exports*
1120 '(operate-on-system
1122 afs-binary-directory afs-source-directory
1123 files-in-system)))
1124 (export (setq *special-exports*
1125 '()))
1126 (export (setq *other-exports*
1127 '(*central-registry*
1128 *bin-subdir*
1130 add-registry-location
1131 find-system
1132 defsystem compile-system load-system hardcopy-system
1134 system-definition-pathname
1136 missing-component
1137 missing-component-name
1138 missing-component-component
1139 missing-module
1140 missing-system
1142 register-foreign-system
1144 machine-type-translation
1145 software-type-translation
1146 compiler-type-translation
1147 ;; require
1148 define-language
1149 allegro-make-system-fasl
1150 files-which-need-compilation
1151 undefsystem
1152 defined-systems
1153 describe-system clean-system edit-system ;hardcopy-system
1154 system-source-size make-system-tag-table
1155 *defsystem-version*
1156 *compile-during-load*
1157 *minimal-load*
1158 *dont-redefine-require*
1159 *files-missing-is-an-error*
1160 *reload-systems-from-disk*
1161 *source-pathname-default*
1162 *binary-pathname-default*
1163 *multiple-lisp-support*
1164 ))))
1167 ;;; We import these symbols into the USER package to make them
1168 ;;; easier to use. Since some lisps have already defined defsystem
1169 ;;; in the user package, we may have to shadowing-import it.
1171 #-(or :sbcl :cmu :ccl :allegro :excl :lispworks :symbolics)
1172 (eval-when (compile load eval)
1173 (import *exports* #-(or :cltl2 :lispworks) :user
1174 #+(or :cltl2 :lispworks) :common-lisp-user)
1175 (import *special-exports* #-(or :cltl2 :lispworks) :user
1176 #+(or :cltl2 :lispworks) :common-lisp-user))
1177 #+(or :sbcl :cmu :ccl :allegro :excl :lispworks :symbolics)
1178 (eval-when (compile load eval)
1179 (import *exports* #-(or :cltl2 :lispworks) :user
1180 #+(or :cltl2 :lispworks) :common-lisp-user)
1181 (shadowing-import *special-exports*
1182 #-(or :cltl2 :lispworks) :user
1183 #+(or :cltl2 :lispworks) :common-lisp-user))
1186 #-(or :pcl :clos :scl)
1187 (when (find-package :pcl)
1188 (pushnew :pcl *modules*)
1189 (pushnew :pcl *features*))
1191 ;;; ********************************
1192 ;;; Defsystem Version **************
1193 ;;; ********************************
1194 (defparameter *defsystem-version* "3.4 Interim 3, 2004-06-10"
1195 "Current version number/date for MK:DEFSYSTEM.")
1197 ;;; ********************************
1198 ;;; Customizable System Parameters *
1199 ;;; ********************************
1201 (defvar *dont-redefine-require*
1202 #+cmu (if (find-symbol "*MODULE-PROVIDER-FUNCTIONS*" :ext) t nil)
1203 #+(or allegro ccl clisp sbcl) t
1204 #-(or allegro ccl clisp cmu sbcl) nil
1205 "If T, prevents the redefinition of REQUIRE. This is useful for
1206 lisps that treat REQUIRE specially in the compiler.")
1208 (defvar *multiple-lisp-support* t
1209 "If T, afs-binary-directory will try to return a name dependent
1210 on the particular lisp compiler version being used.")
1212 ;;; home-subdirectory --
1213 ;;; HOME-SUBDIRECTORY is used only in *central-registry* below.
1214 ;;; Note that CMU CL 17e does not understand the ~/ shorthand for home
1215 ;;; directories.
1217 ;;; Note:
1218 ;;; 20020220 Marco Antoniotti
1219 ;;; The #-cormanlisp version is the original one, which is broken anyway, since
1220 ;;; it is UNIX dependent.
1221 ;;; I added the kludgy #+cormalisp (v 1.5) one, since it is missing
1222 ;;; the ANSI USER-HOMEDIR-PATHNAME function.
1223 #-cormanlisp
1224 (defun home-subdirectory (directory)
1225 (concatenate 'string
1226 #+(or :sbcl :cmu)
1227 "home:"
1228 #+scl "file://home/"
1229 #-(or :sbcl :cmu :scl)
1230 (let ((homedir (user-homedir-pathname)))
1231 (or (and homedir (namestring homedir))
1232 "~/"))
1233 directory))
1235 #+cormanlisp
1236 (defun home-subdirectory (directory)
1237 (declare (type string directory))
1238 (concatenate 'string "C:\\" directory))
1240 ;;; The following function is available for users to add
1241 ;;; (setq mk:*central-registry* (defsys-env-search-path))
1242 ;;; to Lisp init files in order to use the value of the DEFSYSPATH
1243 ;;; instead of directly coding it in the file.
1244 #+:allegro
1245 (defun defsys-env-search-path ()
1246 "This function grabs the value of the DEFSYSPATH environment variable
1247 and breaks the search path into a list of paths."
1248 (remove-duplicates (split-string (sys:getenv "DEFSYSPATH") :item #\:)
1249 :test #'string-equal))
1251 ;;; Change this variable to set up the location of a central
1252 ;;; repository for system definitions if you want one.
1253 ;;; This is a defvar to allow users to change the value in their
1254 ;;; lisp init files without worrying about it reverting if they
1255 ;;; reload defsystem for some reason.
1257 ;;; Note that if a form is included in the registry list, it will be evaluated
1258 ;;; in COMPUTE-SYSTEM-PATH to return the appropriate directory to check.
1260 (defvar *central-registry*
1261 `(;; Current directory
1262 "./"
1263 #+:LUCID (working-directory)
1264 #+ACLPC (current-directory)
1265 #+:allegro (excl:current-directory)
1266 #+:sbcl (progn *default-pathname-defaults*)
1267 #+(or :cmu :scl) (ext:default-directory)
1268 ;; *** Marco Antoniotti <marcoxa@icsi.berkeley.edu>
1269 ;; Somehow it is better to qualify default-directory in CMU with
1270 ;; the appropriate package (i.e. "EXTENSIONS".)
1271 ;; Same for Allegro.
1272 #+(and :lispworks (not :lispworks4))
1273 ,(multiple-value-bind (major minor)
1274 #-:lispworks-personal-edition
1275 (values system::*major-version-number*
1276 system::*minor-version-number*)
1277 #+:lispworks-personal-edition
1278 (values system::*major-version-number*
1279 system::*minor-version-number*)
1280 (if (or (> major 3)
1281 (and (= major 3) (> minor 2))
1282 (and (= major 3) (= minor 2)
1283 (equal (lisp-implementation-version) "3.2.1")))
1284 `(make-pathname :directory
1285 ,(find-symbol "*CURRENT-WORKING-DIRECTORY*"
1286 (find-package "SYSTEM")))
1287 (find-symbol "*CURRENT-WORKING-DIRECTORY*"
1288 (find-package "LW"))))
1289 #+:lispworks4
1290 (hcl:get-working-directory)
1291 ;; Home directory
1292 #-sbcl
1293 (mk::home-subdirectory "lisp/systems/")
1295 ;; Global registry
1296 "/usr/local/lisp/Registry/")
1297 "Central directory of system definitions. May be either a single
1298 directory pathname, or a list of directory pathnames to be checked
1299 after the local directory.")
1302 (defun add-registry-location (pathname)
1303 "Adds a path to the central registry."
1304 (pushnew pathname *central-registry* :test #'equal))
1306 (defvar *bin-subdir* ".bin/"
1307 "The subdirectory of an AFS directory where the binaries are really kept.")
1309 ;;; These variables set up defaults for operate-on-system, and are used
1310 ;;; for communication in lieu of parameter passing. Yes, this is bad,
1311 ;;; but it keeps the interface small. Also, in the case of the -if-no-binary
1312 ;;; variables, parameter passing would require multiple value returns
1313 ;;; from some functions. Why make life complicated?
1314 (defvar *tell-user-when-done* nil
1315 "If T, system will print ...DONE at the end of an operation")
1316 (defvar *oos-verbose* nil
1317 "Operate on System Verbose Mode")
1318 (defvar *oos-test* nil
1319 "Operate on System Test Mode")
1320 (defvar *load-source-if-no-binary* nil
1321 "If T, system will try loading the source if the binary is missing")
1322 (defvar *bother-user-if-no-binary* t
1323 "If T, the system will ask the user whether to load the source if
1324 the binary is missing")
1325 (defvar *load-source-instead-of-binary* nil
1326 "If T, the system will load the source file instead of the binary.")
1327 (defvar *compile-during-load* :query
1328 "If T, the system will compile source files during load if the
1329 binary file is missing. If :query, it will ask the user for
1330 permission first.")
1331 (defvar *minimal-load* nil
1332 "If T, the system tries to avoid reloading files that were already loaded
1333 and up to date.")
1335 (defvar *files-missing-is-an-error* t
1336 "If both the source and binary files are missing, signal a continuable
1337 error instead of just a warning.")
1339 (defvar *operations-propagate-to-subsystems* t
1340 "If T, operations like :COMPILE and :LOAD propagate to subsystems
1341 of a system that are defined either using a component-type of :system
1342 or by another defsystem form.")
1344 ;;; Particular to CMULisp
1345 (defvar *compile-error-file-type* "err"
1346 "File type of compilation error file in cmulisp")
1347 (defvar *cmu-errors-to-terminal* t
1348 "Argument to :errors-to-terminal in compile-file in cmulisp")
1349 (defvar *cmu-errors-to-file* t
1350 "If T, cmulisp will write an error file during compilation")
1352 ;;; ********************************
1353 ;;; Global Variables ***************
1354 ;;; ********************************
1356 ;;; Massage people's *features* into better shape.
1357 (eval-when (compile load eval)
1358 (dolist (feature *features*)
1359 (when (and (symbolp feature) ; 3600
1360 (equal (symbol-name feature) "CMU"))
1361 (pushnew :CMU *features*)))
1363 #+Lucid
1364 (when (search "IBM RT PC" (machine-type))
1365 (pushnew :ibm-rt-pc *features*))
1368 ;;; *filename-extensions* is a cons of the source and binary extensions.
1369 (defvar *filename-extensions*
1370 (car `(#+(and Symbolics Lispm) ("lisp" . "bin")
1371 #+(and dec common vax (not ultrix)) ("LSP" . "FAS")
1372 #+(and dec common vax ultrix) ("lsp" . "fas")
1373 #+ACLPC ("lsp" . "fsl")
1374 #+CLISP ("lisp" . "fas")
1375 #+KCL ("lsp" . "o")
1376 #+ECL ("lsp" . #+msvc "obj" #-msvc "fas")
1377 #+IBCL ("lsp" . "o")
1378 #+Xerox ("lisp" . "dfasl")
1379 ;; Lucid on Silicon Graphics
1380 #+(and Lucid MIPS) ("lisp" . "mbin")
1381 ;; the entry for (and lucid hp300) must precede
1382 ;; that of (and lucid mc68000) for hp9000/300's running lucid,
1383 ;; since *features* on hp9000/300's also include the :mc68000
1384 ;; feature.
1385 #+(and lucid hp300) ("lisp" . "6bin")
1386 #+(and Lucid MC68000) ("lisp" . "lbin")
1387 #+(and Lucid Vax) ("lisp" . "vbin")
1388 #+(and Lucid Prime) ("lisp" . "pbin")
1389 #+(and Lucid SUNRise) ("lisp" . "sbin")
1390 #+(and Lucid SPARC) ("lisp" . "sbin")
1391 #+(and Lucid :IBM-RT-PC) ("lisp" . "bbin")
1392 ;; PA is Precision Architecture, HP's 9000/800 RISC cpu
1393 #+(and Lucid PA) ("lisp" . "hbin")
1394 #+excl ("cl" . ,(pathname-type (compile-file-pathname "foo.cl")))
1395 #+(or cmu scl) ("lisp" . ,(or (c:backend-fasl-file-type c:*backend*) "fasl"))
1396 ; #+(and :CMU (not (or :sgi :sparc))) ("lisp" . "fasl")
1397 ; #+(and :CMU :sgi) ("lisp" . "sgif")
1398 ; #+(and :CMU :sparc) ("lisp" . "sparcf")
1399 #+PRIME ("lisp" . "pbin")
1400 #+HP ("l" . "b")
1401 #+TI ("lisp" . #.(string (si::local-binary-file-type)))
1402 #+:gclisp ("LSP" . "F2S")
1403 #+pyramid ("clisp" . "o")
1405 ;; Harlequin LispWorks
1406 #+:lispworks ("lisp" . ,COMPILER:*FASL-EXTENSION-STRING*)
1407 ; #+(and :sun4 :lispworks) ("lisp" . "wfasl")
1408 ; #+(and :mips :lispworks) ("lisp" . "mfasl")
1409 #+:mcl ("lisp" . ,(pathname-type (compile-file-pathname "foo.lisp")))
1410 #+:coral ("lisp" . "fasl")
1412 ;; Otherwise,
1413 ("lisp" . ,(pathname-type (compile-file-pathname "foo.lisp")))))
1414 "Filename extensions for Common Lisp. A cons of the form
1415 (Source-Extension . Binary-Extension). If the system is
1416 unknown (as in *features* not known), defaults to lisp and fasl.")
1418 (defvar *system-extension*
1419 ;; MS-DOS systems can only handle three character extensions.
1420 #-ACLPC "system"
1421 #+ACLPC "sys"
1422 "The filename extension to use with systems.")
1424 ;;; The above variables and code should be extended to allow a list of
1425 ;;; valid extensions for each lisp implementation, instead of a single
1426 ;;; extension. When writing a file, the first extension should be used.
1427 ;;; But when searching for a file, every extension in the list should
1428 ;;; be used. For example, CMU Common Lisp recognizes "lisp" "l" "cl" and
1429 ;;; "lsp" (*load-source-types*) as source code extensions, and
1430 ;;; (c:backend-fasl-file-type c:*backend*)
1431 ;;; (c:backend-byte-fasl-file-type c:*backend*)
1432 ;;; and "fasl" as binary (object) file extensions (*load-object-types*).
1434 ;;; Note that the above code is used below in the LANGUAGE defstruct.
1436 ;;; There is no real support for this variable being nil, so don't change it.
1437 ;;; Note that in any event, the toplevel system (defined with defsystem)
1438 ;;; will have its dependencies delayed. Not having dependencies delayed
1439 ;;; might be useful if we define several systems within one defsystem.
1440 (defvar *system-dependencies-delayed* t
1441 "If T, system dependencies are expanded at run time")
1443 ;;; Replace this with consp, dammit!
1444 (defun non-empty-listp (list)
1445 (and list (listp list)))
1447 ;;; ********************************
1448 ;;; Component Operation Definition *
1449 ;;; ********************************
1450 (eval-when (:compile-toplevel :load-toplevel :execute)
1451 (defvar *version-dir* nil
1452 "The version subdir. bound in operate-on-system.")
1453 (defvar *version-replace* nil
1454 "The version replace. bound in operate-on-system.")
1455 (defvar *version* nil
1456 "Default version."))
1458 (defvar *component-operations* (make-hash-table :test #'equal)
1459 "Hash table of (operation-name function) pairs.")
1460 (defun component-operation (name &optional operation)
1461 (if operation
1462 (setf (gethash name *component-operations*) operation)
1463 (gethash name *component-operations*)))
1465 ;;; ********************************
1466 ;;; AFS @sys immitator *************
1467 ;;; ********************************
1469 ;;; mc 11-Apr-91: Bashes MCL's point reader, so commented out.
1470 #-:mcl
1471 (eval-when (compile load eval)
1472 ;; Define #@"foo" as a shorthand for (afs-binary-directory "foo").
1473 ;; For example,
1474 ;; <cl> #@"foo"
1475 ;; "foo/.bin/rt_mach/"
1476 (set-dispatch-macro-character
1477 #\# #\@
1478 #'(lambda (stream char arg)
1479 (declare (ignore char arg))
1480 `(afs-binary-directory ,(read stream t nil t)))))
1482 (defvar *find-irix-version-script*
1483 "\"1,4 d\\
1484 s/^[^M]*IRIX Execution Environment 1, *[a-zA-Z]* *\\([^ ]*\\)/\\1/p\\
1485 /./,$ d\\
1486 \"")
1488 (defun operating-system-version ()
1489 #+(and :sgi :excl)
1490 (let* ((full-version (software-version))
1491 (blank-pos (search " " full-version))
1492 (os (subseq full-version 0 blank-pos))
1493 (version-rest (subseq full-version
1494 (1+ blank-pos)))
1495 os-version)
1496 (setq blank-pos (search " " version-rest))
1497 (setq version-rest (subseq version-rest
1498 (1+ blank-pos)))
1499 (setq blank-pos (search " " version-rest))
1500 (setq os-version (subseq version-rest 0 blank-pos))
1501 (setq version-rest (subseq version-rest
1502 (1+ blank-pos)))
1503 (setq blank-pos (search " " version-rest))
1504 (setq version-rest (subseq version-rest
1505 (1+ blank-pos)))
1506 (concatenate 'string
1507 os " " os-version)) ; " " version-rest
1508 #+(and :sgi :cmu :sbcl)
1509 (concatenate 'string
1510 (software-type)
1511 (software-version))
1512 #+(and :lispworks :irix)
1513 (let ((soft-type (software-type)))
1514 (if (equalp soft-type "IRIX5")
1515 (progn
1516 (foreign:call-system
1517 (format nil "versions ~A | sed -e ~A > ~A"
1518 "eoe1"
1519 *find-irix-version-script*
1520 "irix-version")
1521 "/bin/csh")
1522 (with-open-file (s "irix-version")
1523 (format nil "IRIX ~S"
1524 (read s))))
1525 soft-type))
1526 #-(or (and :excl :sgi) (and :cmu :sgi) (and :lispworks :irix))
1527 (software-type))
1529 (defun compiler-version ()
1530 #+:lispworks (concatenate 'string
1531 "lispworks" " " (lisp-implementation-version))
1532 #+excl (concatenate 'string
1533 "excl" " " excl::*common-lisp-version-number*)
1534 #+sbcl (concatenate 'string
1535 "sbcl" " " (lisp-implementation-version))
1536 #+cmu (concatenate 'string
1537 "cmu" " " (lisp-implementation-version))
1538 #+scl (concatenate 'string
1539 "scl" " " (lisp-implementation-version))
1541 #+kcl "kcl"
1542 #+IBCL "ibcl"
1543 #+akcl "akcl"
1544 #+gcl "gcl"
1545 #+ecl "ecl"
1546 #+lucid "lucid"
1547 #+ACLPC "aclpc"
1548 #+CLISP "clisp"
1549 #+Xerox "xerox"
1550 #+symbolics "symbolics"
1551 #+mcl "mcl"
1552 #+coral "coral"
1553 #+gclisp "gclisp"
1556 (defun afs-binary-directory (root-directory)
1557 ;; Function for obtaining the directory AFS's @sys feature would have
1558 ;; chosen when we're not in AFS. This function is useful as the argument
1559 ;; to :binary-pathname in defsystem. For example,
1560 ;; :binary-pathname (afs-binary-directory "scanner/")
1561 (let ((machine (machine-type-translation
1562 #-(and :sgi :allegro-version>= (version>= 4 2))
1563 (machine-type)
1564 #+(and :sgi :allegro-version>= (version>= 4 2))
1565 (machine-version)))
1566 (software (software-type-translation
1567 #-(and :sgi (or :cmu :sbcl :scl
1568 (and :allegro-version>= (version>= 4 2))))
1569 (software-type)
1570 #+(and :sgi (or :cmu :sbcl :scl
1571 (and :allegro-version>= (version>= 4 2))))
1572 (operating-system-version)))
1573 (lisp (compiler-type-translation (compiler-version))))
1574 ;; pmax_mach rt_mach sun3_35 sun3_mach vax_mach
1575 (setq root-directory (namestring root-directory))
1576 (setq root-directory (ensure-trailing-slash root-directory))
1577 (format nil "~A~@[~A~]~@[~A/~]"
1578 root-directory
1579 *bin-subdir*
1580 (if *multiple-lisp-support*
1581 (afs-component machine software lisp)
1582 (afs-component machine software)))))
1584 (defun afs-source-directory (root-directory &optional version-flag)
1585 ;; Function for obtaining the directory AFS's @sys feature would have
1586 ;; chosen when we're not in AFS. This function is useful as the argument
1587 ;; to :source-pathname in defsystem.
1588 (setq root-directory (namestring root-directory))
1589 (setq root-directory (ensure-trailing-slash root-directory))
1590 (format nil "~A~@[~A/~]"
1591 root-directory
1592 (and version-flag (translate-version *version*))))
1594 (defun null-string (s)
1595 (when (stringp s)
1596 (string-equal s "")))
1598 (defun ensure-trailing-slash (dir)
1599 (if (and dir
1600 (not (null-string dir))
1601 (not (char= (char dir
1602 (1- (length dir)))
1603 #\/))
1604 (not (char= (char dir
1605 (1- (length dir)))
1606 #\\))
1608 (concatenate 'string dir "/")
1609 dir))
1611 (defun afs-component (machine software &optional lisp)
1612 (format nil "~@[~A~]~@[_~A~]~@[_~A~]"
1613 machine
1614 (or software "mach")
1615 lisp))
1617 (defvar *machine-type-alist* (make-hash-table :test #'equal)
1618 "Hash table for retrieving the machine-type")
1619 (defun machine-type-translation (name &optional operation)
1620 (if operation
1621 (setf (gethash (string-upcase name) *machine-type-alist*) operation)
1622 (gethash (string-upcase name) *machine-type-alist*)))
1624 (machine-type-translation "IBM RT PC" "rt")
1625 (machine-type-translation "DEC 3100" "pmax")
1626 (machine-type-translation "DEC VAX-11" "vax")
1627 (machine-type-translation "DECstation" "pmax")
1628 (machine-type-translation "Sun3" "sun3")
1629 (machine-type-translation "Sun-4" "sun4")
1630 (machine-type-translation "MIPS Risc" "mips")
1631 (machine-type-translation "SGI" "sgi")
1632 (machine-type-translation "Silicon Graphics Iris 4D" "sgi")
1633 (machine-type-translation "Silicon Graphics Iris 4D (R3000)" "sgi")
1634 (machine-type-translation "Silicon Graphics Iris 4D (R4000)" "sgi")
1635 (machine-type-translation "Silicon Graphics Iris 4D (R4400)" "sgi")
1636 (machine-type-translation "IP22" "sgi")
1637 ;;; MIPS R4000 Processor Chip Revision: 3.0
1638 ;;; MIPS R4400 Processor Chip Revision: 5.0
1639 ;;; MIPS R4600 Processor Chip Revision: 1.0
1640 (machine-type-translation "IP20" "sgi")
1641 ;;; MIPS R4000 Processor Chip Revision: 3.0
1642 (machine-type-translation "IP17" "sgi")
1643 ;;; MIPS R4000 Processor Chip Revision: 2.2
1644 (machine-type-translation "IP12" "sgi")
1645 ;;; MIPS R2000A/R3000 Processor Chip Revision: 3.0
1646 (machine-type-translation "IP7" "sgi")
1647 ;;; MIPS R2000A/R3000 Processor Chip Revision: 3.0
1649 (machine-type-translation "x86" "x86")
1650 ;;; ACL
1651 (machine-type-translation "IBM PC Compatible" "x86")
1652 ;;; LW
1653 (machine-type-translation "I686" "x86")
1654 ;;; LW
1655 (machine-type-translation "PC/386" "x86")
1656 ;;; CLisp Win32
1658 ;;; SCL.
1659 (machine-type-translation "AMD64" "amd64")
1661 #+(and :lucid :sun :mc68000)
1662 (machine-type-translation "unknown" "sun3")
1665 (defvar *software-type-alist* (make-hash-table :test #'equal)
1666 "Hash table for retrieving the software-type")
1667 (defun software-type-translation (name &optional operation)
1668 (if operation
1669 (setf (gethash (string-upcase name) *software-type-alist*) operation)
1670 (gethash (string-upcase name) *software-type-alist*)))
1672 (software-type-translation "BSD UNIX" "mach") ; "unix"
1673 (software-type-translation "Ultrix" "mach") ; "ultrix"
1674 (software-type-translation "SunOS" "SunOS")
1675 (software-type-translation "MACH/4.3BSD" "mach")
1676 (software-type-translation "IRIX System V" "irix") ; (software-type)
1677 (software-type-translation "IRIX5" "irix5")
1678 ;;(software-type-translation "IRIX liasg5 5.2 02282016 IP22 mips" "irix5") ; (software-version)
1680 (software-type-translation "IRIX 5.2" "irix5")
1681 (software-type-translation "IRIX 5.3" "irix5")
1682 (software-type-translation "IRIX5.2" "irix5")
1683 (software-type-translation "IRIX5.3" "irix5")
1685 (software-type-translation "Linux" "linux") ; Lispworks for Linux
1686 (software-type-translation "Linux 2.x, Redhat 6.x and 7.x" "linux") ; ACL
1687 (software-type-translation "Microsoft Windows 9x/Me and NT/2000/XP" "win32")
1688 (software-type-translation "Windows NT" "win32") ; LW for Windows
1689 (software-type-translation "ANSI C program" "ansi-c") ; CLISP
1690 (software-type-translation "C compiler" "ansi-c") ; CLISP for Win32
1692 (software-type-translation nil "")
1694 #+:lucid
1695 (software-type-translation "Unix"
1696 #+:lcl4.0 "4.0"
1697 #+(and :lcl3.0 (not :lcl4.0)) "3.0")
1699 (defvar *compiler-type-alist* (make-hash-table :test #'equal)
1700 "Hash table for retrieving the Common Lisp type")
1701 (defun compiler-type-translation (name &optional operation)
1702 (if operation
1703 (setf (gethash (string-upcase name) *compiler-type-alist*) operation)
1704 (gethash (string-upcase name) *compiler-type-alist*)))
1706 (compiler-type-translation "lispworks 3.2.1" "lispworks")
1707 (compiler-type-translation "lispworks 3.2.60 beta 6" "lispworks")
1708 (compiler-type-translation "lispworks 4.2.0" "lispworks")
1710 #+allegro
1711 (eval-when (:compile-toplevel :load-toplevel :execute)
1712 (unless (or (find :case-sensitive common-lisp:*features*)
1713 (find :case-insensitive common-lisp:*features*))
1714 (if (or (eq excl:*current-case-mode* :case-sensitive-lower)
1715 (eq excl:*current-case-mode* :case-sensitive-upper))
1716 (push :case-sensitive common-lisp:*features*)
1717 (push :case-insensitive common-lisp:*features*))))
1720 #+(and allegro case-sensitive ics)
1721 (compiler-type-translation "excl 6.1" "excl-m")
1722 #+(and allegro case-sensitive (not ics))
1723 (compiler-type-translation "excl 6.1" "excl-m8")
1725 #+(and allegro case-insensitive ics)
1726 (compiler-type-translation "excl 6.1" "excl-a")
1727 #+(and allegro case-insensitive (not ics))
1728 (compiler-type-translation "excl 6.1" "excl-a8")
1730 (compiler-type-translation "excl 4.2" "excl")
1731 (compiler-type-translation "excl 4.1" "excl")
1732 (compiler-type-translation "cmu 17f" "cmu")
1733 (compiler-type-translation "cmu 17e" "cmu")
1734 (compiler-type-translation "cmu 17d" "cmu")
1736 (compiler-type-translation "scl 1.2.7" "scl")
1737 (compiler-type-translation "scl 1.2.8" "scl")
1738 (compiler-type-translation "scl 1.2.9" "scl")
1740 ;;; ********************************
1741 ;;; System Names *******************
1742 ;;; ********************************
1744 ;;; If you use strings for system names, be sure to use the same case
1745 ;;; as it appears on disk, if the filesystem is case sensitive.
1746 (defun canonicalize-system-name (name)
1747 ;; Originally we were storing systems using GET. This meant that the
1748 ;; name of a system had to be a symbol, so we interned the symbols
1749 ;; in the keyword package to avoid package dependencies. Now that we're
1750 ;; storing the systems in a hash table, we've switched to using strings.
1751 ;; Since the hash table is case sensitive, we use uppercase strings.
1752 ;; (Names of modules and files may be symbols or strings.)
1753 #||(if (keywordp name)
1754 name
1755 (intern (string-upcase (string name)) "KEYWORD"))||#
1756 (if (stringp name) (string-upcase name) (string-upcase (string name))))
1758 (defvar *defined-systems* (make-hash-table :test #'equal)
1759 "Hash table containing the definitions of all known systems.")
1761 (defun get-system (name)
1762 "Returns the definition of the system named NAME."
1763 (gethash (canonicalize-system-name name) *defined-systems*))
1765 (defsetf get-system (name) (value)
1766 `(setf (gethash (canonicalize-system-name ,name) *defined-systems*) ,value))
1768 (defun undefsystem (name)
1769 "Removes the definition of the system named NAME."
1770 (setf (get-system name) nil))
1772 (defun defined-systems ()
1773 "Returns a list of defined systems."
1774 (let ((result nil))
1775 (maphash #'(lambda (key value)
1776 (declare (ignore key))
1777 (push value result))
1778 *defined-systems*)
1779 result))
1781 ;;; ********************************
1782 ;;; Directory Pathname Hacking *****
1783 ;;; ********************************
1785 ;;; Unix example: An absolute directory starts with / while a
1786 ;;; relative directory doesn't. A directory ends with /, while
1787 ;;; a file's pathname doesn't. This is important 'cause
1788 ;;; (pathname-directory "foo/bar") will return "foo" and not "foo/".
1790 ;;; I haven't been able to test the fix to the problem with symbolics
1791 ;;; hosts. Essentially, append-directories seems to have been tacking
1792 ;;; the default host onto the front of the pathname (e.g., mk::source-pathname
1793 ;;; gets a "B:" on front) and this overrides the :host specified in the
1794 ;;; component. The value of :host should override that specified in
1795 ;;; the :source-pathname and the default file server. If this doesn't
1796 ;;; fix things, specifying the host in the root pathname "F:>root-dir>"
1797 ;;; may be a good workaround.
1799 ;;; Need to verify that merging of pathnames where modules are located
1800 ;;; on different devices (in VMS-based VAXLisp) now works.
1802 ;;; Merge-pathnames works for VMS systems. In VMS systems, the directory
1803 ;;; part is enclosed in square brackets, e.g.,
1804 ;;; "[root.child.child_child]" or "[root.][child.][child_child]"
1805 ;;; To concatenate directories merge-pathnames works as follows:
1806 ;;; (merge-pathnames "" "[root]") ==> "[root]"
1807 ;;; (merge-pathnames "[root.]" "[son]file.ext") ==> "[root.son]file.ext"
1808 ;;; (merge-pathnames "[root.]file.ext" "[son]") ==> "[root.son]file.ext"
1809 ;;; (merge-pathnames "[root]file.ext" "[son]") ==> "[root]file.ext"
1810 ;;; Thus the problem with the #-VMS code was that it was merging x y into
1811 ;;; [[x]][y] instead of [x][y] or [x]y.
1813 ;;; Miscellaneous notes:
1814 ;;; On GCLisp, the following are equivalent:
1815 ;;; "\\root\\subdir\\BAZ"
1816 ;;; "/root/subdir/BAZ"
1817 ;;; On VAXLisp, the following are equivalent:
1818 ;;; "[root.subdir]BAZ"
1819 ;;; "[root.][subdir]BAZ"
1820 ;;; Use #+:vaxlisp for VAXLisp 3.0, #+(and vms dec common vax) for v2.2
1821 #-scl
1822 (defun new-append-directories (absolute-dir relative-dir)
1823 ;; Version of append-directories for CLtL2-compliant lisps. In particular,
1824 ;; they must conform to section 23.1.3 "Structured Directories". We are
1825 ;; willing to fix minor aberations in this function, but not major ones.
1826 ;; Tested in Allegro CL 4.0 (SPARC), Allegro CL 3.1.12 (DEC 3100),
1827 ;; CMU CL old and new compilers, Lucid 3.0, Lucid 4.0.
1828 (setf absolute-dir (or absolute-dir "")
1829 relative-dir (or relative-dir ""))
1830 (let* ((abs-dir (pathname absolute-dir))
1831 (rel-dir (pathname relative-dir))
1832 (host (pathname-host abs-dir))
1833 (device (if (null-string absolute-dir) ; fix for CMU CL old compiler
1834 (pathname-device rel-dir)
1835 (pathname-device abs-dir)))
1836 (abs-directory (directory-to-list (pathname-directory abs-dir)))
1837 (abs-keyword (when (keywordp (car abs-directory))
1838 (pop abs-directory)))
1839 ;; Stig (July 2001):
1840 ;; Somehow CLISP dies on the next line, but NIL is ok.
1841 (abs-name (ignore-errors (file-namestring abs-dir))) ; was pathname-name
1842 (rel-directory (directory-to-list (pathname-directory rel-dir)))
1843 (rel-keyword (when (keywordp (car rel-directory))
1844 (pop rel-directory)))
1845 #-(or :MCL :gcl :sbcl :clisp :cmu) (rel-file (file-namestring rel-dir))
1846 ;; Stig (July 2001);
1847 ;; These values seems to help clisp as well
1848 #+(or :MCL :gcl :sbcl :clisp :cmu) (rel-name (pathname-name rel-dir))
1849 #+(or :MCL :gcl :sbcl :clisp :cmu) (rel-type (pathname-type rel-dir))
1850 (directory nil))
1852 ;; TI Common Lisp pathnames can return garbage for file names because
1853 ;; of bizarreness in the merging of defaults. The following code makes
1854 ;; sure that the name is a valid name by comparing it with the
1855 ;; pathname-name. It also strips TI specific extensions and handles
1856 ;; the necessary case conversion. TI maps upper back into lower case
1857 ;; for unix files!
1858 #+TI (if (search (pathname-name abs-dir) abs-name :test #'string-equal)
1859 (setf abs-name (string-right-trim ".\x17" (string-upcase abs-name)))
1860 (setf abs-name nil))
1861 #+TI (if (search (pathname-name rel-dir) rel-file :test #'string-equal)
1862 (setf rel-file (string-right-trim ".\x17" (string-upcase rel-file)))
1863 (setf rel-file nil))
1864 ;; Allegro v4.0/4.1 parses "/foo" into :directory '(:absolute :root)
1865 ;; and filename "foo". The namestring of a pathname with
1866 ;; directory '(:absolute :root "foo") ignores everything after the
1867 ;; :root.
1868 #+(and allegro-version>= (version>= 4 0))
1869 (when (eq (car abs-directory) :root) (pop abs-directory))
1870 #+(and allegro-version>= (version>= 4 0))
1871 (when (eq (car rel-directory) :root) (pop rel-directory))
1873 (when (and abs-name (not (null-string abs-name))) ; was abs-name
1874 (cond ((and (null abs-directory) (null abs-keyword))
1875 #-(or :lucid TI) (setf abs-keyword (car (pathname-directory "./")))
1876 (setf abs-directory (list abs-name)))
1878 (setf abs-directory (append abs-directory (list abs-name))))))
1879 (when (and (null abs-directory)
1880 (or (null abs-keyword)
1881 ;; In Lucid, an abs-dir of nil gets a keyword of
1882 ;; :relative since (pathname-directory (pathname ""))
1883 ;; returns (:relative) instead of nil.
1884 #+:lucid (eq abs-keyword :relative))
1885 rel-keyword)
1886 ;; The following feature switches seem necessary in CMUCL
1887 ;; Marco Antoniotti 19990707
1888 #+(or :gcl :sbcl :CMU)
1889 (if (typep abs-dir 'logical-pathname)
1890 (setf abs-keyword :absolute)
1891 (setf abs-keyword rel-keyword))
1892 #-(or :gcl :sbcl :CMU)
1893 (setf abs-keyword rel-keyword))
1894 (setf directory (append abs-directory rel-directory))
1895 (when abs-keyword (setf directory (cons abs-keyword directory)))
1896 #+lispworks (when (and directory (not (symbolp (first directory)))) (setq directory (cons :relative directory)))
1897 (namestring
1898 (make-pathname :host host
1899 :device device
1900 :directory
1901 directory
1902 :name
1903 #-(or :gcl :sbcl :MCL :clisp :cmu) rel-file
1904 #+(or :gcl :sbcl :MCL :clisp :cmu) rel-name
1906 #+(or :gcl :sbcl :MCL :clisp :cmu) :type
1907 #+(or :gcl :sbcl :MCL :clisp :cmu) rel-type
1908 ))))
1909 ;(trace new-append-directories)
1911 #-scl
1912 (defun directory-to-list (directory)
1913 ;; The directory should be a list, but nonstandard implementations have
1914 ;; been known to use a vector or even a string.
1915 (cond ((listp directory)
1916 directory)
1917 ((stringp directory)
1918 (cond ((find #\; directory)
1919 ;; It's probably a logical pathname, so split at the
1920 ;; semicolons:
1921 (split-string directory :item #\;))
1922 #+MCL
1923 ((and (find #\: directory)
1924 (not (find #\/ directory)))
1925 ;; It's probably a MCL pathname, so split at the colons.
1926 (split-string directory :item #\:))
1928 ;; It's probably a unix pathname, so split at the slash.
1929 (split-string directory :item #\/))))
1931 (coerce directory 'list))))
1932 ;(trace directory-to-list)
1935 (defparameter *append-dirs-tests*
1936 '("~/foo/" "baz/bar.lisp"
1937 "~/foo" "baz/bar.lisp"
1938 "/foo/bar/" "baz/barf.lisp"
1939 "/foo/bar/" "/baz/barf.lisp"
1940 "foo/bar/" "baz/barf.lisp"
1941 "foo/bar" "baz/barf.lisp"
1942 "foo/bar" "/baz/barf.lisp"
1943 "foo/bar/" "/baz/barf.lisp"
1944 "/foo/bar/" nil
1945 "foo/bar/" nil
1946 "foo/bar" nil
1947 "foo" nil
1948 "foo" ""
1949 nil "baz/barf.lisp"
1950 nil "/baz/barf.lisp"
1951 nil nil))
1953 (defun test-new-append-directories (&optional (test-dirs *append-dirs-tests*))
1954 (do* ((dir-list test-dirs (cddr dir-list))
1955 (abs-dir (car dir-list) (car dir-list))
1956 (rel-dir (cadr dir-list) (cadr dir-list)))
1957 ((null dir-list) (values))
1958 (format t "~&ABS: ~S ~18TREL: ~S ~41TResult: ~S"
1959 abs-dir rel-dir (new-append-directories abs-dir rel-dir))))
1962 <cl> (test-new-append-directories)
1964 ABS: "~/foo/" REL: "baz/bar.lisp" Result: "/usr0/mkant/foo/baz/bar.lisp"
1965 ABS: "~/foo" REL: "baz/bar.lisp" Result: "/usr0/mkant/foo/baz/bar.lisp"
1966 ABS: "/foo/bar/" REL: "baz/barf.lisp" Result: "/foo/bar/baz/barf.lisp"
1967 ABS: "/foo/bar/" REL: "/baz/barf.lisp" Result: "/foo/bar/baz/barf.lisp"
1968 ABS: "foo/bar/" REL: "baz/barf.lisp" Result: "foo/bar/baz/barf.lisp"
1969 ABS: "foo/bar" REL: "baz/barf.lisp" Result: "foo/bar/baz/barf.lisp"
1970 ABS: "foo/bar" REL: "/baz/barf.lisp" Result: "foo/bar/baz/barf.lisp"
1971 ABS: "foo/bar/" REL: "/baz/barf.lisp" Result: "foo/bar/baz/barf.lisp"
1972 ABS: "/foo/bar/" REL: NIL Result: "/foo/bar/"
1973 ABS: "foo/bar/" REL: NIL Result: "foo/bar/"
1974 ABS: "foo/bar" REL: NIL Result: "foo/bar/"
1975 ABS: "foo" REL: NIL Result: "foo/"
1976 ABS: "foo" REL: "" Result: "foo/"
1977 ABS: NIL REL: "baz/barf.lisp" Result: "baz/barf.lisp"
1978 ABS: NIL REL: "/baz/barf.lisp" Result: "/baz/barf.lisp"
1979 ABS: NIL REL: NIL Result: ""
1983 (defun append-directories (absolute-directory relative-directory)
1984 "There is no CL primitive for tacking a subdirectory onto a directory.
1985 We need such a function because defsystem has both absolute and
1986 relative pathnames in the modules. This is a somewhat ugly hack which
1987 seems to work most of the time. We assume that ABSOLUTE-DIRECTORY
1988 is a directory, with no filename stuck on the end. Relative-directory,
1989 however, may have a filename stuck on the end."
1990 (when (or absolute-directory relative-directory)
1991 (cond
1992 ;; KMR commented out because: when appending two logical pathnames,
1993 ;; using this code translates the first logical pathname then appends
1994 ;; the second logical pathname -- an error.
1996 ;; We need a reliable way to determine if a pathname is logical.
1997 ;; Allegro 4.1 does not recognize the syntax of a logical pathname
1998 ;; as being logical unless its logical host is already defined.
2000 #+(or (and allegro-version>= (version>= 4 1))
2001 :logical-pathnames-mk)
2002 ((and absolute-directory
2003 (logical-pathname-p absolute-directory)
2004 relative-directory)
2005 ;; For use with logical pathnames package.
2006 (append-logical-directories-mk absolute-directory relative-directory))
2008 #-scl
2009 ((namestring-probably-logical absolute-directory)
2010 ;; A simplistic stab at handling logical pathnames
2011 (append-logical-pnames absolute-directory relative-directory))
2012 #-scl
2014 ;; In VMS, merge-pathnames actually does what we want!!!
2015 #+:VMS
2016 (namestring (merge-pathnames (or absolute-directory "")
2017 (or relative-directory "")))
2018 #+:macl1.3.2
2019 (namestring (make-pathname :directory absolute-directory
2020 :name relative-directory))
2021 ;; Cross your fingers and pray.
2022 #-(or :VMS :macl1.3.2)
2023 (new-append-directories absolute-directory relative-directory))
2024 #+scl
2026 (let ((absolute (pathname (or absolute-directory ""))))
2027 (when (or (pathname-name absolute) (pathname-type absolute))
2028 (let* ((directory (or (pathname-directory absolute) '(:relative)))
2029 (directory (append directory (list (file-namestring absolute)))))
2030 (setf absolute (make-pathname :directory directory
2031 :name nil
2032 :type nil
2033 :version nil
2034 :defaults absolute))))
2035 (ext:resolve-pathname (or relative-directory "")
2036 absolute))))))
2039 #+:logical-pathnames-mk
2040 (defun append-logical-directories-mk (absolute-dir relative-dir)
2041 (lp:append-logical-directories absolute-dir relative-dir))
2044 ;;; append-logical-pathnames-mk --
2045 ;;; The following is probably still bogus and it does not solve the
2046 ;;; problem of appending two logical pathnames.
2047 ;;; Anyway, as per suggetsion by KMR, the function is not called
2048 ;;; anymore.
2049 ;;; Hopefully this will not cause problems for ACL.
2051 #+(and (and allegro-version>= (version>= 4 1))
2052 (not :logical-pathnames-mk))
2053 (defun append-logical-directories-mk (absolute-dir relative-dir)
2054 ;; We know absolute-dir and relative-dir are non nil. Moreover
2055 ;; absolute-dir is a logical pathname.
2056 (setq absolute-dir (logical-pathname absolute-dir))
2057 (etypecase relative-dir
2058 (string (setq relative-dir (parse-namestring relative-dir)))
2059 (pathname #| do nothing |#))
2061 (translate-logical-pathname
2062 (merge-pathnames relative-dir absolute-dir)))
2064 #| Old version 2002-03-02
2065 #+(and (and allegro-version>= (version>= 4 1))
2066 (not :logical-pathnames-mk))
2067 (defun append-logical-directories-mk (absolute-dir relative-dir)
2068 ;; We know absolute-dir and relative-dir are non nil. Moreover
2069 ;; absolute-dir is a logical pathname.
2070 (setq absolute-dir (logical-pathname absolute-dir))
2071 (etypecase relative-dir
2072 (string (setq relative-dir (parse-namestring relative-dir)))
2073 (pathname #| do nothing |#))
2075 (translate-logical-pathname
2076 (make-pathname
2077 :host (or (pathname-host absolute-dir)
2078 (pathname-host relative-dir))
2079 :directory (append (pathname-directory absolute-dir)
2080 (cdr (pathname-directory relative-dir)))
2081 :name (or (pathname-name absolute-dir)
2082 (pathname-name relative-dir))
2083 :type (or (pathname-type absolute-dir)
2084 (pathname-type relative-dir))
2085 :version (or (pathname-version absolute-dir)
2086 (pathname-version relative-dir)))))
2088 ;; Old version
2089 #+(and (and allegro-version>= (version>= 4 1))
2090 (not :logical-pathnames-mk))
2091 (defun append-logical-directories-mk (absolute-dir relative-dir)
2092 (when (or absolute-dir relative-dir)
2093 (setq absolute-dir (logical-pathname (or absolute-dir ""))
2094 relative-dir (logical-pathname (or relative-dir "")))
2095 (translate-logical-pathname
2096 (make-pathname
2097 :host (or (pathname-host absolute-dir)
2098 (pathname-host relative-dir))
2099 :directory (append (pathname-directory absolute-dir)
2100 (cdr (pathname-directory relative-dir)))
2101 :name (or (pathname-name absolute-dir)
2102 (pathname-name relative-dir))
2103 :type (or (pathname-type absolute-dir)
2104 (pathname-type relative-dir))
2105 :version (or (pathname-version absolute-dir)
2106 (pathname-version relative-dir))))))
2109 ;;; determines if string or pathname object is logical
2110 #+:logical-pathnames-mk
2111 (defun logical-pathname-p (thing)
2112 (eq (lp:pathname-host-type thing) :logical))
2114 ;;; From Kevin Layer for 4.1final.
2115 #+(and (and allegro-version>= (version>= 4 1))
2116 (not :logical-pathnames-mk))
2117 (defun logical-pathname-p (thing)
2118 (typep (parse-namestring thing) 'logical-pathname))
2120 #-scl
2121 (defun pathname-logical-p (thing)
2122 (typecase thing
2123 (logical-pathname t)
2124 #+clisp ; CLisp has non conformant Logical Pathnames.
2125 (pathname (pathname-logical-p (namestring thing)))
2126 (string (and (= 1 (count #\: thing)) ; Shortcut.
2127 (ignore-errors (translate-logical-pathname thing))
2129 (t nil)))
2131 ;;; This affects only one thing.
2132 ;;; 19990707 Marco Antoniotti
2133 ;;; old version
2135 #-scl
2136 (defun namestring-probably-logical (namestring)
2137 (and (stringp namestring)
2138 ;; unix pathnames don't have embedded semicolons
2139 (find #\; namestring)))
2141 ;;; New version
2142 (defun namestring-probably-logical (namestring)
2143 (and (stringp namestring)
2144 (typep (parse-namestring namestring) 'logical-pathname)))
2147 ;;; New new version
2148 ;;; 20000321 Marco Antoniotti
2149 (defun namestring-probably-logical (namestring)
2150 (pathname-logical-p namestring))
2154 #|| This is incorrect, as it strives to keep strings around, when it
2155 shouldn't. MERGE-PATHNAMES already DTRT.
2156 (defun append-logical-pnames (absolute relative)
2157 (declare (type (or null string pathname) absolute relative))
2158 (let ((abs (if absolute
2159 #-clisp (namestring absolute)
2160 #+clisp absolute ;; Stig (July 2001): hack to avoid CLISP from translating the whole string
2161 ""))
2162 (rel (if relative (namestring relative) ""))
2164 ;; Make sure the absolute directory ends with a semicolon unless
2165 ;; the pieces are null strings
2166 (unless (or (null-string abs) (null-string rel)
2167 (char= (char abs (1- (length abs)))
2168 #\;))
2169 (setq abs (concatenate 'string abs ";")))
2170 ;; Return the concatenate pathnames
2171 (concatenate 'string abs rel)))
2175 #-scl
2176 (defun append-logical-pnames (absolute relative)
2177 (declare (type (or null string pathname) absolute relative))
2178 (let ((abs (if absolute
2179 (pathname absolute)
2180 (make-pathname :directory (list :absolute)
2181 :name nil
2182 :type nil)
2184 (rel (if relative
2185 (pathname relative)
2186 (make-pathname :directory (list :relative)
2187 :name nil
2188 :type nil)
2191 ;; The following is messed up because CMUCL and LW use different
2192 ;; defaults for host (in particular LW uses NIL). Thus
2193 ;; MERGE-PATHNAMES has legitimate different behaviors on both
2194 ;; implementations. Of course this is disgusting, but that is the
2195 ;; way it is and the rest tries to circumvent this crap.
2196 (etypecase abs
2197 (logical-pathname
2198 (etypecase rel
2199 (logical-pathname
2200 (namestring (merge-pathnames rel abs)))
2201 (pathname
2202 ;; The following potentially translates the logical pathname
2203 ;; very early, but we cannot avoid it.
2204 (namestring (merge-pathnames rel (translate-logical-pathname abs))))
2206 (pathname
2207 (namestring (merge-pathnames rel abs)))
2211 ;;; This was a try at appending a subdirectory onto a directory.
2212 ;;; It failed. We're keeping this around to prevent future mistakes
2213 ;;; of a similar sort.
2214 (defun merge-directories (absolute-directory relative-directory)
2215 ;; replace concatenate with something more intelligent
2216 ;; i.e., concatenation won't work with some directories.
2217 ;; it should also behave well if the parent directory
2218 ;; has a filename at the end, or if the relative-directory ain't relative
2219 (when absolute-directory
2220 (setq absolute-directory (pathname-directory absolute-directory)))
2221 (concatenate 'string
2222 (or absolute-directory "")
2223 (or relative-directory "")))
2227 <cl> (defun d (d n) (namestring (make-pathname :directory d :name n)))
2230 <cl> (d "~/foo/" "baz/bar.lisp")
2231 "/usr0/mkant/foo/baz/bar.lisp"
2233 <cl> (d "~/foo" "baz/bar.lisp")
2234 "/usr0/mkant/foo/baz/bar.lisp"
2236 <cl> (d "/foo/bar/" "baz/barf.lisp")
2237 "/foo/bar/baz/barf.lisp"
2239 <cl> (d "foo/bar/" "baz/barf.lisp")
2240 "foo/bar/baz/barf.lisp"
2242 <cl> (d "foo/bar" "baz/barf.lisp")
2243 "foo/bar/baz/barf.lisp"
2245 <cl> (d "foo/bar" "/baz/barf.lisp")
2246 "foo/bar//baz/barf.lisp"
2248 <cl> (d "foo/bar" nil)
2249 "foo/bar/"
2251 <cl> (d nil "baz/barf.lisp")
2252 "baz/barf.lisp"
2254 <cl> (d nil nil)
2259 (defun new-file-type (pathname type)
2260 (make-pathname :type type :defaults pathname))
2263 ;;; ********************************
2264 ;;; Component Defstruct ************
2265 ;;; ********************************
2266 (defvar *source-pathname-default* nil
2267 "Default value of :source-pathname keyword in DEFSYSTEM. Set this to
2268 \"\" to avoid having to type :source-pathname \"\" all the time.")
2270 (defvar *binary-pathname-default* nil
2271 "Default value of :binary-pathname keyword in DEFSYSTEM.")
2273 ;;; Removed TIME slot, which has been made unnecessary by the new definition
2274 ;;; of topological-sort.
2276 (defstruct (topological-sort-node (:conc-name topsort-))
2277 (color :white :type (member :gray :black :white))
2278 ;; time
2281 (defstruct (component (:include topological-sort-node)
2282 (:print-function print-component))
2283 (type :file ; to pacify the CMUCL compiler (:type is alway supplied)
2284 :type (member :defsystem
2285 :system
2286 :subsystem
2287 :module
2288 :file
2289 :private-file
2291 (name nil :type (or symbol string))
2292 (indent 0 :type (mod 1024)) ; Number of characters of indent in
2293 ; verbose output to the user.
2294 host ; The pathname host (i.e., "/../a").
2295 device ; The pathname device.
2296 source-root-dir ; Relative or absolute (starts
2297 ; with "/"), directory or file
2298 ; (ends with "/").
2299 (source-pathname *source-pathname-default*)
2300 source-extension ; A string, e.g., "lisp"
2301 ; if NIL, inherit
2302 (binary-pathname *binary-pathname-default*)
2303 binary-root-dir
2304 binary-extension ; A string, e.g., "fasl". If
2305 ; NIL, uses default for
2306 ; machine-type.
2307 package ; Package for use-package.
2309 ;; The following three slots are used to provide for alternate compilation
2310 ;; and loading functions for the files contained within a component. If
2311 ;; a component has a compiler or a loader specified, those functions are
2312 ;; used. Otherwise the functions are derived from the language. If no
2313 ;; language is specified, it defaults to Common Lisp (:lisp). Other current
2314 ;; possible languages include :scheme (PseudoScheme) and :c, but the user
2315 ;; can define additional language mappings. Compilation functions should
2316 ;; accept a pathname argument and a :output-file keyword; loading functions
2317 ;; just a pathname argument. The default functions are #'compile-file and
2318 ;; #'load. Unlike fdmm's SET-LANGUAGE macro, this allows a defsystem to
2319 ;; mix languages.
2320 (language nil :type (or null symbol))
2321 (compiler nil :type (or null symbol function))
2322 (loader nil :type (or null symbol function))
2323 (compiler-options nil :type list) ; A list of compiler options to
2324 ; use for compiling this
2325 ; component. These must be
2326 ; keyword options supported by
2327 ; the compiler.
2329 (components () :type list) ; A list of components
2330 ; comprising this component's
2331 ; definition.
2332 (depends-on () :type list) ; A list of the components
2333 ; this one depends on. may
2334 ; refer only to the components
2335 ; at the same level as this
2336 ; one.
2337 proclamations ; Compiler options, such as
2338 ; '(optimize (safety 3)).
2339 initially-do ; Form to evaluate before the
2340 ; operation.
2341 finally-do ; Form to evaluate after the operation.
2342 compile-form ; For foreign libraries.
2343 load-form ; For foreign libraries.
2345 ;; load-time ; The file-write-date of the
2346 ; binary/source file loaded.
2348 ;; If load-only is T, will not compile the file on operation :compile.
2349 ;; In other words, for files which are :load-only T, loading the file
2350 ;; satisfies any demand to recompile.
2351 load-only ; If T, will not compile this
2352 ; file on operation :compile.
2353 ;; If compile-only is T, will not load the file on operation :compile.
2354 ;; Either compiles or loads the file, but not both. In other words,
2355 ;; compiling the file satisfies the demand to load it. This is useful
2356 ;; for PCL defmethod and defclass definitions, which wrap a
2357 ;; (eval-when (compile load eval) ...) around the body of the definition.
2358 ;; This saves time in some lisps.
2359 compile-only ; If T, will not load this
2360 ; file on operation :compile.
2361 #|| ISI Extension ||#
2362 load-always ; If T, will force loading
2363 ; even if file has not
2364 ; changed.
2365 ;; PVE: add banner
2366 (banner nil :type (or null string))
2368 (documentation nil :type (or null string)) ; Optional documentation slot
2372 ;;; To allow dependencies from "foreign systems" like ASDF or one of
2373 ;;; the proprietary ones like ACL or LW.
2375 (defstruct (foreign-system (:include component (type :system)))
2376 kind ; This is a keyword: (member :asdf :pcl :lispworks-common-defsystem ...)
2377 object ; The actual foreign system object.
2381 (defun register-foreign-system (name &key representation kind)
2382 (declare (type (or symbol string) name))
2383 (let ((fs (make-foreign-system :name name
2384 :kind kind
2385 :object representation)))
2386 (setf (get-system name) fs)))
2390 (define-condition missing-component (simple-condition)
2391 ((name :reader missing-component-name
2392 :initarg :name)
2393 (component :reader missing-component-component
2394 :initarg :component)
2396 #-gcl(:default-initargs :component nil)
2397 (:report (lambda (mmc stream)
2398 (format stream "MK:DEFSYSTEM: missing component ~S for ~S."
2399 (missing-component-name mmc)
2400 (missing-component-component mmc))))
2403 (define-condition missing-module (missing-component)
2405 (:report (lambda (mmc stream)
2406 (format stream "MK:DEFSYSTEM: missing module ~S for ~S."
2407 (missing-component-name mmc)
2408 (missing-component-component mmc))))
2411 (define-condition missing-system (missing-module)
2413 (:report (lambda (msc stream)
2414 (format stream "MK:DEFSYSTEM: missing system ~S~@[ for S~]."
2415 (missing-component-name msc)
2416 (missing-component-component msc))))
2421 (defvar *file-load-time-table* (make-hash-table :test #'equal)
2422 "Hash table of file-write-dates for the system definitions and
2423 files in the system definitions.")
2424 (defun component-load-time (component)
2425 (when component
2426 (etypecase component
2427 (string (gethash component *file-load-time-table*))
2428 (pathname (gethash (namestring component) *file-load-time-table*))
2429 (component
2430 (ecase (component-type component)
2431 (:defsystem
2432 (let* ((name (component-name component))
2433 (path (when name (compute-system-path name nil))))
2434 (declare (type (or string pathname null) path))
2435 (when path
2436 (gethash (namestring path) *file-load-time-table*))))
2437 ((:file :private-file)
2438 ;; Use only :source pathname to identify component's
2439 ;; load time.
2440 (let ((path (component-full-pathname component :source)))
2441 (when path
2442 (gethash path *file-load-time-table*)))))))))
2444 #-(or :cmu :scl)
2445 (defsetf component-load-time (component) (value)
2446 `(when ,component
2447 (etypecase ,component
2448 (string (setf (gethash ,component *file-load-time-table*) ,value))
2449 (pathname (setf (gethash (namestring (the pathname ,component))
2450 *file-load-time-table*)
2451 ,value))
2452 (component
2453 (ecase (component-type ,component)
2454 (:defsystem
2455 (let* ((name (component-name ,component))
2456 (path (when name (compute-system-path name nil))))
2457 (declare (type (or string pathname null) path))
2458 (when path
2459 (setf (gethash (namestring path) *file-load-time-table*)
2460 ,value))))
2461 ((:file :private-file)
2462 ;; Use only :source pathname to identify file.
2463 (let ((path (component-full-pathname ,component :source)))
2464 (when path
2465 (setf (gethash path *file-load-time-table*)
2466 ,value)))))))
2467 ,value))
2469 #+(or :cmu :scl)
2470 (defun (setf component-load-time) (value component)
2471 (declare
2472 (type (or null string pathname component) component)
2473 (type (or unsigned-byte null) value))
2474 (when component
2475 (etypecase component
2476 (string (setf (gethash component *file-load-time-table*) value))
2477 (pathname (setf (gethash (namestring (the pathname component))
2478 *file-load-time-table*)
2479 value))
2480 (component
2481 (ecase (component-type component)
2482 (:defsystem
2483 (let* ((name (component-name component))
2484 (path (when name (compute-system-path name nil))))
2485 (declare (type (or string pathname null) path))
2486 (when path
2487 (setf (gethash (namestring path) *file-load-time-table*)
2488 value))))
2489 ((:file :private-file)
2490 ;; Use only :source pathname to identify file.
2491 (let ((path (component-full-pathname component :source)))
2492 (when path
2493 (setf (gethash path *file-load-time-table*)
2494 value)))))))
2495 value))
2498 ;;; compute-system-path --
2500 (defun compute-system-path (module-name definition-pname)
2501 (let* ((module-string-name
2502 (etypecase module-name
2503 (symbol (string-downcase
2504 (string module-name)))
2505 (string module-name)))
2507 (file-pathname
2508 (make-pathname :name module-string-name
2509 :type *system-extension*))
2511 (lib-file-pathname
2512 (make-pathname ;:directory (list :relative module-string-name)
2513 :name module-string-name
2514 :type *system-extension*))
2516 (or (when definition-pname ; given pathname for system def
2517 (probe-file definition-pname))
2518 ;; Then the central registry. Note that we also check the current
2519 ;; directory in the registry, but the above check is hard-coded.
2520 (cond (*central-registry*
2521 (if (listp *central-registry*)
2522 (dolist (registry *central-registry*)
2523 (let ((file (or (probe-file
2524 (append-directories (if (consp registry)
2525 (eval registry)
2526 registry)
2527 file-pathname))
2528 (probe-file
2529 (append-directories (if (consp registry)
2530 (eval registry)
2531 registry)
2532 lib-file-pathname))
2535 (when file (return file))))
2536 (or (probe-file (append-directories *central-registry*
2537 file-pathname))
2538 (probe-file (append-directories *central-registry*
2539 lib-file-pathname))
2543 ;; No central registry. Assume current working directory.
2544 ;; Maybe this should be an error?
2545 (or (probe-file file-pathname)
2546 (probe-file lib-file-pathname)))))
2550 (defun system-definition-pathname (system-name)
2551 (let ((system (ignore-errors (find-system system-name :error))))
2552 (if system
2553 (let ((system-def-pathname
2554 (make-pathname :type "system"
2555 :defaults (pathname (component-full-pathname system :source))))
2557 (values system-def-pathname
2558 (probe-file system-def-pathname)))
2559 (values nil nil))))
2566 (defun compute-system-path (module-name definition-pname)
2567 (let* ((filename (format nil "~A.~A"
2568 (if (symbolp module-name)
2569 (string-downcase (string module-name))
2570 module-name)
2571 *system-extension*)))
2572 (or (when definition-pname ; given pathname for system def
2573 (probe-file definition-pname))
2574 ;; Then the central registry. Note that we also check the current
2575 ;; directory in the registry, but the above check is hard-coded.
2576 (cond (*central-registry*
2577 (if (listp *central-registry*)
2578 (dolist (registry *central-registry*)
2579 (let ((file (probe-file
2580 (append-directories (if (consp registry)
2581 (eval registry)
2582 registry)
2583 filename))))
2584 (when file (return file))))
2585 (probe-file (append-directories *central-registry*
2586 filename))))
2588 ;; No central registry. Assume current working directory.
2589 ;; Maybe this should be an error?
2590 (probe-file filename))))))
2594 (defvar *reload-systems-from-disk* t
2595 "If T, always tries to reload newer system definitions from disk.
2596 Otherwise first tries to find the system definition in the current
2597 environment.")
2599 (defun find-system (system-name &optional (mode :ask) definition-pname)
2600 "Returns the system named SYSTEM-NAME.
2601 If not already loaded, loads it, depending on the value of
2602 *RELOAD-SYSTEMS-FROM-DISK* and of the value of MODE. MODE can be :ASK,
2603 :ERROR, :LOAD-OR-NIL, or :LOAD. :ASK is the default.
2604 This allows OPERATE-ON-SYSTEM to work on non-loaded as well as
2605 loaded system definitions. DEFINITION-PNAME is the pathname for
2606 the system definition, if provided."
2607 (ecase mode
2608 (:ask
2609 (or (get-system system-name)
2610 (when (y-or-n-p-wait
2611 #\y 20
2612 "System ~A not loaded. Shall I try loading it? "
2613 system-name)
2614 (find-system system-name :load definition-pname))))
2615 (:error
2616 (or (get-system system-name)
2617 (error 'missing-system :name system-name)))
2618 (:load-or-nil
2619 (let ((system (get-system system-name)))
2620 (or (unless *reload-systems-from-disk* system)
2621 ;; If SYSTEM-NAME is a symbol, it will lowercase the
2622 ;; symbol's string.
2623 ;; If SYSTEM-NAME is a string, it doesn't change the case of the
2624 ;; string. So if case matters in the filename, use strings, not
2625 ;; symbols, wherever the system is named.
2626 (when (foreign-system-p system)
2627 (warn "Foreing system ~S cannot be reloaded by MK:DEFSYSTEM." system)
2628 (return-from find-system nil))
2629 (let ((path (compute-system-path system-name definition-pname)))
2630 (when (and path
2631 (or (null system)
2632 (null (component-load-time path))
2633 (< (component-load-time path)
2634 (file-write-date path))))
2635 (tell-user-generic
2636 (format nil "Loading system ~A from file ~A"
2637 system-name
2638 path))
2639 (load path)
2640 (setf system (get-system system-name))
2641 (when system
2642 (setf (component-load-time path)
2643 (file-write-date path))))
2644 system)
2645 system)))
2646 (:load
2647 (or (unless *reload-systems-from-disk* (get-system system-name))
2648 (when (foreign-system-p (get-system system-name))
2649 (warn "Foreign system ~S cannot be reloaded by MK:DEFSYSTEM." system-name)
2650 (return-from find-system nil))
2651 (or (find-system system-name :load-or-nil definition-pname)
2652 (error "Can't find system named ~s." system-name))))))
2655 (defun print-component (component stream depth)
2656 (declare (ignore depth))
2657 (format stream "#<~:@(~A~): ~A>"
2658 (component-type component)
2659 (component-name component)))
2662 (defun describe-system (name &optional (stream *standard-output*))
2663 "Prints a description of the system to the stream. If NAME is the
2664 name of a system, gets it and prints a description of the system.
2665 If NAME is a component, prints a description of the component."
2666 (let ((system (if (typep name 'component) name (find-system name :load))))
2667 (format stream "~&~A ~A: ~
2668 ~@[~& Host: ~A~]~
2669 ~@[~& Device: ~A~]~
2670 ~@[~& Package: ~A~]~
2671 ~& Source: ~@[~A~] ~@[~A~] ~@[~A~]~
2672 ~& Binary: ~@[~A~] ~@[~A~] ~@[~A~]~
2673 ~@[~& Depends On: ~A ~]~& Components:~{~15T~A~&~}"
2674 (component-type system)
2675 (component-name system)
2676 (component-host system)
2677 (component-device system)
2678 (component-package system)
2679 (component-root-dir system :source)
2680 (component-pathname system :source)
2681 (component-extension system :source)
2682 (component-root-dir system :binary)
2683 (component-pathname system :binary)
2684 (component-extension system :binary)
2685 (component-depends-on system)
2686 (component-components system))
2687 #||(when recursive
2688 (dolist (component (component-components system))
2689 (describe-system component stream recursive)))||#
2690 system))
2692 (defun canonicalize-component-name (component)
2693 ;; Within the component, the name is a string.
2694 (if (typep (component-name component) 'string)
2695 ;; Unnecessary to change it, so just return it, same case
2696 (component-name component)
2697 ;; Otherwise, make it a downcase string -- important since file
2698 ;; names are often constructed from component names, and unix
2699 ;; prefers lowercase as a default.
2700 (setf (component-name component)
2701 (string-downcase (string (component-name component))))))
2703 (defun component-pathname (component type)
2704 (when component
2705 (ecase type
2706 (:source (component-source-pathname component))
2707 (:binary (component-binary-pathname component))
2708 (:error (component-error-pathname component)))))
2709 (defun component-error-pathname (component)
2710 (let ((binary (component-pathname component :binary)))
2711 (new-file-type binary *compile-error-file-type*)))
2712 (defsetf component-pathname (component type) (value)
2713 `(when ,component
2714 (ecase ,type
2715 (:source (setf (component-source-pathname ,component) ,value))
2716 (:binary (setf (component-binary-pathname ,component) ,value)))))
2718 (defun component-root-dir (component type)
2719 (when component
2720 (ecase type
2721 (:source (component-source-root-dir component))
2722 ((:binary :error) (component-binary-root-dir component))
2724 (defsetf component-root-dir (component type) (value)
2725 `(when ,component
2726 (ecase ,type
2727 (:source (setf (component-source-root-dir ,component) ,value))
2728 (:binary (setf (component-binary-root-dir ,component) ,value)))))
2730 (defvar *source-pathnames-table* (make-hash-table :test #'equal)
2731 "Table which maps from components to full source pathnames.")
2732 (defvar *binary-pathnames-table* (make-hash-table :test #'equal)
2733 "Table which maps from cosmponents to full binary pathnames.")
2734 (defparameter *reset-full-pathname-table* t
2735 "If T, clears the full-pathname tables before each call to
2736 OPERATE-ON-SYSTEM. Setting this to NIL may yield faster performance
2737 after multiple calls to LOAD-SYSTEM and COMPILE-SYSTEM, but could
2738 result in changes to system and language definitions to not take
2739 effect, and so should be used with caution.")
2740 (defun clear-full-pathname-tables ()
2741 (clrhash *source-pathnames-table*)
2742 (clrhash *binary-pathnames-table*))
2744 (defun component-full-pathname (component type &optional (version *version*))
2745 (when component
2746 (case type
2747 (:source
2748 (let ((old (gethash component *source-pathnames-table*)))
2749 (or old
2750 (let ((new (component-full-pathname-i component type version)))
2751 (setf (gethash component *source-pathnames-table*) new)
2752 new))))
2753 (:binary
2754 (let ((old (gethash component *binary-pathnames-table*)))
2755 (or old
2756 (let ((new (component-full-pathname-i component type version)))
2757 (setf (gethash component *binary-pathnames-table*) new)
2758 new))))
2759 (otherwise
2760 (component-full-pathname-i component type version)))))
2762 (defun component-full-pathname-i (component type
2763 &optional (version *version*)
2764 &aux version-dir version-replace)
2765 ;; If the pathname-type is :binary and the root pathname is null,
2766 ;; distribute the binaries among the sources (= use :source pathname).
2767 ;; This assumes that the component's :source pathname has been set
2768 ;; before the :binary one.
2769 (if version
2770 (multiple-value-setq (version-dir version-replace)
2771 (translate-version version))
2772 (setq version-dir *version-dir* version-replace *version-replace*))
2773 ;; (format *trace-output* "~&>>>> VERSION COMPUTED ~S ~S~%" version-dir version-replace)
2774 (let ((pathname
2775 (append-directories
2776 (if version-replace
2777 version-dir
2778 (append-directories (component-root-dir component type)
2779 version-dir))
2780 (component-pathname component type))))
2782 ;; When a logical pathname is used, it must first be translated to
2783 ;; a physical pathname. This isn't strictly correct. What should happen
2784 ;; is we fill in the appropriate slots of the logical pathname, and
2785 ;; then return the logical pathname for use by compile-file & friends.
2786 ;; But calling translate-logical-pathname to return the actual pathname
2787 ;; should do for now.
2789 ;; (format t "pathname = ~A~%" pathname)
2790 ;; (format t "type = ~S~%" (component-extension component type))
2792 ;; 20000303 Marco Antoniotti
2793 ;; Changed the following according to suggestion by Ray Toy. I
2794 ;; just collapsed the tests for "logical-pathname-ness" into a
2795 ;; single test (heavy, but probably very portable) and added the
2796 ;; :name argument to the MAKE-PATHNAME in the MERGE-PATHNAMES
2797 ;; beacuse of possible null names (e.g. :defsystem components)
2798 ;; causing problems with the subsequenct call to NAMESTRING.
2799 ;; (format *trace-output* "~&>>>> PATHNAME is ~S~%" pathname)
2800 (cond #-scl
2801 ((pathname-logical-p pathname) ; See definition of test above.
2802 (setf pathname
2803 (merge-pathnames pathname
2804 (make-pathname
2805 :name (component-name component)
2806 :type (component-extension component
2807 type))))
2808 ;;(format t "new path = ~A~%" pathname)
2809 (namestring (translate-logical-pathname pathname)))
2810 #-scl
2812 (namestring
2813 (make-pathname :host (when (component-host component)
2814 ;; MCL2.0b1 and ACLPC cause an error on
2815 ;; (pathname-host nil)
2816 #+sbcl
2817 (component-host component)
2818 #+openmcl
2819 (component-host (if (eq component :unspecific) "" component))
2820 #-(or :sbcl :openmcl)
2821 (pathname-host (component-host component)))
2822 :directory (pathname-directory pathname)
2823 ;; Use :directory instead of :defaults
2824 :name (pathname-name pathname)
2825 :type (component-extension component type)
2826 :device
2827 #+sbcl
2828 :unspecific
2829 #-(or :sbcl)
2830 (let ((dev (component-device component)))
2831 (if dev
2832 (pathname-device dev
2833 #+scl :case #+scl :common
2835 (pathname-device pathname
2836 #+scl :case #+scl :common
2838 ;; :version :newest
2840 #+scl
2842 (make-pathname
2843 :name (component-name component)
2844 :type (component-extension component type)
2845 :defaults pathname
2846 :case :uri)))))
2848 ;;; What about CMU17 :device :unspecific in the above?
2850 #-lispworks
2851 (defun translate-version (version)
2852 ;; Value returns the version directory and whether it replaces
2853 ;; the entire root (t) or is a subdirectory.
2854 ;; Version may be nil to signify no subdirectory,
2855 ;; a symbol, such as alpha, beta, omega, :alpha, mark, which
2856 ;; specifies a subdirectory of the root, or
2857 ;; a string, which replaces the root.
2858 (cond ((null version)
2859 (values "" nil))
2860 ((symbolp version)
2861 (values (let ((sversion (string version)))
2862 (if (find-if #'lower-case-p sversion)
2863 sversion
2864 (string-downcase sversion)))
2865 nil))
2866 ((stringp version)
2867 (values version t))
2868 (t (error "~&; Illegal version ~S" version))))
2871 ;;; Looks like LW has a bug in MERGE-PATHNAMES.
2873 ;;; (merge-pathnames "" "LP:foo;bar;") ==> "LP:"
2875 ;;; Which is incorrect.
2876 ;;; The change here ensures that the result of TRANSLATE-VERSION is
2877 ;;; appropriate.
2879 #+lispworks
2880 (defun translate-version (version)
2881 ;; Value returns the version directory and whether it replaces
2882 ;; the entire root (t) or is a subdirectory.
2883 ;; Version may be nil to signify no subdirectory,
2884 ;; a symbol, such as alpha, beta, omega, :alpha, mark, which
2885 ;; specifies a subdirectory of the root, or
2886 ;; a string, which replaces the root.
2887 (cond ((null version)
2888 (values (pathname "") nil))
2889 ((symbolp version)
2890 (values (let ((sversion (string version)))
2891 (if (find-if #'lower-case-p sversion)
2892 (pathname sversion)
2893 (pathname (string-downcase sversion))))
2894 nil))
2895 ((stringp version)
2896 (values (pathname version) t))
2897 (t (error "~&; Illegal version ~S" version))))
2902 (defun component-extension (component type &key local)
2903 (ecase type
2904 (:source (or (component-source-extension component)
2905 (unless local
2906 (default-source-extension component)) ; system default
2907 ;; (and (component-language component))
2909 (:binary (or (component-binary-extension component)
2910 (unless local
2911 (default-binary-extension component)) ; system default
2912 ;; (and (component-language component))
2914 (:error *compile-error-file-type*)))
2917 (defsetf component-extension (component type) (value)
2918 `(ecase ,type
2919 (:source (setf (component-source-extension ,component) ,value))
2920 (:binary (setf (component-binary-extension ,component) ,value))
2921 (:error (setf *compile-error-file-type* ,value))))
2923 ;;; ********************************
2924 ;;; System Definition **************
2925 ;;; ********************************
2926 (defun create-component (type name definition-body &optional parent (indent 0))
2927 (let ((component (apply #'make-component
2928 :type type
2929 :name name
2930 :indent indent
2931 definition-body)))
2932 ;; Set up :load-only attribute
2933 (unless (find :load-only definition-body)
2934 ;; If the :load-only attribute wasn't specified,
2935 ;; inherit it from the parent. If no parent, default it to nil.
2936 (setf (component-load-only component)
2937 (when parent
2938 (component-load-only parent))))
2939 ;; Set up :compile-only attribute
2940 (unless (find :compile-only definition-body)
2941 ;; If the :compile-only attribute wasn't specified,
2942 ;; inherit it from the parent. If no parent, default it to nil.
2943 (setf (component-compile-only component)
2944 (when parent
2945 (component-compile-only parent))))
2947 ;; Set up :compiler-options attribute
2948 (unless (find :compiler-options definition-body)
2949 ;; If the :compiler-option attribute wasn't specified,
2950 ;; inherit it from the parent. If no parent, default it to NIL.
2951 (setf (component-compiler-options component)
2952 (when parent
2953 (component-compiler-options parent))))
2955 #|| ISI Extension ||#
2956 ;; Set up :load-always attribute
2957 (unless (find :load-always definition-body)
2958 ;; If the :load-always attribute wasn't specified,
2959 ;; inherit it from the parent. If no parent, default it to nil.
2960 (setf (component-load-always component)
2961 (when parent
2962 (component-load-always parent))))
2964 ;; Initializations/after makes
2965 (canonicalize-component-name component)
2967 ;; Inherit package from parent if not specified.
2968 (setf (component-package component)
2969 (or (component-package component)
2970 (when parent (component-package parent))))
2972 ;; Type specific setup:
2973 (when (or (eq type :defsystem) (eq type :system) (eq type :subsystem))
2974 (setf (get-system name) component)
2975 #|(unless (component-language component)
2976 (setf (component-language component) :lisp))|#)
2978 ;; Set up the component's pathname
2979 (create-component-pathnames component parent)
2981 ;; If there are any components of the component, expand them too.
2982 (expand-component-components component (+ indent 2))
2984 ;; Make depends-on refer to structs instead of names.
2985 (link-component-depends-on (component-components component))
2987 ;; Design Decision: Topologically sort the dependency graph at
2988 ;; time of definition instead of at time of use. Probably saves a
2989 ;; little bit of time for the user.
2991 ;; Topological Sort the components at this level.
2992 (setf (component-components component)
2993 (topological-sort (component-components component)))
2995 ;; Return the component.
2996 component))
2999 ;;; defsystem --
3000 ;;; The main macro.
3002 ;;; 2002-11-22 Marco Antoniotti
3003 ;;; Added code to achieve a first cut "pathname less" operation,
3004 ;;; following the ideas in ASDF. If the DEFSYSTEM form is loaded from
3005 ;;; a file, then the location of the file (intended as a directory) is
3006 ;;; computed from *LOAD-PATHNAME* and stored as the :SOURCE-PATHNAME
3007 ;;; of the system.
3009 (defmacro defsystem (name &rest definition-body)
3010 (unless (find :source-pathname definition-body)
3011 (setf definition-body
3012 (list* :source-pathname
3013 '(when #-gcl *load-pathname* #+gcl si::*load-pathname*
3014 (make-pathname :name nil
3015 :type nil
3016 :defaults #-gcl *load-pathname*
3017 #+gcl si::*load-pathname*))
3018 definition-body)))
3019 `(create-component :defsystem ',name ',definition-body nil 0))
3021 (defun create-component-pathnames (component parent)
3022 ;; Set up language-specific defaults
3024 (setf (component-language component)
3025 (or (component-language component) ; for local defaulting
3026 (when parent ; parent's default
3027 (component-language parent))))
3029 (setf (component-compiler component)
3030 (or (component-compiler component) ; for local defaulting
3031 (when parent ; parent's default
3032 (component-compiler parent))))
3033 (setf (component-loader component)
3034 (or (component-loader component) ; for local defaulting
3035 (when parent ; parent's default
3036 (component-loader parent))))
3038 ;; Evaluate the root dir arg
3039 (setf (component-root-dir component :source)
3040 (eval (component-root-dir component :source)))
3041 (setf (component-root-dir component :binary)
3042 (eval (component-root-dir component :binary)))
3044 ;; Evaluate the pathname arg
3045 (setf (component-pathname component :source)
3046 (eval (component-pathname component :source)))
3047 (setf (component-pathname component :binary)
3048 (eval (component-pathname component :binary)))
3050 ;; Pass along the host and devices
3051 (setf (component-host component)
3052 (or (component-host component)
3053 (when parent (component-host parent))
3054 (pathname-host *default-pathname-defaults*)))
3055 (setf (component-device component)
3056 (or (component-device component)
3057 (when parent (component-device parent))))
3059 ;; Set up extension defaults
3060 (setf (component-extension component :source)
3061 (or (component-extension component :source
3062 :local #| (component-language component) |#
3064 ) ; local default
3065 (when (component-language component)
3066 (default-source-extension component))
3067 (when parent ; parent's default
3068 (component-extension parent :source))))
3069 (setf (component-extension component :binary)
3070 (or (component-extension component :binary
3071 :local #| (component-language component) |#
3073 ) ; local default
3074 (when (component-language component)
3075 (default-binary-extension component))
3076 (when parent ; parent's default
3077 (component-extension parent :binary))))
3079 ;; Set up pathname defaults -- expand with parent
3080 ;; We must set up the source pathname before the binary pathname
3081 ;; to allow distribution of binaries among the sources to work.
3082 (generate-component-pathname component parent :source)
3083 (generate-component-pathname component parent :binary))
3086 ;; maybe file's inheriting of pathnames should be moved elsewhere?
3087 (defun generate-component-pathname (component parent pathname-type)
3088 ;; Pieces together a pathname for the component based on its component-type.
3089 ;; Assumes source defined first.
3090 ;; Null binary pathnames inherit from source instead of the component's
3091 ;; name. This allows binaries to be distributed among the source if
3092 ;; binary pathnames are not specified. Or if the root directory is
3093 ;; specified for binaries, but no module directories, it inherits
3094 ;; parallel directory structure.
3095 (case (component-type component)
3096 ((:defsystem :system) ; Absolute Pathname
3097 ;; Set the root-dir to be the absolute pathname
3098 (setf (component-root-dir component pathname-type)
3099 (or (component-pathname component pathname-type)
3100 (when (eq pathname-type :binary)
3101 ;; When the binary root is nil, use source.
3102 (component-root-dir component :source))) )
3103 ;; Set the relative pathname to be nil
3104 (setf (component-pathname component pathname-type)
3105 nil));; should this be "" instead?
3106 ;; If the name of the component-pathname is nil, it
3107 ;; defaults to the name of the component. Use "" to
3108 ;; avoid this defaulting.
3109 (:private-file ; Absolute Pathname
3110 ;; Root-dir is the directory part of the pathname
3111 (setf (component-root-dir component pathname-type)
3113 #+ignore(or (when (component-pathname component pathname-type)
3114 (pathname-directory
3115 (component-pathname component pathname-type)))
3116 (when (eq pathname-type :binary)
3117 ;; When the binary root is nil, use source.
3118 (component-root-dir component :source)))
3120 ;; If *SOURCE-PATHNAME-DEFAULT* or *BINARY-PATHNAME-DEFAULT* is "",
3121 ;; then COMPONENT-SOURCE-PATHNAME or COMPONENT-BINARY-PATHNAME could
3122 ;; wind up being "", which is wrong for :file components. So replace
3123 ;; them with NIL.
3124 (when (null-string (component-pathname component pathname-type))
3125 (setf (component-pathname component pathname-type) nil))
3126 ;; The relative pathname is the name part
3127 (setf (component-pathname component pathname-type)
3128 (or (when (and (eq pathname-type :binary)
3129 (null (component-pathname component :binary)))
3130 ;; When the binary-pathname is nil use source.
3131 (component-pathname component :source))
3132 (or (when (component-pathname component pathname-type)
3133 ; (pathname-name )
3134 (component-pathname component pathname-type))
3135 (component-name component)))))
3136 ((:module :subsystem) ; Pathname relative to parent.
3137 ;; Inherit root-dir from parent
3138 (setf (component-root-dir component pathname-type)
3139 (component-root-dir parent pathname-type))
3140 ;; Tack the relative-dir onto the pathname
3141 (setf (component-pathname component pathname-type)
3142 (or (when (and (eq pathname-type :binary)
3143 (null (component-pathname component :binary)))
3144 ;; When the binary-pathname is nil use source.
3145 (component-pathname component :source))
3146 (append-directories
3147 (component-pathname parent pathname-type)
3148 (or (component-pathname component pathname-type)
3149 (component-name component))))))
3150 (:file ; Pathname relative to parent.
3151 ;; Inherit root-dir from parent
3152 (setf (component-root-dir component pathname-type)
3153 (component-root-dir parent pathname-type))
3154 ;; If *SOURCE-PATHNAME-DEFAULT* or *BINARY-PATHNAME-DEFAULT* is "",
3155 ;; then COMPONENT-SOURCE-PATHNAME or COMPONENT-BINARY-PATHNAME could
3156 ;; wind up being "", which is wrong for :file components. So replace
3157 ;; them with NIL.
3158 (when (null-string (component-pathname component pathname-type))
3159 (setf (component-pathname component pathname-type) nil))
3160 ;; Tack the relative-dir onto the pathname
3161 (setf (component-pathname component pathname-type)
3162 (or (append-directories
3163 (component-pathname parent pathname-type)
3164 (or (component-pathname component pathname-type)
3165 (component-name component)
3166 (when (eq pathname-type :binary)
3167 ;; When the binary-pathname is nil use source.
3168 (component-pathname component :source)))))))
3171 #|| ;; old version
3172 (defun expand-component-components (component &optional (indent 0))
3173 (let ((definitions (component-components component)))
3174 (setf (component-components component)
3175 (remove-if #'null
3176 (mapcar #'(lambda (definition)
3177 (expand-component-definition definition
3178 component
3179 indent))
3180 definitions)))))
3182 ;; new version
3183 (defun expand-component-components (component &optional (indent 0))
3184 (let ((definitions (component-components component)))
3185 (if (eq (car definitions) :serial)
3186 (setf (component-components component)
3187 (expand-serial-component-chain (cdr definitions)
3188 component indent))
3189 (setf (component-components component)
3190 (expand-component-definitions definitions component indent)))))
3192 (defun expand-component-definitions (definitions parent &optional (indent 0))
3193 (let ((components nil))
3194 (dolist (definition definitions)
3195 (let ((new (expand-component-definition definition parent indent)))
3196 (when new (push new components))))
3197 (nreverse components)))
3199 (defun expand-serial-component-chain (definitions parent &optional (indent 0))
3200 (let ((previous nil)
3201 (components nil))
3202 (dolist (definition definitions)
3203 (let ((new (expand-component-definition definition parent indent)))
3204 (when new
3205 ;; Make this component depend on the previous one. Since
3206 ;; we don't know the form of the definition, we have to
3207 ;; expand it first.
3208 (when previous (pushnew previous (component-depends-on new)))
3209 ;; The dependencies will be linked later, so we use the name
3210 ;; instead of the actual component.
3211 (setq previous (component-name new))
3212 ;; Save the new component.
3213 (push new components))))
3214 ;; Return the list of expanded components, in appropriate order.
3215 (nreverse components)))
3218 (defparameter *enable-straz-absolute-string-hack* nil
3219 "Special hack requested by Steve Strassman, where the shorthand
3220 that specifies a list of components as a list of strings also
3221 recognizes absolute pathnames and treats them as files of type
3222 :private-file instead of type :file. Defaults to NIL, because I
3223 haven't tested this.")
3224 (defun absolute-file-namestring-p (string)
3225 ;; If a FILE namestring starts with a slash, or is a logical pathname
3226 ;; as implied by the existence of a colon in the filename, assume it
3227 ;; represents an absolute pathname.
3228 (or (find #\: string :test #'char=)
3229 (and (not (null-string string))
3230 (char= (char string 0) #\/))))
3232 (defun expand-component-definition (definition parent &optional (indent 0))
3233 ;; Should do some checking for malformed definitions here.
3234 (cond ((null definition) nil)
3235 ((stringp definition)
3236 ;; Strings are assumed to be of type :file
3237 (if (and *enable-straz-absolute-string-hack*
3238 (absolute-file-namestring-p definition))
3239 ;; Special hack for Straz
3240 (create-component :private-file definition nil parent indent)
3241 ;; Normal behavior
3242 (create-component :file definition nil parent indent)))
3243 ((and (listp definition)
3244 (not (member (car definition)
3245 '(:defsystem :system :subsystem
3246 :module :file :private-file))))
3247 ;; Lists whose first element is not a component type
3248 ;; are assumed to be of type :file
3249 (create-component :file
3250 (car definition)
3251 (cdr definition)
3252 parent
3253 indent))
3254 ((listp definition)
3255 ;; Otherwise, it is (we hope) a normal form definition
3256 (create-component (car definition) ; type
3257 (cadr definition) ; name
3258 (cddr definition) ; definition body
3259 parent ; parent
3260 indent) ; indent
3263 (defun link-component-depends-on (components)
3264 (dolist (component components)
3265 (unless (and *system-dependencies-delayed*
3266 (eq (component-type component) :defsystem))
3267 (setf (component-depends-on component)
3268 (mapcar #'(lambda (dependency)
3269 (let ((parent (find (string dependency) components
3270 :key #'component-name
3271 :test #'string-equal)))
3272 (cond (parent parent)
3273 ;; make it more intelligent about the following
3274 (t (warn "Dependency ~S of component ~S not found."
3275 dependency component)))))
3277 (component-depends-on component))))))
3279 ;;; ********************************
3280 ;;; Topological Sort the Graph *****
3281 ;;; ********************************
3283 ;;; New version of topological sort suggested by rs2. Even though
3284 ;;; this version avoids the call to sort, in practice it isn't faster. It
3285 ;;; does, however, eliminate the need to have a TIME slot in the
3286 ;;; topological-sort-node defstruct.
3287 (defun topological-sort (list &aux (sorted-list nil))
3288 (labels ((dfs-visit (znode)
3289 (setf (topsort-color znode) :gray)
3290 (unless (and *system-dependencies-delayed*
3291 (eq (component-type znode) :system))
3292 (dolist (child (component-depends-on znode))
3293 (cond ((eq (topsort-color child) :white)
3294 (dfs-visit child))
3295 ((eq (topsort-color child) :gray)
3296 (format t "~&Detected cycle containing ~A" child)))))
3297 (setf (topsort-color znode) :black)
3298 (push znode sorted-list)))
3299 (dolist (znode list)
3300 (setf (topsort-color znode) :white))
3301 (dolist (znode list)
3302 (when (eq (topsort-color znode) :white)
3303 (dfs-visit znode)))
3304 (nreverse sorted-list)))
3307 ;;; Older version of topological sort.
3308 (defun topological-sort (list &aux (time 0))
3309 ;; The algorithm works by calling depth-first-search to compute the
3310 ;; blackening times for each vertex, and then sorts the vertices into
3311 ;; reverse order by blackening time.
3312 (labels ((dfs-visit (node)
3313 (setf (topsort-color node) 'gray)
3314 (unless (and *system-dependencies-delayed*
3315 (eq (component-type node) :defsystem))
3316 (dolist (child (component-depends-on node))
3317 (cond ((eq (topsort-color child) 'white)
3318 (dfs-visit child))
3319 ((eq (topsort-color child) 'gray)
3320 (format t "~&Detected cycle containing ~A" child)))))
3321 (setf (topsort-color node) 'black)
3322 (setf (topsort-time node) time)
3323 (incf time)))
3324 (dolist (node list)
3325 (setf (topsort-color node) 'white))
3326 (dolist (node list)
3327 (when (eq (topsort-color node) 'white)
3328 (dfs-visit node)))
3329 (sort list #'< :key #'topsort-time)))
3332 ;;; ********************************
3333 ;;; Output to User *****************
3334 ;;; ********************************
3335 ;;; All output to the user is via the tell-user functions.
3337 (defun split-string (string &key (item #\space) (test #'char=))
3338 ;; Splits the string into substrings at spaces.
3339 (let ((len (length string))
3340 (index 0) result)
3341 (dotimes (i len
3342 (progn (unless (= index len)
3343 (push (subseq string index) result))
3344 (reverse result)))
3345 (when (funcall test (char string i) item)
3346 (unless (= index i);; two spaces in a row
3347 (push (subseq string index i) result))
3348 (setf index (1+ i))))))
3350 ;; probably should remove the ",1" entirely. But AKCL 1.243 dies on it
3351 ;; because of an AKCL bug.
3352 ;; KGK suggests using an 8 instead, but 1 does nicely.
3353 (defun prompt-string (component)
3354 (format nil "; ~:[~;TEST:~]~V,1@T "
3355 *oos-test*
3356 (component-indent component)))
3359 (defun format-justified-string (prompt contents)
3360 (format t (concatenate 'string
3361 "~%"
3362 prompt
3363 "-~{~<~%" prompt " ~1,80:; ~A~>~^~}")
3364 (split-string contents))
3365 (finish-output *standard-output*))
3368 (defun format-justified-string (prompt contents &optional (width 80)
3369 (stream *standard-output*))
3370 (let ((prompt-length (+ 2 (length prompt))))
3371 (cond ((< (+ prompt-length (length contents)) width)
3372 (format stream "~%~A- ~A" prompt contents))
3374 (format stream "~%~A-" prompt)
3375 (do* ((cursor prompt-length)
3376 (contents (split-string contents) (cdr contents))
3377 (content (car contents) (car contents))
3378 (content-length (1+ (length content)) (1+ (length content))))
3379 ((null contents))
3380 (cond ((< (+ cursor content-length) width)
3381 (incf cursor content-length)
3382 (format stream " ~A" content))
3384 (setf cursor (+ prompt-length content-length))
3385 (format stream "~%~A ~A" prompt content)))))))
3386 (finish-output stream))
3388 (defun tell-user (what component &optional type no-dots force)
3389 (when (or *oos-verbose* force)
3390 (format-justified-string (prompt-string component)
3391 (format nil "~A ~(~A~) ~@[\"~A\"~] ~:[~;...~]"
3392 ;; To have better messages, wrap the following around the
3393 ;; case statement:
3394 ;;(if (find (component-type component)
3395 ;; '(:defsystem :system :subsystem :module))
3396 ;; "Checking"
3397 ;; (case ...))
3398 ;; This gets around the problem of DEFSYSTEM reporting
3399 ;; that it's loading a module, when it eventually never
3400 ;; loads any of the files of the module.
3401 (case what
3402 ((compile :compile)
3403 (if (component-load-only component)
3404 ;; If it is :load-only t, we're loading.
3405 "Loading"
3406 ;; Otherwise we're compiling.
3407 "Compiling"))
3408 ((load :load) "Loading")
3409 (otherwise what))
3410 (component-type component)
3411 (or (when type
3412 (component-full-pathname component type))
3413 (component-name component))
3414 (and *tell-user-when-done*
3415 (not no-dots))))))
3417 (defun tell-user-done (component &optional force no-dots)
3418 ;; test is no longer really used, but we're leaving it in.
3419 (when (and *tell-user-when-done*
3420 (or *oos-verbose* force))
3421 (format t "~&~A~:[~;...~] Done."
3422 (prompt-string component) (not no-dots))
3423 (finish-output *standard-output*)))
3425 (defmacro with-tell-user ((what component &optional type no-dots force) &body body)
3426 `(progn
3427 (tell-user ,what ,component ,type ,no-dots ,force)
3428 ,@body
3429 (tell-user-done ,component ,force ,no-dots)))
3431 (defun tell-user-no-files (component &optional force)
3432 (when (or *oos-verbose* force)
3433 (format-justified-string (prompt-string component)
3434 (format nil "Source file ~A ~
3435 ~:[and binary file ~A ~;~]not found, not loading."
3436 (component-full-pathname component :source)
3437 (or *load-source-if-no-binary* *load-source-instead-of-binary*)
3438 (component-full-pathname component :binary)))))
3440 (defun tell-user-require-system (name parent)
3441 (when *oos-verbose*
3442 (format t "~&; ~:[~;TEST:~] - System ~A requires ~S"
3443 *oos-test* (component-name parent) name)
3444 (finish-output *standard-output*)))
3446 (defun tell-user-generic (string)
3447 (when *oos-verbose*
3448 (format t "~&; ~:[~;TEST:~] - ~A"
3449 *oos-test* string)
3450 (finish-output *standard-output*)))
3452 ;;; ********************************
3453 ;;; Y-OR-N-P-WAIT ******************
3454 ;;; ********************************
3455 ;;; Y-OR-N-P-WAIT is like Y-OR-N-P, but will timeout after a specified
3456 ;;; number of seconds. I should really replace this with a call to
3457 ;;; the Y-OR-N-P-WAIT defined in the query.cl package and include that
3458 ;;; instead.
3460 (defparameter *use-timeouts* t
3461 "If T, timeouts in Y-OR-N-P-WAIT are enabled. Otherwise it behaves
3462 like Y-OR-N-P. This is provided for users whose lisps don't handle
3463 read-char-no-hang properly.")
3465 (defparameter *clear-input-before-query* t
3466 "If T, y-or-n-p-wait will clear the input before printing the prompt
3467 and asking the user for input.")
3469 ;;; The higher *sleep-amount* is, the less consing, but the lower the
3470 ;;; responsiveness.
3471 (defparameter *sleep-amount* #-CMU 0.1 #+CMU 1.0
3472 "Amount of time to sleep between checking query-io. In multiprocessing
3473 Lisps, this allows other processes to continue while we busy-wait. If
3474 0, skips call to SLEEP.")
3476 (defun internal-real-time-in-seconds ()
3477 (get-universal-time))
3479 (defun read-char-wait (&optional (timeout 20) input-stream
3480 (eof-error-p t) eof-value
3481 &aux peek)
3482 (do ((start (internal-real-time-in-seconds)))
3483 ((or (setq peek (listen input-stream))
3484 (< (+ start timeout) (internal-real-time-in-seconds)))
3485 (when peek
3486 ;; was read-char-no-hang
3487 (read-char input-stream eof-error-p eof-value)))
3488 (unless (zerop *sleep-amount*)
3489 (sleep *sleep-amount*))))
3491 ;;; Lots of lisps, especially those that run on top of UNIX, do not get
3492 ;;; their input one character at a time, but a whole line at a time because
3493 ;;; of the buffering done by the UNIX system. This causes y-or-n-p-wait
3494 ;;; to not always work as expected.
3496 ;;; I wish lisp did all its own buffering (turning off UNIX input line
3497 ;;; buffering by putting the UNIX into CBREAK mode). Of course, this means
3498 ;;; that we lose input editing, but why can't the lisp implement this?
3500 (defun y-or-n-p-wait (&optional (default #\y) (timeout 20)
3501 format-string &rest args)
3502 "Y-OR-N-P-WAIT prints the message, if any, and reads characters from
3503 *QUERY-IO* until the user enters y, Y or space as an affirmative, or either
3504 n or N as a negative answer, or the timeout occurs. It asks again if
3505 you enter any other characters."
3506 (when *clear-input-before-query* (clear-input *query-io*))
3507 (when format-string
3508 (fresh-line *query-io*)
3509 (apply #'format *query-io* format-string args)
3510 ;; FINISH-OUTPUT needed for CMU and other places which don't handle
3511 ;; output streams nicely. This prevents it from continuing and
3512 ;; reading the query until the prompt has been printed.
3513 (finish-output *query-io*))
3514 (loop
3515 (let* ((read-char (if *use-timeouts*
3516 (read-char-wait timeout *query-io* nil nil)
3517 (read-char *query-io*)))
3518 (char (or read-char default)))
3519 ;; We need to ignore #\newline because otherwise the bugs in
3520 ;; clear-input will cause y-or-n-p-wait to print the "Type ..."
3521 ;; message every time... *sigh*
3522 ;; Anyway, we might want to use this to ignore whitespace once
3523 ;; clear-input is fixed.
3524 (unless (find char '(#\tab #\newline #\return))
3525 (when (null read-char)
3526 (format *query-io* "~@[~A~]" default)
3527 (finish-output *query-io*))
3528 (cond ((null char) (return t))
3529 ((find char '(#\y #\Y #\space) :test #'char=) (return t))
3530 ((find char '(#\n #\N) :test #'char=) (return nil))
3532 (when *clear-input-before-query* (clear-input *query-io*))
3533 (format *query-io* "~&Type \"y\" for yes or \"n\" for no. ")
3534 (when format-string
3535 (fresh-line *query-io*)
3536 (apply #'format *query-io* format-string args))
3537 (finish-output *query-io*)))))))
3540 (y-or-n-p-wait #\y 20 "What? ")
3541 (progn (format t "~&hi") (finish-output)
3542 (y-or-n-p-wait #\y 10 "1? ")
3543 (y-or-n-p-wait #\n 10 "2? "))
3545 ;;; ********************************
3546 ;;; Operate on System **************
3547 ;;; ********************************
3548 ;;; Operate-on-system
3549 ;;; Operation is :compile, 'compile, :load or 'load
3550 ;;; Force is :all or :new-source or :new-source-and-dependents or a list of
3551 ;;; specific modules.
3552 ;;; :all (or T) forces a recompilation of every file in the system
3553 ;;; :new-source-and-dependents compiles only those files whose
3554 ;;; sources have changed or who depend on recompiled files.
3555 ;;; :new-source compiles only those files whose sources have changed
3556 ;;; A list of modules means that only those modules and their
3557 ;;; dependents are recompiled.
3558 ;;; Test is T to print out what it would do without actually doing it.
3559 ;;; Note: it automatically sets verbose to T if test is T.
3560 ;;; Verbose is T to print out what it is doing (compiling, loading of
3561 ;;; modules and files) as it does it.
3562 ;;; Dribble should be the pathname of the dribble file if you want to
3563 ;;; dribble the compilation.
3564 ;;; Load-source-instead-of-binary is T to load .lisp instead of binary files.
3565 ;;; Version may be nil to signify no subdirectory,
3566 ;;; a symbol, such as alpha, beta, omega, :alpha, mark, which
3567 ;;; specifies a subdirectory of the root, or
3568 ;;; a string, which replaces the root.
3570 (defun operate-on-system (name operation
3571 &key
3572 force
3573 (version *version*)
3574 (test *oos-test*) (verbose *oos-verbose*)
3575 (load-source-instead-of-binary
3576 *load-source-instead-of-binary*)
3577 (load-source-if-no-binary
3578 *load-source-if-no-binary*)
3579 (bother-user-if-no-binary
3580 *bother-user-if-no-binary*)
3581 (compile-during-load *compile-during-load*)
3582 dribble
3583 (minimal-load *minimal-load*)
3584 (override-compilation-unit t)
3586 (declare #-(or :cltl2 :ansi-cl) (ignore override-compilation-unit))
3587 (unwind-protect
3588 ;; Protect the undribble.
3589 (#+(and (or :cltl2 :ansi-cl) (not :gcl)) with-compilation-unit
3590 #+(and (or :cltl2 :ansi-cl) (not :gcl)) (:override override-compilation-unit)
3591 #-(and (or :cltl2 :ansi-cl) (not :gcl)) progn
3592 (when *reset-full-pathname-table* (clear-full-pathname-tables))
3593 (when dribble (dribble dribble))
3594 (when test (setq verbose t))
3595 (when (null force) ; defaults
3596 (case operation
3597 ((load :load) (setq force :all))
3598 ((compile :compile) (setq force :new-source-and-dependents))
3599 (t (setq force :all))))
3600 ;; Some CL implementations have a variable called *compile-verbose*
3601 ;; or *compile-file-verbose*.
3602 (multiple-value-bind (*version-dir* *version-replace*)
3603 (translate-version version)
3604 ;; CL implementations may uniformly default this to nil
3605 (let (
3606 #-(or MCL CMU CLISP ECL :sbcl lispworks scl)
3607 (*compile-file-verbose* t) ; nil
3608 #+common-lisp-controller
3609 (*compile-print* nil)
3610 #+(and common-lisp-controller cmu)
3611 (ext:*compile-progress* nil)
3612 #+(and common-lisp-controller cmu)
3613 (ext:*require-verbose* nil)
3614 #+(and common-lisp-controller cmu)
3615 (ext:*gc-verbose* nil)
3617 (*version* version)
3618 (*oos-verbose* verbose)
3619 (*oos-test* test)
3620 (*load-source-if-no-binary* load-source-if-no-binary)
3621 (*compile-during-load* compile-during-load)
3622 (*bother-user-if-no-binary* bother-user-if-no-binary)
3623 (*load-source-instead-of-binary* load-source-instead-of-binary)
3624 (*minimal-load* minimal-load)
3625 (system (if (and (component-p name)
3626 (member (component-type name)
3627 '(:system :defsystem :subsystem)))
3628 name
3629 (find-system name :load))))
3630 #-(or CMU CLISP :sbcl :lispworks :cormanlisp scl)
3631 (declare (special *compile-verbose* #-MCL *compile-file-verbose*)
3632 #-openmcl (ignore *compile-verbose*
3633 #-MCL *compile-file-verbose*)
3634 #-openmcl (optimize (inhibit-warnings 3)))
3635 (unless (component-operation operation)
3636 (error "Operation ~A undefined." operation))
3637 (operate-on-component system operation force))))
3638 (when dribble (dribble))))
3641 (defun compile-system (name &key force
3642 (version *version*)
3643 (test *oos-test*) (verbose *oos-verbose*)
3644 (load-source-instead-of-binary
3645 *load-source-instead-of-binary*)
3646 (load-source-if-no-binary
3647 *load-source-if-no-binary*)
3648 (bother-user-if-no-binary
3649 *bother-user-if-no-binary*)
3650 (compile-during-load *compile-during-load*)
3651 dribble
3652 (minimal-load *minimal-load*))
3653 ;; For users who are confused by OOS.
3654 (operate-on-system
3655 name :compile
3656 :force force
3657 :version version
3658 :test test
3659 :verbose verbose
3660 :load-source-instead-of-binary load-source-instead-of-binary
3661 :load-source-if-no-binary load-source-if-no-binary
3662 :bother-user-if-no-binary bother-user-if-no-binary
3663 :compile-during-load compile-during-load
3664 :dribble dribble
3665 :minimal-load minimal-load))
3667 (defun load-system (name &key force
3668 (version *version*)
3669 (test *oos-test*) (verbose *oos-verbose*)
3670 (load-source-instead-of-binary
3671 *load-source-instead-of-binary*)
3672 (load-source-if-no-binary *load-source-if-no-binary*)
3673 (bother-user-if-no-binary *bother-user-if-no-binary*)
3674 (compile-during-load *compile-during-load*)
3675 dribble
3676 (minimal-load *minimal-load*))
3677 ;; For users who are confused by OOS.
3678 (operate-on-system
3679 name :load
3680 :force force
3681 :version version
3682 :test test
3683 :verbose verbose
3684 :load-source-instead-of-binary load-source-instead-of-binary
3685 :load-source-if-no-binary load-source-if-no-binary
3686 :bother-user-if-no-binary bother-user-if-no-binary
3687 :compile-during-load compile-during-load
3688 :dribble dribble
3689 :minimal-load minimal-load))
3691 (defun clean-system (name &key (force :all)
3692 (version *version*)
3693 (test *oos-test*) (verbose *oos-verbose*)
3694 dribble)
3695 "Deletes all the binaries in the system."
3696 ;; For users who are confused by OOS.
3697 (operate-on-system
3698 name :delete-binaries
3699 :force force
3700 :version version
3701 :test test
3702 :verbose verbose
3703 :dribble dribble))
3705 (defun edit-system
3706 (name &key force
3707 (version *version*)
3708 (test *oos-test*)
3709 (verbose *oos-verbose*)
3710 dribble)
3712 (operate-on-system
3713 name :edit
3714 :force force
3715 :version version
3716 :test test
3717 :verbose verbose
3718 :dribble dribble))
3720 (defun hardcopy-system
3721 (name &key force
3722 (version *version*)
3723 (test *oos-test*)
3724 (verbose *oos-verbose*)
3725 dribble)
3727 (operate-on-system
3728 name :hardcopy
3729 :force force
3730 :version version
3731 :test test
3732 :verbose verbose
3733 :dribble dribble))
3736 ;;; ensure-external-system-def-loaded component --
3737 ;;; Let's treat definition clauses of the form
3739 ;;; (:system "name")
3740 ;;; i.e.
3742 ;;; (:system "name" :components nil)
3744 ;;; in a special way.
3745 ;;; When encountered, MK:DEFSYSTEM tries to FIND-SYSTEM
3746 ;;; the system named "name" (by forcing a reload from disk).
3747 ;;; This may be more "natural".
3749 (defun ensure-external-system-def-loaded (component)
3750 (assert (member (component-type component)
3751 '(:subsystem :system)))
3752 (when (null (component-components component))
3753 (let ((cname (component-name component)))
3754 ;; First we ensure that we reload the system definition.
3755 (undefsystem cname)
3756 (let* ((*reload-systems-from-disk* t)
3757 (system-component
3758 (find-system (component-name component)
3759 :load
3761 ;; Let's not supply the def-pname
3762 ;; yet.
3763 #+not-yet
3764 (merge-pathname
3765 (make-pathname :name cname
3766 :type "system"
3767 :directory ())
3768 (component-full-pathname component
3769 :source))
3774 ;; Now we have a problem.
3775 ;; We have just ensured that a system definition is
3776 ;; loaded, however, the COMPONENT at hand is different
3777 ;; from SYSTEM-COMPONENT.
3778 ;; To fix this problem we just use the following
3779 ;; kludge. This should prevent re-entering in this
3780 ;; code branch, while actually preparing the COMPONENT
3781 ;; for operation.
3782 (setf (component-components component)
3783 (list system-component))
3784 ))))
3787 (defun operate-on-component (component operation force &aux changed)
3788 ;; Returns T if something changed and had to be compiled.
3789 (let ((type (component-type component))
3790 (old-package (package-name *package*)))
3792 (unwind-protect
3793 ;; Protect old-package.
3794 (progn
3795 ;; Use the correct package.
3796 (when (component-package component)
3797 (tell-user-generic (format nil "Using package ~A"
3798 (component-package component)))
3799 (unless *oos-test*
3800 (unless (find-package (component-package component))
3801 ;; If the package name is the same as the name of the system,
3802 ;; and the package is not defined, this would lead to an
3803 ;; infinite loop, so bomb out with an error.
3804 (when (string-equal (string (component-package component))
3805 (component-name component))
3806 (format t "~%Component ~A not loaded:~%"
3807 (component-name component))
3808 (error " Package ~A is not defined"
3809 (component-package component)))
3810 ;; If package not found, try using REQUIRE to load it.
3811 (new-require (component-package component)))
3812 ;; This was USE-PACKAGE, but should be IN-PACKAGE.
3813 ;; Actually, CLtL2 lisps define in-package as a macro,
3814 ;; so we'll set the package manually.
3815 ;; (in-package (component-package component))
3816 (let ((package (find-package (component-package component))))
3817 (when package
3818 (setf *package* package)))))
3820 ;; Marco Antoniotti 20040609
3821 ;; New feature. Try to FIND-SYSTEM :system components if
3822 ;; they have no local :components definition.
3823 ;; OPERATE-ON-SYSTEM-DEPENDENCIES should still work as
3824 ;; advertised, given the small change made there.
3826 (when (or (eq type :system) (eq type :subsystem))
3827 (ensure-external-system-def-loaded component))
3829 (when (or (eq type :defsystem) (eq type :system))
3830 (operate-on-system-dependencies component operation force))
3832 ;; Do any compiler proclamations
3833 (when (component-proclamations component)
3834 (tell-user-generic (format nil "Doing proclamations for ~A"
3835 (component-name component)))
3836 (or *oos-test*
3837 (proclaim (component-proclamations component))))
3839 ;; Do any initial actions
3840 (when (component-initially-do component)
3841 (tell-user-generic (format nil "Doing initializations for ~A"
3842 (component-name component)))
3843 (or *oos-test*
3844 (eval (component-initially-do component))))
3846 ;; If operation is :compile and load-only is T, this would change
3847 ;; the operation to load. Only, this would mean that a module would
3848 ;; be considered to have changed if it was :load-only and had to be
3849 ;; loaded, and then dependents would be recompiled -- this doesn't
3850 ;; seem right. So instead, we propagate the :load-only attribute
3851 ;; to the components, and modify compile-file-operation so that
3852 ;; it won't compile the files (and modify tell-user to say "Loading"
3853 ;; instead of "Compiling" for load-only modules).
3855 (when (and (find operation '(:compile compile))
3856 (component-load-only component))
3857 (setf operation :load))
3860 ;; Do operation and set changed flag if necessary.
3861 (setq changed
3862 (case type
3863 ((:file :private-file)
3864 (funcall (component-operation operation) component force))
3865 ((:module :system :subsystem :defsystem)
3866 (operate-on-components component operation force changed))))
3868 ;; Do any final actions
3869 (when (component-finally-do component)
3870 (tell-user-generic (format nil "Doing finalizations for ~A"
3871 (component-name component)))
3872 (or *oos-test*
3873 (eval (component-finally-do component))))
3875 ;; add the banner if needed
3876 #+(or cmu scl)
3877 (when (component-banner component)
3878 (unless (stringp (component-banner component))
3879 (error "The banner should be a string, it is: ~S"
3880 (component-banner component)))
3881 (setf (getf ext:*herald-items*
3882 (intern (string-upcase (component-name component))
3883 (find-package :keyword)))
3884 (list
3885 (component-banner component)))))
3887 ;; Reset the package. (Cleanup form of unwind-protect.)
3888 ;;(in-package old-package)
3889 (setf *package* (find-package old-package)))
3891 ;; Provide the loaded system
3892 (when (or (eq type :defsystem) (eq type :system) (eq type :subsystem))
3893 (tell-user-generic (format nil "Providing system ~A~%"
3894 (component-name component)))
3895 (or *oos-test*
3896 (provide (canonicalize-system-name (component-name component))))))
3898 ;; Return non-NIL if something changed in this component and hence had
3899 ;; to be recompiled. This is only used as a boolean.
3900 changed)
3902 (defvar *force* nil)
3903 (defvar *providing-blocks-load-propagation* t
3904 "If T, if a system dependency exists on *modules*, it is not loaded.")
3906 (defun operate-on-system-dependencies (component operation &optional force)
3907 (when *system-dependencies-delayed*
3908 (let ((*force* force))
3909 (dolist (system (component-depends-on component))
3910 ;; For each system that this system depends on, if it is a
3911 ;; defined system (either via defsystem or component type :system),
3912 ;; and propagation is turned on, propagates the operation to the
3913 ;; subsystem. Otherwise runs require (my version) on that system
3914 ;; to load it (needed since we may be depending on a lisp
3915 ;; dependent package).
3916 ;; Explores the system tree in a DFS manner.
3918 ;; Do not try to do anything with non system components.
3919 (cond ((and *operations-propagate-to-subsystems*
3920 (not (listp system))
3921 (or (stringp system) (symbolp system))
3922 ;; The subsystem is a defined system.
3923 (find-system system :load-or-nil))
3924 ;; Call OOS on it. Since *system-dependencies-delayed* is
3925 ;; T, the :depends-on slot is filled with the names of
3926 ;; systems, not defstructs.
3927 ;; Aside from system, operation, force, for everything else
3928 ;; we rely on the globals.
3929 (unless (and *providing-blocks-load-propagation*
3930 ;; If *providing-blocks-load-propagation* is T,
3931 ;; the system dependency must not exist in the
3932 ;; *modules* for it to be loaded. Note that
3933 ;; the dependencies are implicitly systems.
3934 (find operation '(load :load))
3935 ;; (or (eq force :all) (eq force t))
3936 (find (canonicalize-system-name system)
3937 *modules* :test #'string-equal))
3939 (operate-on-system system operation :force force)))
3941 ((listp system)
3942 ;; If the SYSTEM is a list then its contents are as follows.
3944 ;; (<name> <definition-pathname> <action> &optional <version>)
3947 (destructuring-bind (system-name definition-pathname action
3948 &optional version)
3949 system
3950 (tell-user-require-system
3951 (if (and (null system-name)
3952 (null definition-pathname))
3953 action
3954 system)
3955 component)
3956 (or *oos-test* (new-require system-name
3958 (eval definition-pathname)
3959 action
3960 (or version *version*)))))
3961 ((and (component-p system)
3962 (not (member (component-type system)
3963 '(:defsystem :subsystem :system))))
3964 ;; Do nothing for non system components.
3967 (tell-user-require-system system component)
3968 (or *oos-test* (new-require system))))
3969 ))))
3971 ;;; Modules can depend only on siblings. If a module should depend
3972 ;;; on an uncle, then the parent module should depend on that uncle
3973 ;;; instead. Likewise a module should depend on a sibling, not a niece
3974 ;;; or nephew. Modules also cannot depend on cousins. Modules cannot
3975 ;;; depend on parents, since that is circular.
3977 (defun module-depends-on-changed (module changed)
3978 (dolist (dependent (component-depends-on module))
3979 (when (member dependent changed)
3980 (return t))))
3982 (defun operate-on-components (component operation force changed)
3983 (with-tell-user (operation component)
3984 (if (component-components component)
3985 (dolist (module (component-components component))
3986 (when (operate-on-component module operation
3987 (cond ((and (module-depends-on-changed module changed)
3988 #||(some #'(lambda (dependent)
3989 (member dependent changed))
3990 (component-depends-on module))||#
3991 (or (non-empty-listp force)
3992 (eq force :new-source-and-dependents)))
3993 ;; The component depends on a changed file
3994 ;; and force agrees.
3995 (if (eq force :new-source-and-dependents)
3996 :new-source-all
3997 :all))
3998 ((and (non-empty-listp force)
3999 (member (component-name module) force
4000 :test #'string-equal :key #'string))
4001 ;; Force is a list of modules
4002 ;; and the component is one of them.
4003 :all)
4004 (t force)))
4005 (push module changed)))
4006 (case operation
4007 ((compile :compile)
4008 (eval (component-compile-form component)))
4009 ((load :load)
4010 (eval (component-load-form component))))))
4011 ;; This is only used as a boolean.
4012 changed)
4014 ;;; ********************************
4015 ;;; New Require ********************
4016 ;;; ********************************
4018 ;;; This needs cleaning. Obviously the code is a left over from the
4019 ;;; time people did not know how to use packages in a proper way or
4020 ;;; CLs were shaky in their implementation.
4022 ;;; First of all we need this. (Commented out for the time being)
4023 ;;; (shadow '(cl:require))
4026 (defvar *old-require* nil)
4028 ;;; All calls to require in this file have been replaced with calls
4029 ;;; to new-require to avoid compiler warnings and make this less of
4030 ;;; a tangled mess.
4032 (defun new-require (module-name
4033 &optional
4034 pathname
4035 definition-pname
4036 default-action
4037 (version *version*))
4038 ;; If the pathname is present, this behaves like the old require.
4039 (unless (and module-name
4040 (find (string module-name)
4041 *modules* :test #'string=))
4042 (handler-case
4043 (cond (pathname
4044 (funcall *old-require* module-name pathname))
4045 ;; If the system is defined, load it.
4046 ((find-system module-name :load-or-nil definition-pname)
4047 (operate-on-system
4048 module-name :load
4049 :force *force*
4050 :version version
4051 :test *oos-test*
4052 :verbose *oos-verbose*
4053 :load-source-if-no-binary *load-source-if-no-binary*
4054 :bother-user-if-no-binary *bother-user-if-no-binary*
4055 :compile-during-load *compile-during-load*
4056 :load-source-instead-of-binary *load-source-instead-of-binary*
4057 :minimal-load *minimal-load*))
4058 ;; If there's a default action, do it. This could be a progn which
4059 ;; loads a file that does everything.
4060 ((and default-action
4061 (eval default-action)))
4062 ;; If no system definition file, try regular require.
4063 ;; had last arg PATHNAME, but this wasn't really necessary.
4064 ((funcall *old-require* module-name))
4065 ;; If no default action, print a warning or error message.
4068 (format t "~&Warning: System ~A doesn't seem to be defined..."
4069 module-name)
4071 (error 'missing-system :name module-name)))
4072 (missing-module (mmc) (signal mmc)) ; Resignal.
4073 (error (e)
4074 (declare (ignore e))
4075 ;; Signal a (maybe wrong) MISSING-SYSTEM.
4076 (error 'missing-system :name module-name)))
4080 ;;; Note that in some lisps, when the compiler sees a REQUIRE form at
4081 ;;; top level it immediately executes it. This is as if an
4082 ;;; (eval-when (compile load eval) ...) were wrapped around the REQUIRE
4083 ;;; form. I don't see any easy way to do this without making REQUIRE
4084 ;;; a macro.
4086 ;;; For example, in VAXLisp, if a (require 'streams) form is at the top of
4087 ;;; a file in the system, compiling the system doesn't wind up loading the
4088 ;;; streams module. If the (require 'streams) form is included within an
4089 ;;; (eval-when (compile load eval) ...) then everything is OK.
4091 ;;; So perhaps we should replace the redefinition of lisp:require
4092 ;;; with the following macro definition:
4094 (unless *old-require*
4095 (setf *old-require*
4096 (symbol-function #-(or :lispworks
4097 :sbcl
4098 (and :excl :allegro-v4.0)) 'lisp:require
4099 #+:sbcl 'cl:require
4100 #+:lispworks 'system:::require
4101 #+(and :excl :allegro-v4.0) 'cltl1:require))
4103 (let (#+:CCL (ccl:*warn-if-redefine-kernel* nil))
4104 ;; Note that lots of lisps barf if we redefine a function from
4105 ;; the LISP package. So what we do is define a macro with an
4106 ;; unused name, and use (setf macro-function) to redefine
4107 ;; lisp:require without compiler warnings. If the lisp doesn't
4108 ;; do the right thing, try just replacing require-as-macro
4109 ;; with lisp:require.
4110 (defmacro require-as-macro (module-name
4111 &optional pathname definition-pname
4112 default-action (version '*version*))
4113 `(eval-when (compile load eval)
4114 (new-require ,module-name ,pathname ,definition-pname
4115 ,default-action ,version)))
4116 (setf (macro-function #-(and :excl :sbcl :allegro-v4.0) 'lisp:require
4117 #+:sbcl 'cl:require
4118 #+(and :excl :allegro-v4.0) 'cltl1:require)
4119 (macro-function 'require-as-macro))))
4121 ;;; This will almost certainly fix the problem, but will cause problems
4122 ;;; if anybody does a funcall on #'require.
4124 ;;; Redefine old require to call the new require.
4125 (eval-when #-(or :lucid) (:load-toplevel :execute)
4126 #+(or :lucid) (load eval)
4127 (unless *old-require*
4128 (setf *old-require*
4129 (symbol-function
4130 #-(or (and :excl :allegro-v4.0) :ecl :mcl :sbcl :scl :lispworks :abcl :openmcl) 'lisp:require
4131 #+(and :excl :allegro-v4.0) 'cltl1:require
4132 #+(or :ecl :sbcl :scl) 'cl:require
4133 #+(or :lispworks3.1 :abcl) 'common-lisp::require
4134 #+(and :lispworks (not :lispworks3.1)) 'system::require
4135 #+:openmcl 'cl:require
4136 #+(and :mcl (not :openmcl)) 'ccl:require
4139 (unless *dont-redefine-require*
4140 (let (#+(or :mcl (and :CCL (not :lispworks)))
4141 (ccl:*warn-if-redefine-kernel* nil))
4142 #-(or :ecl (and allegro-version>= (version>= 4 1)) :lispworks)
4143 (setf (symbol-function
4144 #-(or (and :excl :allegro-v4.0) :mcl :sbcl :scl :lispworks :abcl :openmcl) 'lisp:require
4145 #+(and :excl :allegro-v4.0) 'cltl1:require
4146 #+(or :lispworks3.1 :abcl) 'common-lisp::require
4147 #+(or :sbcl :scl) 'cl:require
4148 #+(and :lispworks (not :lispworks3.1)) 'system::require
4149 #+:openmcl 'cl:require
4150 #+(and :mcl (not :openmcl)) 'ccl:require
4152 (symbol-function 'new-require))
4153 #+:ecl
4154 (progn
4155 (ext:package-lock "CL" nil)
4156 (setf (symbol-function 'cl:require)
4157 (symbol-function 'new-require))
4158 (ext:package-lock "CL" t))
4159 #+:lispworks
4160 (let ((warn-packs system::*packages-for-warn-on-redefinition*))
4161 (declare (special system::*packages-for-warn-on-redefinition*))
4162 (setq system::*packages-for-warn-on-redefinition* nil)
4163 (setf (symbol-function
4164 #+:lispworks3.1 'common-lisp::require
4165 #-:lispworks3.1 'system::require
4167 (symbol-function 'new-require))
4168 (setq system::*packages-for-warn-on-redefinition* warn-packs))
4169 #+(and allegro-version>= (version>= 4 1))
4170 (excl:without-package-locks
4171 (setf (symbol-function 'lisp:require)
4172 (symbol-function 'new-require))))))
4176 ;;; Well, let's add some more REQUIRE hacking; specifically for SBCL,
4177 ;;; and, eventually, for CMUCL.
4179 #+sbcl
4180 (eval-when (:compile-toplevel :load-toplevel :execute)
4182 (defun sbcl-mk-defsystem-module-provider (name)
4183 ;; Let's hope things go smoothly.
4184 (let ((module-name (string-downcase (string name))))
4185 (when (mk:find-system module-name :load-or-nil)
4186 (mk:load-system module-name
4187 :compile-during-load t
4188 :verbose nil))))
4190 (pushnew 'sbcl-mk-defsystem-module-provider sb-ext:*module-provider-functions*)
4193 #+#.(cl:if (cl:and (cl:find-package :ext) (cl:find-symbol "*MODULE-PROVIDER-FUNCTIONS*" :ext)) '(and) '(or))
4194 (progn
4195 (defun cmucl-mk-defsystem-module-provider (name)
4196 (let ((module-name (string-downcase (string name))))
4197 (when (mk:find-system module-name :load-or-nil)
4198 (mk:load-system module-name
4199 :compile-during-load t
4200 :verbose nil))))
4202 (pushnew 'cmucl-mk-defsystem-module-provider ext:*module-provider-functions*)
4208 ;;; ********************************
4209 ;;; Language-Dependent Characteristics
4210 ;;; ********************************
4211 ;;; This section is used for defining language-specific behavior of
4212 ;;; defsystem. If the user changes a language definition, it should
4213 ;;; take effect immediately -- they shouldn't have to reload the
4214 ;;; system definition file for the changes to take effect.
4216 (defvar *language-table* (make-hash-table :test #'equal)
4217 "Hash table that maps from languages to language structures.")
4218 (defun find-language (name)
4219 (gethash name *language-table*))
4221 (defstruct (language (:print-function print-language))
4222 name ; The name of the language (a keyword)
4223 compiler ; The function used to compile files in the language
4224 loader ; The function used to load files in the language
4225 source-extension ; Filename extensions for source files
4226 binary-extension ; Filename extensions for binary files
4229 (defun print-language (language stream depth)
4230 (declare (ignore depth))
4231 (format stream "#<~:@(~A~): ~A ~A>"
4232 (language-name language)
4233 (language-source-extension language)
4234 (language-binary-extension language)))
4236 (defun compile-function (component)
4237 (or (component-compiler component)
4238 (let ((language (find-language (or (component-language component)
4239 :lisp))))
4240 (when language (language-compiler language)))
4241 #'compile-file))
4243 (defun load-function (component)
4244 (or (component-loader component)
4245 (let ((language (find-language (or (component-language component)
4246 :lisp))))
4247 (when language (language-loader language)))
4248 #'load))
4250 (defun default-source-extension (component)
4251 (let ((language (find-language (or (component-language component)
4252 :lisp))))
4253 (or (when language (language-source-extension language))
4254 (car *filename-extensions*))))
4256 (defun default-binary-extension (component)
4257 (let ((language (find-language (or (component-language component)
4258 :lisp))))
4259 (or (when language (language-binary-extension language))
4260 (cdr *filename-extensions*))))
4262 (defmacro define-language (name &key compiler loader
4263 source-extension binary-extension)
4264 (let ((language (gensym (symbol-name '#:language))))
4265 `(let ((,language (make-language :name ,name
4266 :compiler ,compiler
4267 :loader ,loader
4268 :source-extension ,source-extension
4269 :binary-extension ,binary-extension)))
4270 (setf (gethash ,name *language-table*) ,language)
4271 ,name)))
4274 ;;; Test System for verifying multi-language capabilities.
4275 (defsystem foo
4276 :language :lisp
4277 :components ((:module c :language :c :components ("foo" "bar"))
4278 (:module lisp :components ("baz" "barf"))))
4282 ;;; *** Lisp Language Definition
4283 (define-language :lisp
4284 :compiler #'compile-file
4285 :loader #'load
4286 :source-extension (car *filename-extensions*)
4287 :binary-extension (cdr *filename-extensions*))
4289 ;;; *** PseudoScheme Language Definition
4290 (defun scheme-compile-file (filename &rest args)
4291 (let ((scheme-package (find-package '#:scheme)))
4292 (apply (symbol-function (find-symbol (symbol-name 'compile-file)
4293 scheme-package))
4294 filename
4295 (funcall (symbol-function
4296 (find-symbol (symbol-name '#:interaction-environment)
4297 scheme-package)))
4298 args)))
4300 (define-language :scheme
4301 :compiler #'scheme-compile-file
4302 :loader #'load
4303 :source-extension "scm"
4304 :binary-extension "bin")
4306 ;;; *** C Language Definition
4308 ;;; This is very basic. Somebody else who needs it can add in support
4309 ;;; for header files, libraries, different C compilers, etc. For example,
4310 ;;; we might add a COMPILER-OPTIONS slot to the component defstruct.
4312 (defparameter *c-compiler* "gcc")
4313 #-(or symbolics (and :lispworks :harlequin-pc-lisp ))
4315 (defun run-unix-program (program arguments)
4316 ;; arguments should be a list of strings, where each element is a
4317 ;; command-line option to send to the program.
4318 #+:lucid (run-program program :arguments arguments)
4319 #+:allegro (excl:run-shell-command
4320 (format nil "~A~@[ ~{~A~^ ~}~]"
4321 program arguments))
4322 #+(or :kcl :ecl) (system (format nil "~A~@[ ~{~A~^ ~}~]" program arguments))
4323 #+(or :cmu :scl) (extensions:run-program program arguments)
4324 #+:openmcl (ccl:run-program program arguments)
4325 #+:sbcl (sb-ext:run-program program arguments)
4326 #+:lispworks (sys:call-system-showing-output
4327 (format nil "~A~@[ ~{~A~^ ~}~]" program arguments))
4328 #+clisp (#+lisp=cl ext:run-program #-lisp=cl lisp:run-program
4329 program :arguments arguments)
4332 #+(or symbolics (and :lispworks :harlequin-pc-lisp))
4333 (defun run-unix-program (program arguments)
4334 (declare (ignore program arguments))
4335 (error "MK::RUN-UNIX-PROGRAM: this does not seem to be a UN*X system.")
4339 (defun c-compile-file (filename &rest args &key output-file error-file)
4340 ;; gcc -c foo.c -o foo.o
4341 (declare (ignore args))
4342 (run-unix-program *c-compiler*
4343 (format nil "-c ~A~@[ -o ~A~]"
4344 filename
4345 output-file)))
4349 (defun c-compile-file (filename &rest args &key output-file error-file)
4350 ;; gcc -c foo.c -o foo.o
4351 (declare (ignore args error-file))
4352 (run-unix-program *c-compiler*
4353 `("-c" ,filename ,@(if output-file `("-o" ,output-file)))))
4357 ;;; The following code was inserted to improve C compiler support (at
4358 ;;; least under Linux/GCC).
4359 ;;; Thanks to Espen S Johnsen.
4361 ;;; 20001118 Marco Antoniotti.
4363 (defun default-output-pathname (path1 path2 type)
4364 (if (eq path1 t)
4365 (translate-logical-pathname
4366 (merge-pathnames (make-pathname :type type) (pathname path2)))
4367 (translate-logical-pathname (pathname path1))))
4370 (defun run-compiler (program
4371 arguments
4372 output-file
4373 error-file
4374 error-output
4375 verbose)
4376 #-(or cmu scl) (declare (ignore error-file error-output))
4378 (flet ((make-useable-stream (&rest streams)
4379 (apply #'make-broadcast-stream (delete nil streams)))
4381 (let (#+(or cmu scl) (error-file error-file)
4382 #+(or cmu scl) (error-file-stream nil)
4383 (verbose-stream nil)
4384 (old-timestamp (file-write-date output-file))
4385 (fatal-error nil)
4386 (output-file-written nil)
4388 (unwind-protect
4389 (progn
4390 #+(or cmu scl)
4391 (setf error-file
4392 (when error-file
4393 (default-output-pathname error-file
4394 output-file
4395 *compile-error-file-type*))
4397 error-file-stream
4398 (and error-file
4399 (open error-file
4400 :direction :output
4401 :if-exists :supersede)))
4403 (setf verbose-stream
4404 (make-useable-stream
4405 #+(or cmu scl) error-file-stream
4406 (and verbose *trace-output*)))
4408 (format verbose-stream "Running ~A~@[ ~{~A~^ ~}~]~%"
4409 program
4410 arguments)
4412 (setf fatal-error
4413 #-(or cmu scl)
4414 (and (run-unix-program program arguments) nil) ; Incomplete.
4415 #+(or cmu scl)
4416 (let* ((error-output
4417 (make-useable-stream error-file-stream
4418 (if (eq error-output t)
4419 *error-output*
4420 error-output)))
4421 (process
4422 (ext:run-program program arguments
4423 :error error-output)))
4424 (not (zerop (ext:process-exit-code process)))))
4426 (setf output-file-written
4427 (and (probe-file output-file)
4428 (not (eql old-timestamp
4429 (file-write-date output-file)))))
4432 (when output-file-written
4433 (format verbose-stream "~A written~%" output-file))
4434 (format verbose-stream "Running of ~A finished~%"
4435 program)
4436 (values (and output-file-written output-file)
4437 fatal-error
4438 fatal-error))
4440 #+(or cmu scl)
4441 (when error-file
4442 (close error-file-stream)
4443 (unless (or fatal-error (not output-file-written))
4444 (delete-file error-file)))
4446 (values (and output-file-written output-file)
4447 fatal-error
4448 fatal-error)))))
4451 ;;; C Language definitions.
4453 (defun c-compile-file (filename &rest args
4454 &key
4455 (output-file t)
4456 (error-file t)
4457 (error-output t)
4458 (verbose *compile-verbose*)
4459 debug
4460 link
4461 optimize
4462 cflags
4463 definitions
4464 include-paths
4465 library-paths
4466 libraries
4467 (error t))
4468 (declare (ignore args))
4470 (flet ((map-options (flag options &optional (func #'identity))
4471 (mapcar #'(lambda (option)
4472 (format nil "~A~A" flag (funcall func option)))
4473 options))
4475 (let* ((output-file (default-output-pathname output-file filename "o"))
4476 (arguments
4477 `(,@(when (not link) '("-c"))
4478 ,@(when debug '("-g"))
4479 ,@(when optimize (list (format nil "-O~D" optimize)))
4480 ,@cflags
4481 ,@(map-options
4482 "-D" definitions
4483 #'(lambda (definition)
4484 (if (atom definition)
4485 definition
4486 (apply #'format nil "~A=~A" definition))))
4487 ,@(map-options "-I" include-paths #'truename)
4488 ,(namestring (truename filename))
4489 "-o"
4490 ,(namestring (translate-logical-pathname output-file))
4491 ,@(map-options "-L" library-paths #'truename)
4492 ,@(map-options "-l" libraries))))
4494 (multiple-value-bind (output-file warnings fatal-errors)
4495 (run-compiler *c-compiler*
4496 arguments
4497 output-file
4498 error-file
4499 error-output
4500 verbose)
4501 (if (and error (or (not output-file) fatal-errors))
4502 (error "Compilation failed")
4503 (values output-file warnings fatal-errors))))))
4506 (define-language :c
4507 :compiler #'c-compile-file
4508 :loader #+:lucid #'load-foreign-files
4509 #+:allegro #'load
4510 #+(or :cmu :scl) #'alien:load-foreign
4511 #+:sbcl #'sb-alien:load-foreign
4512 #+(and :lispworks :unix (not :linux) (not :macosx)) #'link-load:read-foreign-modules
4513 #+(and :lispworks :unix (or :linux :macosx)) #'fli:register-module
4514 #+(and :lispworks :win32) #'fli:register-module
4515 #+(or :ecl :gcl :kcl) #'load ; should be enough.
4516 #-(or :lucid
4517 :allegro
4518 :cmu
4519 :sbcl
4520 :scl
4521 :lispworks
4522 :ecl :gcl :kcl)
4523 (lambda (&rest args)
4524 (declare (ignore args))
4525 (cerror "Continue returning NIL."
4526 "Loader not defined for C foreign libraries in ~A ~A."
4527 (lisp-implementation-type)
4528 (lisp-implementation-version)))
4529 :source-extension "c"
4530 :binary-extension "o")
4533 ;;; Fortran Language definitions.
4534 ;;; From Matlisp.
4536 (export '(*fortran-compiler* *fortran-options*))
4538 (defparameter *fortran-compiler* "g77")
4539 (defparameter *fortran-options* '("-O"))
4541 (defun fortran-compile-file (filename &rest args
4542 &key output-file error-file
4543 &allow-other-keys)
4544 (declare (ignore error-file args))
4545 (let ((arg-list
4546 (append *fortran-options*
4547 `("-c" ,filename ,@(if output-file `("-o" ,output-file))))))
4548 (run-unix-program *fortran-compiler* arg-list)))
4551 (mk:define-language :fortran
4552 :compiler #'fortran-compile-file
4553 :loader #'identity
4554 :source-extension "f"
4555 :binary-extension "o")
4558 ;;; AR support.
4559 ;; How to create a library (archive) of object files
4561 (export '(*ar-program* build-lib))
4563 (defparameter *ar-program* "ar")
4565 (defun build-lib (libname directory)
4566 (let ((args (list "rv" (truename libname))))
4567 (format t ";;; Building archive ~A~%" libname)
4568 (run-unix-program *ar-program*
4569 (append args
4570 (mapcar #'truename (directory directory))))))
4573 ;;; ********************************
4574 ;;; Component Operations ***********
4575 ;;; ********************************
4576 ;;; Define :compile/compile and :load/load operations
4577 (eval-when (load eval)
4578 (component-operation :compile 'compile-and-load-operation)
4579 (component-operation 'compile 'compile-and-load-operation)
4580 (component-operation :load 'load-file-operation)
4581 (component-operation 'load 'load-file-operation)
4584 (defun compile-and-load-operation (component force)
4585 ;; FORCE was CHANGED. this caused defsystem during compilation to only
4586 ;; load files that it immediately compiled.
4587 (let ((changed (compile-file-operation component force)))
4588 ;; Return T if the file had to be recompiled and reloaded.
4589 (if (and changed (component-compile-only component))
4590 ;; For files which are :compile-only T, compiling the file
4591 ;; satisfies the need to load.
4592 changed
4593 ;; If the file wasn't compiled, or :compile-only is nil,
4594 ;; check to see if it needs to be loaded.
4595 (and (load-file-operation component force) ; FORCE was CHANGED ???
4596 changed))))
4598 (defun unmunge-lucid (namestring)
4599 ;; Lucid's implementation of COMPILE-FILE is non-standard, in that
4600 ;; when the :output-file is a relative pathname, it tries to munge
4601 ;; it with the directory of the source file. For example,
4602 ;; (compile-file "src/globals.lisp" :output-file "bin/globals.sbin")
4603 ;; tries to stick the file in "./src/bin/globals.sbin" instead of
4604 ;; "./bin/globals.sbin" like any normal lisp. This hack seems to fix the
4605 ;; problem. I wouldn't have expected this problem to occur with any
4606 ;; use of defsystem, but some defsystem users are depending on
4607 ;; using relative pathnames (at least three folks reported the problem).
4608 (cond ((null-string namestring) namestring)
4609 ((char= (char namestring 0) #\/)
4610 ;; It's an absolute namestring
4611 namestring)
4613 ;; Ugly, but seems to fix the problem.
4614 (concatenate 'string "./" namestring))))
4616 ;; Define our own version of ensure-directories-exist for gcl, if gcl
4617 ;; doesn't have it. (gcl 2.6.10 has ensure-directories-exist).
4618 #+#.(cl:if (cl:and (cl:member :gcl cl:*features*) (cl:not (cl:fboundp (cl:find-symbol "ENSURE-DIRECTORIES-EXIST" "COMMON-LISP")))) '(and) '(or))
4619 (defun ensure-directories-exist (pathspec &key verbose)
4620 (declare (ignore verbose))
4621 ;; A very gross implementation of ensure-directories-exist. Just
4622 ;; call /bin/mkdir with our desired path.
4623 (let* ((dir (make-pathname :host (pathname-host pathspec)
4624 :device (pathname-device pathspec)
4625 :directory (pathname-directory pathspec)))
4626 (cmd (if (member :win32 *features*)
4627 (format nil "mkdir \"~a\""
4628 (coerce (subst #\\ #\/ (coerce (namestring dir) 'list)) 'string))
4629 (format nil "/bin/mkdir -p ~S" (namestring dir)))))
4630 (unless (directory dir)
4631 (lisp:system cmd))
4632 ;; The second return value is supposed to be T if directories were
4633 ;; created. I don't know how to tell that, so we just return T.
4634 ;; (Would NIL be better?)
4635 (values pathspec t)))
4637 (defun compile-file-operation (component force)
4638 ;; Returns T if the file had to be compiled.
4639 (let ((must-compile
4640 ;; For files which are :load-only T, loading the file
4641 ;; satisfies the demand to recompile.
4642 (and (null (component-load-only component)) ; not load-only
4643 (or (find force '(:all :new-source-all t) :test #'eq)
4644 (and (find force '(:new-source :new-source-and-dependents)
4645 :test #'eq)
4646 (needs-compilation component nil)))))
4647 (source-pname (component-full-pathname component :source)))
4649 (cond ((and must-compile (probe-file source-pname))
4650 (with-tell-user ("Compiling source" component :source)
4651 (let ((output-file
4652 #+:lucid
4653 (unmunge-lucid (component-full-pathname component
4654 :binary))
4655 #-:lucid
4656 (component-full-pathname component :binary)))
4658 ;; make certain the directory we need to write to
4659 ;; exists [pvaneynd@debian.org 20001114]
4660 ;; Added PATHNAME-HOST following suggestion by John
4661 ;; DeSoi [marcoxa@sourceforge.net 20020529]
4663 (ensure-directories-exist
4664 (make-pathname :name nil
4665 :type nil
4666 :version nil
4667 :defaults output-file))
4669 (or *oos-test*
4670 (apply (compile-function component)
4671 source-pname
4672 :output-file
4673 output-file
4674 #+(or :cmu :scl) :error-file
4675 #+(or :cmu :scl) (and *cmu-errors-to-file*
4676 (component-full-pathname component
4677 :error))
4678 #+CMU
4679 :error-output
4680 #+CMU
4681 *cmu-errors-to-terminal*
4682 (component-compiler-options component)
4683 ))))
4684 must-compile)
4685 (must-compile
4686 (tell-user "Source file not found. Not compiling"
4687 component :source :no-dots :force)
4688 nil)
4689 (t nil))))
4691 ;; see CLOCC/PORT/sys.lisp:compiled-file-p
4692 (eval-when (load eval compile)
4693 (when (find-package :port)
4694 (import (find-symbol (symbol-name '#:compiled-file-p) :port))))
4695 (unless (fboundp 'compiled-file-p)
4696 (defun compiled-file-p (file-name)
4697 "Return T if the FILE-NAME is a filename designator for a valid compiled.
4698 Signal an error when it is not a filename designator.
4699 Return NIL when the file does not exist, or is not readable,
4700 or does not contain valid compiled code."
4701 (declare (ignorable file-name))
4702 #+clisp
4703 (with-open-file (in file-name :direction :input :if-does-not-exist nil)
4704 (and in (char= #\( (peek-char nil in))
4705 (let ((form (ignore-errors (read in nil nil))))
4706 (and (consp form)
4707 (eq (car form) 'SYSTEM::VERSION)
4708 (null (nth-value 1 (ignore-errors (eval form))))))))
4709 #-clisp t))
4711 (defun needs-compilation (component force)
4712 ;; If there is no binary, or it is older than the source
4713 ;; file, then the component needs to be compiled.
4714 ;; Otherwise we only need to recompile if it depends on a file that changed.
4715 (declare (ignore force))
4716 (let ((source-pname (component-full-pathname component :source))
4717 (binary-pname (component-full-pathname component :binary)))
4718 (and
4719 ;; source must exist
4720 (probe-file source-pname)
4722 ;; We force recompilation.
4723 #|(find force '(:all :new-source-all) :test #'eq)|#
4724 ;; no binary
4725 (null (probe-file binary-pname))
4726 ;; old binary
4727 (< (file-write-date binary-pname)
4728 (file-write-date source-pname))
4729 ;; invalid binary
4730 #+clisp (not (compiled-file-p binary-pname))))))
4733 (defun needs-loading (component &optional (check-source t) (check-binary t))
4734 ;; Compares the component's load-time against the file-write-date of
4735 ;; the files on disk.
4736 (let ((load-time (component-load-time component))
4737 (source-pname (component-full-pathname component :source))
4738 (binary-pname (component-full-pathname component :binary)))
4740 #|| ISI Extension ||#
4741 (component-load-always component)
4743 ;; File never loaded.
4744 (null load-time)
4745 ;; Binary is newer.
4746 (when (and check-binary
4747 (probe-file binary-pname))
4748 (< load-time
4749 (file-write-date binary-pname)))
4750 ;; Source is newer.
4751 (when (and check-source
4752 (probe-file source-pname))
4753 (< load-time
4754 (file-write-date source-pname))))))
4756 ;;; Need to completely rework this function...
4757 (defun load-file-operation (component force)
4758 ;; Returns T if the file had to be loaded
4759 (let* ((binary-pname (component-full-pathname component :binary))
4760 (source-pname (component-full-pathname component :source))
4761 (binary-exists (probe-file binary-pname))
4762 (source-exists (probe-file source-pname))
4763 (source-needs-loading (needs-loading component t nil))
4764 (binary-needs-loading (needs-loading component nil t))
4765 ;; needs-compilation has an implicit source-exists in it.
4766 (needs-compilation (if (component-load-only component)
4767 source-needs-loading
4768 (needs-compilation component force)))
4769 (check-for-new-source
4770 ;; If force is :new-source*, we're checking for files
4771 ;; whose source is newer than the compiled versions.
4772 (find force '(:new-source :new-source-and-dependents :new-source-all)
4773 :test #'eq))
4774 (load-binary (or (find force '(:all :new-source-all t) :test #'eq)
4775 binary-needs-loading))
4776 (load-source
4777 (or *load-source-instead-of-binary*
4778 (and load-binary (component-load-only component))
4779 (and check-for-new-source needs-compilation)))
4780 (compile-and-load
4781 (and needs-compilation
4782 (or load-binary check-for-new-source)
4783 (compile-and-load-source-if-no-binary component)))
4785 ;; When we're trying to minimize the files loaded to only those
4786 ;; that need be, restrict the values of load-source and load-binary
4787 ;; so that we only load the component if the files are newer than
4788 ;; the load-time.
4789 (when (and *minimal-load*
4790 (not (find force '(:all :new-source-all)
4791 :test #'eq)))
4792 (when load-source (setf load-source source-needs-loading))
4793 (when load-binary (setf load-binary binary-needs-loading)))
4795 (when (or load-source load-binary compile-and-load)
4796 (cond (compile-and-load
4797 ;; If we're loading the binary and it is old or nonexistent,
4798 ;; and the user says yes, compile and load the source.
4799 (compile-file-operation component t)
4800 (with-tell-user ("Loading binary" component :binary)
4801 (or *oos-test*
4802 (progn
4803 (funcall (load-function component) binary-pname)
4804 (setf (component-load-time component)
4805 (file-write-date binary-pname)))))
4807 ((and source-exists
4808 (or (and load-source ; implicit needs-comp...
4809 (or *load-source-instead-of-binary*
4810 (component-load-only component)
4811 (not *compile-during-load*)))
4812 (and load-binary
4813 (not binary-exists)
4814 (load-source-if-no-binary component))))
4815 ;; Load the source if the source exists and:
4816 ;; o we're loading binary and it doesn't exist
4817 ;; o we're forcing it
4818 ;; o we're loading new source and user wasn't asked to compile
4819 (with-tell-user ("Loading source" component :source)
4820 (or *oos-test*
4821 (progn
4822 (funcall (load-function component) source-pname)
4823 (setf (component-load-time component)
4824 (file-write-date source-pname)))))
4826 ((and binary-exists load-binary)
4827 (with-tell-user ("Loading binary" component :binary)
4828 (or *oos-test*
4829 (progn
4830 (funcall (load-function component) binary-pname)
4831 (setf (component-load-time component)
4832 (file-write-date binary-pname)))))
4834 ((and (not binary-exists) (not source-exists))
4835 (tell-user-no-files component :force)
4836 (when *files-missing-is-an-error*
4837 (cerror "Continue, ignoring missing files."
4838 "~&Source file ~S ~:[and binary file ~S ~;~]do not exist."
4839 source-pname
4840 (or *load-source-if-no-binary*
4841 *load-source-instead-of-binary*)
4842 binary-pname))
4843 nil)
4845 nil)))))
4847 (eval-when (load eval)
4848 (component-operation :clean 'delete-binaries-operation)
4849 (component-operation 'clean 'delete-binaries-operation)
4850 (component-operation :delete-binaries 'delete-binaries-operation)
4851 (component-operation 'delete-binaries 'delete-binaries-operation)
4853 (defun delete-binaries-operation (component force)
4854 (when (or (eq force :all)
4855 (eq force t)
4856 (and (find force '(:new-source :new-source-and-dependents
4857 :new-source-all)
4858 :test #'eq)
4859 (needs-compilation component nil)))
4860 (let ((binary-pname (component-full-pathname component :binary)))
4861 (when (probe-file binary-pname)
4862 (with-tell-user ("Deleting binary" component :binary)
4863 (or *oos-test*
4864 (delete-file binary-pname)))))))
4867 ;; when the operation = :compile, we can assume the binary exists in test mode.
4868 ;; ((and *oos-test*
4869 ;; (eq operation :compile)
4870 ;; (probe-file (component-full-pathname component :source)))
4871 ;; (with-tell-user ("Loading binary" component :binary)))
4873 (defun binary-exists (component)
4874 (probe-file (component-full-pathname component :binary)))
4876 ;;; or old-binary
4877 (defun compile-and-load-source-if-no-binary (component)
4878 (when (not (or *load-source-instead-of-binary*
4879 (and *load-source-if-no-binary*
4880 (not (binary-exists component)))))
4881 (cond ((component-load-only component)
4883 (let ((prompt (prompt-string component)))
4884 (format t "~A- File ~A is load-only, ~
4885 ~&~A not compiling."
4886 prompt
4887 (component-full-pathname component :source)
4888 prompt))
4890 nil)
4891 ((eq *compile-during-load* :query)
4892 (let* ((prompt (prompt-string component))
4893 (compile-source
4894 (y-or-n-p-wait
4895 #\y 30
4896 "~A- Binary file ~A is old or does not exist. ~
4897 ~&~A Compile (and load) source file ~A instead? "
4898 prompt
4899 (component-full-pathname component :binary)
4900 prompt
4901 (component-full-pathname component :source))))
4902 (unless (y-or-n-p-wait
4903 #\y 30
4904 "~A- Should I bother you if this happens again? "
4905 prompt)
4906 (setq *compile-during-load*
4907 (y-or-n-p-wait
4908 #\y 30
4909 "~A- Should I compile while loading the system? "
4910 prompt))) ; was compile-source, then t
4911 compile-source))
4912 (*compile-during-load*)
4913 (t nil))))
4915 (defun load-source-if-no-binary (component)
4916 (and (not *load-source-instead-of-binary*)
4917 (or (and *load-source-if-no-binary*
4918 (not (binary-exists component)))
4919 (component-load-only component)
4920 (when *bother-user-if-no-binary*
4921 (let* ((prompt (prompt-string component))
4922 (load-source
4923 (y-or-n-p-wait #\y 30
4924 "~A- Binary file ~A does not exist. ~
4925 ~&~A Load source file ~A instead? "
4926 prompt
4927 (component-full-pathname component :binary)
4928 prompt
4929 (component-full-pathname component :source))))
4930 (setq *bother-user-if-no-binary*
4931 (y-or-n-p-wait #\n 30
4932 "~A- Should I bother you if this happens again? "
4933 prompt ))
4934 (unless *bother-user-if-no-binary*
4935 (setq *load-source-if-no-binary* load-source))
4936 load-source)))))
4938 ;;; ********************************
4939 ;;; Allegro Toplevel Commands ******
4940 ;;; ********************************
4941 ;;; Creates toplevel command aliases for Allegro CL.
4942 #+:allegro
4943 (top-level:alias ("compile-system" 8)
4944 (system &key force (minimal-load mk:*minimal-load*)
4945 test verbose version)
4946 "Compile the specified system"
4948 (mk:compile-system system :force force
4949 :minimal-load minimal-load
4950 :test test :verbose verbose
4951 :version version))
4953 #+:allegro
4954 (top-level:alias ("load-system" 5)
4955 (system &key force (minimal-load mk:*minimal-load*)
4956 (compile-during-load mk:*compile-during-load*)
4957 test verbose version)
4958 "Compile the specified system"
4960 (mk:load-system system :force force
4961 :minimal-load minimal-load
4962 :compile-during-load compile-during-load
4963 :test test :verbose verbose
4964 :version version))
4966 #+:allegro
4967 (top-level:alias ("show-system" 5) (system)
4968 "Show information about the specified system."
4970 (mk:describe-system system))
4972 #+:allegro
4973 (top-level:alias ("describe-system" 9) (system)
4974 "Show information about the specified system."
4976 (mk:describe-system system))
4978 #+:allegro
4979 (top-level:alias ("system-source-size" 9) (system)
4980 "Show size information about source files in the specified system."
4982 (mk:system-source-size system))
4984 #+:allegro
4985 (top-level:alias ("clean-system" 6)
4986 (system &key force test verbose version)
4987 "Delete binaries in the specified system."
4989 (mk:clean-system system :force force
4990 :test test :verbose verbose
4991 :version version))
4993 #+:allegro
4994 (top-level:alias ("edit-system" 7)
4995 (system &key force test verbose version)
4996 "Load system source files into Emacs."
4998 (mk:edit-system system :force force
4999 :test test :verbose verbose
5000 :version version))
5002 #+:allegro
5003 (top-level:alias ("hardcopy-system" 9)
5004 (system &key force test verbose version)
5005 "Hardcopy files in the specified system."
5007 (mk:hardcopy-system system :force force
5008 :test test :verbose verbose
5009 :version version))
5011 #+:allegro
5012 (top-level:alias ("make-system-tag-table" 13) (system)
5013 "Make an Emacs TAGS file for source files in specified system."
5015 (mk:make-system-tag-table system))
5018 ;;; ********************************
5019 ;;; Allegro Make System Fasl *******
5020 ;;; ********************************
5021 #+:excl
5022 (defun allegro-make-system-fasl (system destination
5023 &optional (include-dependents t))
5024 (excl:shell
5025 (format nil "rm -f ~A; cat~{ ~A~} > ~A"
5026 destination
5027 (if include-dependents
5028 (files-in-system-and-dependents system :all :binary)
5029 (files-in-system system :all :binary))
5030 destination)))
5032 (defun files-which-need-compilation (system)
5033 (mapcar #'(lambda (comp) (component-full-pathname comp :source))
5034 (remove nil
5035 (file-components-in-component
5036 (find-system system :load) :new-source))))
5038 (defun files-in-system-and-dependents (name &optional (force :all)
5039 (type :source) version)
5040 ;; Returns a list of the pathnames in system and dependents in load order.
5041 (let ((system (find-system name :load)))
5042 (multiple-value-bind (*version-dir* *version-replace*)
5043 (translate-version version)
5044 (let ((*version* version))
5045 (let ((result (file-pathnames-in-component system type force)))
5046 (dolist (dependent (reverse (component-depends-on system)))
5047 (setq result
5048 (append (files-in-system-and-dependents dependent
5049 force type version)
5050 result)))
5051 result)))))
5053 (defun files-in-system (name &optional (force :all) (type :source) version)
5054 ;; Returns a list of the pathnames in system in load order.
5055 (let ((system (if (and (component-p name)
5056 (member (component-type name) '(:defsystem :system :subsystem)))
5057 name
5058 (find-system name :load))))
5059 (multiple-value-bind (*version-dir* *version-replace*)
5060 (translate-version version)
5061 (let ((*version* version))
5062 (file-pathnames-in-component system type force)))))
5064 (defun file-pathnames-in-component (component type &optional (force :all))
5065 (mapcar #'(lambda (comp) (component-full-pathname comp type))
5066 (file-components-in-component component force)))
5068 (defun file-components-in-component (component &optional (force :all)
5069 &aux result changed)
5070 (case (component-type component)
5071 ((:file :private-file)
5072 (when (setq changed
5073 (or (find force '(:all t) :test #'eq)
5074 (and (not (non-empty-listp force))
5075 (needs-compilation component nil))))
5076 (setq result
5077 (list component))))
5078 ((:module :system :subsystem :defsystem)
5079 (dolist (module (component-components component))
5080 (multiple-value-bind (r c)
5081 (file-components-in-component
5082 module
5083 (cond ((and (some #'(lambda (dependent)
5084 (member dependent changed))
5085 (component-depends-on module))
5086 (or (non-empty-listp force)
5087 (eq force :new-source-and-dependents)))
5088 ;; The component depends on a changed file and force agrees.
5089 :all)
5090 ((and (non-empty-listp force)
5091 (member (component-name module) force
5092 :test #'string-equal :key #'string))
5093 ;; Force is a list of modules and the component is
5094 ;; one of them.
5095 :all)
5096 (t force)))
5097 (when c
5098 (push module changed)
5099 (setq result (append result r)))))))
5100 (values result changed))
5102 (setf (symbol-function 'oos) (symbol-function 'operate-on-system))
5104 ;;; ********************************
5105 ;;; Additional Component Operations
5106 ;;; ********************************
5108 ;;; *** Edit Operation ***
5110 ;;; Should this conditionalization be (or :mcl (and :CCL (not :lispworks)))?
5112 #+:ccl
5113 (defun edit-operation (component force)
5114 "Always returns nil, i.e. component not changed."
5115 (declare (ignore force))
5117 (let* ((full-pathname (make::component-full-pathname component :source))
5118 (already-editing\? #+:mcl (dolist (w (CCL:windows :class
5119 'fred-window))
5120 (when (equal (CCL:window-filename w)
5121 full-pathname)
5122 (return w)))
5123 #-:mcl nil))
5124 (if already-editing\?
5125 #+:mcl (CCL:window-select already-editing\?) #-:mcl nil
5126 (ed full-pathname)))
5127 nil)
5129 #+:allegro
5130 (defun edit-operation (component force)
5131 "Edit a component - always returns nil, i.e. component not changed."
5132 (declare (ignore force))
5133 (let ((full-pathname (component-full-pathname component :source)))
5134 (ed full-pathname))
5135 nil)
5137 #+(or :ccl :allegro)
5138 (make::component-operation :edit 'edit-operation)
5139 #+(or :ccl :allegro)
5140 (make::component-operation 'edit 'edit-operation)
5143 ;;; *** Hardcopy System ***
5144 (defparameter *print-command* "enscript -2Gr" ; "lpr"
5145 "Command to use for printing files on UNIX systems.")
5146 #+:allegro
5147 (defun hardcopy-operation (component force)
5148 "Hardcopy a component - always returns nil, i.e. component not changed."
5149 (declare (ignore force))
5150 (let ((full-pathname (component-full-pathname component :source)))
5151 (excl:run-shell-command (format nil "~A ~A"
5152 *print-command* full-pathname)))
5153 nil)
5155 #+:allegro
5156 (make::component-operation :hardcopy 'hardcopy-operation)
5157 #+:allegro
5158 (make::component-operation 'hardcopy 'hardcopy-operation)
5161 ;;; *** System Source Size ***
5163 (defun system-source-size (system-name &optional (force :all))
5164 "Prints a short report and returns the size in bytes of the source files in
5165 <system-name>."
5166 (let* ((file-list (files-in-system system-name force :source))
5167 (total-size (file-list-size file-list)))
5168 (format t "~&~a/~a (~:d file~:p) totals ~:d byte~:p (~:d kB)"
5169 system-name force (length file-list)
5170 total-size (round total-size 1024))
5171 total-size))
5173 (defun file-list-size (file-list)
5174 "Returns the size in bytes of the files in <file-list>."
5176 (let ((total-size 0))
5177 (dolist (file file-list)
5178 (with-open-file (stream file)
5179 (incf total-size (file-length stream))))
5180 total-size))
5182 ;;; *** System Tag Table ***
5184 #+:allegro
5185 (defun make-system-tag-table (system-name)
5186 "Makes an Emacs tag table using the GNU etags program."
5187 (let ((files-in-system (files-in-system system-name :all :source)))
5189 (format t "~&Making tag table...")
5190 (excl:run-shell-command (format nil "etags ~{~a ~}" files-in-system))
5191 (format t "done.~%")))
5194 ;;; end of file -- defsystem.lisp --