Windows installer: update Gnuplot
[maxima.git] / lisp-utils / defsystem.lisp
blobdda669d268ad1134f932a55ac156957ac1bcee1f
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 (namestring
1897 (make-pathname :host host
1898 :device device
1899 :directory
1900 directory
1901 :name
1902 #-(or :gcl :sbcl :MCL :clisp :cmu) rel-file
1903 #+(or :gcl :sbcl :MCL :clisp :cmu) rel-name
1905 #+(or :gcl :sbcl :MCL :clisp :cmu) :type
1906 #+(or :gcl :sbcl :MCL :clisp :cmu) rel-type
1907 ))))
1908 ;(trace new-append-directories)
1910 #-scl
1911 (defun directory-to-list (directory)
1912 ;; The directory should be a list, but nonstandard implementations have
1913 ;; been known to use a vector or even a string.
1914 (cond ((listp directory)
1915 directory)
1916 ((stringp directory)
1917 (cond ((find #\; directory)
1918 ;; It's probably a logical pathname, so split at the
1919 ;; semicolons:
1920 (split-string directory :item #\;))
1921 #+MCL
1922 ((and (find #\: directory)
1923 (not (find #\/ directory)))
1924 ;; It's probably a MCL pathname, so split at the colons.
1925 (split-string directory :item #\:))
1927 ;; It's probably a unix pathname, so split at the slash.
1928 (split-string directory :item #\/))))
1930 (coerce directory 'list))))
1931 ;(trace directory-to-list)
1934 (defparameter *append-dirs-tests*
1935 '("~/foo/" "baz/bar.lisp"
1936 "~/foo" "baz/bar.lisp"
1937 "/foo/bar/" "baz/barf.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/" nil
1944 "foo/bar/" nil
1945 "foo/bar" nil
1946 "foo" nil
1947 "foo" ""
1948 nil "baz/barf.lisp"
1949 nil "/baz/barf.lisp"
1950 nil nil))
1952 (defun test-new-append-directories (&optional (test-dirs *append-dirs-tests*))
1953 (do* ((dir-list test-dirs (cddr dir-list))
1954 (abs-dir (car dir-list) (car dir-list))
1955 (rel-dir (cadr dir-list) (cadr dir-list)))
1956 ((null dir-list) (values))
1957 (format t "~&ABS: ~S ~18TREL: ~S ~41TResult: ~S"
1958 abs-dir rel-dir (new-append-directories abs-dir rel-dir))))
1961 <cl> (test-new-append-directories)
1963 ABS: "~/foo/" REL: "baz/bar.lisp" Result: "/usr0/mkant/foo/baz/bar.lisp"
1964 ABS: "~/foo" REL: "baz/bar.lisp" Result: "/usr0/mkant/foo/baz/bar.lisp"
1965 ABS: "/foo/bar/" REL: "baz/barf.lisp" Result: "/foo/bar/baz/barf.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: NIL Result: "/foo/bar/"
1972 ABS: "foo/bar/" REL: NIL Result: "foo/bar/"
1973 ABS: "foo/bar" REL: NIL Result: "foo/bar/"
1974 ABS: "foo" REL: NIL Result: "foo/"
1975 ABS: "foo" REL: "" Result: "foo/"
1976 ABS: NIL REL: "baz/barf.lisp" Result: "baz/barf.lisp"
1977 ABS: NIL REL: "/baz/barf.lisp" Result: "/baz/barf.lisp"
1978 ABS: NIL REL: NIL Result: ""
1982 (defun append-directories (absolute-directory relative-directory)
1983 "There is no CL primitive for tacking a subdirectory onto a directory.
1984 We need such a function because defsystem has both absolute and
1985 relative pathnames in the modules. This is a somewhat ugly hack which
1986 seems to work most of the time. We assume that ABSOLUTE-DIRECTORY
1987 is a directory, with no filename stuck on the end. Relative-directory,
1988 however, may have a filename stuck on the end."
1989 (when (or absolute-directory relative-directory)
1990 (cond
1991 ;; KMR commented out because: when appending two logical pathnames,
1992 ;; using this code translates the first logical pathname then appends
1993 ;; the second logical pathname -- an error.
1995 ;; We need a reliable way to determine if a pathname is logical.
1996 ;; Allegro 4.1 does not recognize the syntax of a logical pathname
1997 ;; as being logical unless its logical host is already defined.
1999 #+(or (and allegro-version>= (version>= 4 1))
2000 :logical-pathnames-mk)
2001 ((and absolute-directory
2002 (logical-pathname-p absolute-directory)
2003 relative-directory)
2004 ;; For use with logical pathnames package.
2005 (append-logical-directories-mk absolute-directory relative-directory))
2007 #-scl
2008 ((namestring-probably-logical absolute-directory)
2009 ;; A simplistic stab at handling logical pathnames
2010 (append-logical-pnames absolute-directory relative-directory))
2011 #-scl
2013 ;; In VMS, merge-pathnames actually does what we want!!!
2014 #+:VMS
2015 (namestring (merge-pathnames (or absolute-directory "")
2016 (or relative-directory "")))
2017 #+:macl1.3.2
2018 (namestring (make-pathname :directory absolute-directory
2019 :name relative-directory))
2020 ;; Cross your fingers and pray.
2021 #-(or :VMS :macl1.3.2)
2022 (new-append-directories absolute-directory relative-directory))
2023 #+scl
2025 (let ((absolute (pathname (or absolute-directory ""))))
2026 (when (or (pathname-name absolute) (pathname-type absolute))
2027 (let* ((directory (or (pathname-directory absolute) '(:relative)))
2028 (directory (append directory (list (file-namestring absolute)))))
2029 (setf absolute (make-pathname :directory directory
2030 :name nil
2031 :type nil
2032 :version nil
2033 :defaults absolute))))
2034 (ext:resolve-pathname (or relative-directory "")
2035 absolute))))))
2038 #+:logical-pathnames-mk
2039 (defun append-logical-directories-mk (absolute-dir relative-dir)
2040 (lp:append-logical-directories absolute-dir relative-dir))
2043 ;;; append-logical-pathnames-mk --
2044 ;;; The following is probably still bogus and it does not solve the
2045 ;;; problem of appending two logical pathnames.
2046 ;;; Anyway, as per suggetsion by KMR, the function is not called
2047 ;;; anymore.
2048 ;;; Hopefully this will not cause problems for ACL.
2050 #+(and (and allegro-version>= (version>= 4 1))
2051 (not :logical-pathnames-mk))
2052 (defun append-logical-directories-mk (absolute-dir relative-dir)
2053 ;; We know absolute-dir and relative-dir are non nil. Moreover
2054 ;; absolute-dir is a logical pathname.
2055 (setq absolute-dir (logical-pathname absolute-dir))
2056 (etypecase relative-dir
2057 (string (setq relative-dir (parse-namestring relative-dir)))
2058 (pathname #| do nothing |#))
2060 (translate-logical-pathname
2061 (merge-pathnames relative-dir absolute-dir)))
2063 #| Old version 2002-03-02
2064 #+(and (and allegro-version>= (version>= 4 1))
2065 (not :logical-pathnames-mk))
2066 (defun append-logical-directories-mk (absolute-dir relative-dir)
2067 ;; We know absolute-dir and relative-dir are non nil. Moreover
2068 ;; absolute-dir is a logical pathname.
2069 (setq absolute-dir (logical-pathname absolute-dir))
2070 (etypecase relative-dir
2071 (string (setq relative-dir (parse-namestring relative-dir)))
2072 (pathname #| do nothing |#))
2074 (translate-logical-pathname
2075 (make-pathname
2076 :host (or (pathname-host absolute-dir)
2077 (pathname-host relative-dir))
2078 :directory (append (pathname-directory absolute-dir)
2079 (cdr (pathname-directory relative-dir)))
2080 :name (or (pathname-name absolute-dir)
2081 (pathname-name relative-dir))
2082 :type (or (pathname-type absolute-dir)
2083 (pathname-type relative-dir))
2084 :version (or (pathname-version absolute-dir)
2085 (pathname-version relative-dir)))))
2087 ;; Old version
2088 #+(and (and allegro-version>= (version>= 4 1))
2089 (not :logical-pathnames-mk))
2090 (defun append-logical-directories-mk (absolute-dir relative-dir)
2091 (when (or absolute-dir relative-dir)
2092 (setq absolute-dir (logical-pathname (or absolute-dir ""))
2093 relative-dir (logical-pathname (or relative-dir "")))
2094 (translate-logical-pathname
2095 (make-pathname
2096 :host (or (pathname-host absolute-dir)
2097 (pathname-host relative-dir))
2098 :directory (append (pathname-directory absolute-dir)
2099 (cdr (pathname-directory relative-dir)))
2100 :name (or (pathname-name absolute-dir)
2101 (pathname-name relative-dir))
2102 :type (or (pathname-type absolute-dir)
2103 (pathname-type relative-dir))
2104 :version (or (pathname-version absolute-dir)
2105 (pathname-version relative-dir))))))
2108 ;;; determines if string or pathname object is logical
2109 #+:logical-pathnames-mk
2110 (defun logical-pathname-p (thing)
2111 (eq (lp:pathname-host-type thing) :logical))
2113 ;;; From Kevin Layer for 4.1final.
2114 #+(and (and allegro-version>= (version>= 4 1))
2115 (not :logical-pathnames-mk))
2116 (defun logical-pathname-p (thing)
2117 (typep (parse-namestring thing) 'logical-pathname))
2119 #-scl
2120 (defun pathname-logical-p (thing)
2121 (typecase thing
2122 (logical-pathname t)
2123 #+clisp ; CLisp has non conformant Logical Pathnames.
2124 (pathname (pathname-logical-p (namestring thing)))
2125 (string (and (= 1 (count #\: thing)) ; Shortcut.
2126 (ignore-errors (translate-logical-pathname thing))
2128 (t nil)))
2130 ;;; This affects only one thing.
2131 ;;; 19990707 Marco Antoniotti
2132 ;;; old version
2134 #-scl
2135 (defun namestring-probably-logical (namestring)
2136 (and (stringp namestring)
2137 ;; unix pathnames don't have embedded semicolons
2138 (find #\; namestring)))
2140 ;;; New version
2141 (defun namestring-probably-logical (namestring)
2142 (and (stringp namestring)
2143 (typep (parse-namestring namestring) 'logical-pathname)))
2146 ;;; New new version
2147 ;;; 20000321 Marco Antoniotti
2148 (defun namestring-probably-logical (namestring)
2149 (pathname-logical-p namestring))
2153 #|| This is incorrect, as it strives to keep strings around, when it
2154 shouldn't. MERGE-PATHNAMES already DTRT.
2155 (defun append-logical-pnames (absolute relative)
2156 (declare (type (or null string pathname) absolute relative))
2157 (let ((abs (if absolute
2158 #-clisp (namestring absolute)
2159 #+clisp absolute ;; Stig (July 2001): hack to avoid CLISP from translating the whole string
2160 ""))
2161 (rel (if relative (namestring relative) ""))
2163 ;; Make sure the absolute directory ends with a semicolon unless
2164 ;; the pieces are null strings
2165 (unless (or (null-string abs) (null-string rel)
2166 (char= (char abs (1- (length abs)))
2167 #\;))
2168 (setq abs (concatenate 'string abs ";")))
2169 ;; Return the concatenate pathnames
2170 (concatenate 'string abs rel)))
2174 #-scl
2175 (defun append-logical-pnames (absolute relative)
2176 (declare (type (or null string pathname) absolute relative))
2177 (let ((abs (if absolute
2178 (pathname absolute)
2179 (make-pathname :directory (list :absolute)
2180 :name nil
2181 :type nil)
2183 (rel (if relative
2184 (pathname relative)
2185 (make-pathname :directory (list :relative)
2186 :name nil
2187 :type nil)
2190 ;; The following is messed up because CMUCL and LW use different
2191 ;; defaults for host (in particular LW uses NIL). Thus
2192 ;; MERGE-PATHNAMES has legitimate different behaviors on both
2193 ;; implementations. Of course this is disgusting, but that is the
2194 ;; way it is and the rest tries to circumvent this crap.
2195 (etypecase abs
2196 (logical-pathname
2197 (etypecase rel
2198 (logical-pathname
2199 (namestring (merge-pathnames rel abs)))
2200 (pathname
2201 ;; The following potentially translates the logical pathname
2202 ;; very early, but we cannot avoid it.
2203 (namestring (merge-pathnames rel (translate-logical-pathname abs))))
2205 (pathname
2206 (namestring (merge-pathnames rel abs)))
2210 ;;; This was a try at appending a subdirectory onto a directory.
2211 ;;; It failed. We're keeping this around to prevent future mistakes
2212 ;;; of a similar sort.
2213 (defun merge-directories (absolute-directory relative-directory)
2214 ;; replace concatenate with something more intelligent
2215 ;; i.e., concatenation won't work with some directories.
2216 ;; it should also behave well if the parent directory
2217 ;; has a filename at the end, or if the relative-directory ain't relative
2218 (when absolute-directory
2219 (setq absolute-directory (pathname-directory absolute-directory)))
2220 (concatenate 'string
2221 (or absolute-directory "")
2222 (or relative-directory "")))
2226 <cl> (defun d (d n) (namestring (make-pathname :directory d :name n)))
2229 <cl> (d "~/foo/" "baz/bar.lisp")
2230 "/usr0/mkant/foo/baz/bar.lisp"
2232 <cl> (d "~/foo" "baz/bar.lisp")
2233 "/usr0/mkant/foo/baz/bar.lisp"
2235 <cl> (d "/foo/bar/" "baz/barf.lisp")
2236 "/foo/bar/baz/barf.lisp"
2238 <cl> (d "foo/bar/" "baz/barf.lisp")
2239 "foo/bar/baz/barf.lisp"
2241 <cl> (d "foo/bar" "baz/barf.lisp")
2242 "foo/bar/baz/barf.lisp"
2244 <cl> (d "foo/bar" "/baz/barf.lisp")
2245 "foo/bar//baz/barf.lisp"
2247 <cl> (d "foo/bar" nil)
2248 "foo/bar/"
2250 <cl> (d nil "baz/barf.lisp")
2251 "baz/barf.lisp"
2253 <cl> (d nil nil)
2258 (defun new-file-type (pathname type)
2259 (make-pathname :type type :defaults pathname))
2262 ;;; ********************************
2263 ;;; Component Defstruct ************
2264 ;;; ********************************
2265 (defvar *source-pathname-default* nil
2266 "Default value of :source-pathname keyword in DEFSYSTEM. Set this to
2267 \"\" to avoid having to type :source-pathname \"\" all the time.")
2269 (defvar *binary-pathname-default* nil
2270 "Default value of :binary-pathname keyword in DEFSYSTEM.")
2272 ;;; Removed TIME slot, which has been made unnecessary by the new definition
2273 ;;; of topological-sort.
2275 (defstruct (topological-sort-node (:conc-name topsort-))
2276 (color :white :type (member :gray :black :white))
2277 ;; time
2280 (defstruct (component (:include topological-sort-node)
2281 (:print-function print-component))
2282 (type :file ; to pacify the CMUCL compiler (:type is alway supplied)
2283 :type (member :defsystem
2284 :system
2285 :subsystem
2286 :module
2287 :file
2288 :private-file
2290 (name nil :type (or symbol string))
2291 (indent 0 :type (mod 1024)) ; Number of characters of indent in
2292 ; verbose output to the user.
2293 host ; The pathname host (i.e., "/../a").
2294 device ; The pathname device.
2295 source-root-dir ; Relative or absolute (starts
2296 ; with "/"), directory or file
2297 ; (ends with "/").
2298 (source-pathname *source-pathname-default*)
2299 source-extension ; A string, e.g., "lisp"
2300 ; if NIL, inherit
2301 (binary-pathname *binary-pathname-default*)
2302 binary-root-dir
2303 binary-extension ; A string, e.g., "fasl". If
2304 ; NIL, uses default for
2305 ; machine-type.
2306 package ; Package for use-package.
2308 ;; The following three slots are used to provide for alternate compilation
2309 ;; and loading functions for the files contained within a component. If
2310 ;; a component has a compiler or a loader specified, those functions are
2311 ;; used. Otherwise the functions are derived from the language. If no
2312 ;; language is specified, it defaults to Common Lisp (:lisp). Other current
2313 ;; possible languages include :scheme (PseudoScheme) and :c, but the user
2314 ;; can define additional language mappings. Compilation functions should
2315 ;; accept a pathname argument and a :output-file keyword; loading functions
2316 ;; just a pathname argument. The default functions are #'compile-file and
2317 ;; #'load. Unlike fdmm's SET-LANGUAGE macro, this allows a defsystem to
2318 ;; mix languages.
2319 (language nil :type (or null symbol))
2320 (compiler nil :type (or null symbol function))
2321 (loader nil :type (or null symbol function))
2322 (compiler-options nil :type list) ; A list of compiler options to
2323 ; use for compiling this
2324 ; component. These must be
2325 ; keyword options supported by
2326 ; the compiler.
2328 (components () :type list) ; A list of components
2329 ; comprising this component's
2330 ; definition.
2331 (depends-on () :type list) ; A list of the components
2332 ; this one depends on. may
2333 ; refer only to the components
2334 ; at the same level as this
2335 ; one.
2336 proclamations ; Compiler options, such as
2337 ; '(optimize (safety 3)).
2338 initially-do ; Form to evaluate before the
2339 ; operation.
2340 finally-do ; Form to evaluate after the operation.
2341 compile-form ; For foreign libraries.
2342 load-form ; For foreign libraries.
2344 ;; load-time ; The file-write-date of the
2345 ; binary/source file loaded.
2347 ;; If load-only is T, will not compile the file on operation :compile.
2348 ;; In other words, for files which are :load-only T, loading the file
2349 ;; satisfies any demand to recompile.
2350 load-only ; If T, will not compile this
2351 ; file on operation :compile.
2352 ;; If compile-only is T, will not load the file on operation :compile.
2353 ;; Either compiles or loads the file, but not both. In other words,
2354 ;; compiling the file satisfies the demand to load it. This is useful
2355 ;; for PCL defmethod and defclass definitions, which wrap a
2356 ;; (eval-when (compile load eval) ...) around the body of the definition.
2357 ;; This saves time in some lisps.
2358 compile-only ; If T, will not load this
2359 ; file on operation :compile.
2360 #|| ISI Extension ||#
2361 load-always ; If T, will force loading
2362 ; even if file has not
2363 ; changed.
2364 ;; PVE: add banner
2365 (banner nil :type (or null string))
2367 (documentation nil :type (or null string)) ; Optional documentation slot
2371 ;;; To allow dependencies from "foreign systems" like ASDF or one of
2372 ;;; the proprietary ones like ACL or LW.
2374 (defstruct (foreign-system (:include component (type :system)))
2375 kind ; This is a keyword: (member :asdf :pcl :lispworks-common-defsystem ...)
2376 object ; The actual foreign system object.
2380 (defun register-foreign-system (name &key representation kind)
2381 (declare (type (or symbol string) name))
2382 (let ((fs (make-foreign-system :name name
2383 :kind kind
2384 :object representation)))
2385 (setf (get-system name) fs)))
2389 (define-condition missing-component (simple-condition)
2390 ((name :reader missing-component-name
2391 :initarg :name)
2392 (component :reader missing-component-component
2393 :initarg :component)
2395 #-gcl(:default-initargs :component nil)
2396 (:report (lambda (mmc stream)
2397 (format stream "MK:DEFSYSTEM: missing component ~S for ~S."
2398 (missing-component-name mmc)
2399 (missing-component-component mmc))))
2402 (define-condition missing-module (missing-component)
2404 (:report (lambda (mmc stream)
2405 (format stream "MK:DEFSYSTEM: missing module ~S for ~S."
2406 (missing-component-name mmc)
2407 (missing-component-component mmc))))
2410 (define-condition missing-system (missing-module)
2412 (:report (lambda (msc stream)
2413 (format stream "MK:DEFSYSTEM: missing system ~S~@[ for S~]."
2414 (missing-component-name msc)
2415 (missing-component-component msc))))
2420 (defvar *file-load-time-table* (make-hash-table :test #'equal)
2421 "Hash table of file-write-dates for the system definitions and
2422 files in the system definitions.")
2423 (defun component-load-time (component)
2424 (when component
2425 (etypecase component
2426 (string (gethash component *file-load-time-table*))
2427 (pathname (gethash (namestring component) *file-load-time-table*))
2428 (component
2429 (ecase (component-type component)
2430 (:defsystem
2431 (let* ((name (component-name component))
2432 (path (when name (compute-system-path name nil))))
2433 (declare (type (or string pathname null) path))
2434 (when path
2435 (gethash (namestring path) *file-load-time-table*))))
2436 ((:file :private-file)
2437 ;; Use only :source pathname to identify component's
2438 ;; load time.
2439 (let ((path (component-full-pathname component :source)))
2440 (when path
2441 (gethash path *file-load-time-table*)))))))))
2443 #-(or :cmu :scl)
2444 (defsetf component-load-time (component) (value)
2445 `(when ,component
2446 (etypecase ,component
2447 (string (setf (gethash ,component *file-load-time-table*) ,value))
2448 (pathname (setf (gethash (namestring (the pathname ,component))
2449 *file-load-time-table*)
2450 ,value))
2451 (component
2452 (ecase (component-type ,component)
2453 (:defsystem
2454 (let* ((name (component-name ,component))
2455 (path (when name (compute-system-path name nil))))
2456 (declare (type (or string pathname null) path))
2457 (when path
2458 (setf (gethash (namestring path) *file-load-time-table*)
2459 ,value))))
2460 ((:file :private-file)
2461 ;; Use only :source pathname to identify file.
2462 (let ((path (component-full-pathname ,component :source)))
2463 (when path
2464 (setf (gethash path *file-load-time-table*)
2465 ,value)))))))
2466 ,value))
2468 #+(or :cmu :scl)
2469 (defun (setf component-load-time) (value component)
2470 (declare
2471 (type (or null string pathname component) component)
2472 (type (or unsigned-byte null) value))
2473 (when component
2474 (etypecase component
2475 (string (setf (gethash component *file-load-time-table*) value))
2476 (pathname (setf (gethash (namestring (the pathname component))
2477 *file-load-time-table*)
2478 value))
2479 (component
2480 (ecase (component-type component)
2481 (:defsystem
2482 (let* ((name (component-name component))
2483 (path (when name (compute-system-path name nil))))
2484 (declare (type (or string pathname null) path))
2485 (when path
2486 (setf (gethash (namestring path) *file-load-time-table*)
2487 value))))
2488 ((:file :private-file)
2489 ;; Use only :source pathname to identify file.
2490 (let ((path (component-full-pathname component :source)))
2491 (when path
2492 (setf (gethash path *file-load-time-table*)
2493 value)))))))
2494 value))
2497 ;;; compute-system-path --
2499 (defun compute-system-path (module-name definition-pname)
2500 (let* ((module-string-name
2501 (etypecase module-name
2502 (symbol (string-downcase
2503 (string module-name)))
2504 (string module-name)))
2506 (file-pathname
2507 (make-pathname :name module-string-name
2508 :type *system-extension*))
2510 (lib-file-pathname
2511 (make-pathname ;:directory (list :relative module-string-name)
2512 :name module-string-name
2513 :type *system-extension*))
2515 (or (when definition-pname ; given pathname for system def
2516 (probe-file definition-pname))
2517 ;; Then the central registry. Note that we also check the current
2518 ;; directory in the registry, but the above check is hard-coded.
2519 (cond (*central-registry*
2520 (if (listp *central-registry*)
2521 (dolist (registry *central-registry*)
2522 (let ((file (or (probe-file
2523 (append-directories (if (consp registry)
2524 (eval registry)
2525 registry)
2526 file-pathname))
2527 (probe-file
2528 (append-directories (if (consp registry)
2529 (eval registry)
2530 registry)
2531 lib-file-pathname))
2534 (when file (return file))))
2535 (or (probe-file (append-directories *central-registry*
2536 file-pathname))
2537 (probe-file (append-directories *central-registry*
2538 lib-file-pathname))
2542 ;; No central registry. Assume current working directory.
2543 ;; Maybe this should be an error?
2544 (or (probe-file file-pathname)
2545 (probe-file lib-file-pathname)))))
2549 (defun system-definition-pathname (system-name)
2550 (let ((system (ignore-errors (find-system system-name :error))))
2551 (if system
2552 (let ((system-def-pathname
2553 (make-pathname :type "system"
2554 :defaults (pathname (component-full-pathname system :source))))
2556 (values system-def-pathname
2557 (probe-file system-def-pathname)))
2558 (values nil nil))))
2565 (defun compute-system-path (module-name definition-pname)
2566 (let* ((filename (format nil "~A.~A"
2567 (if (symbolp module-name)
2568 (string-downcase (string module-name))
2569 module-name)
2570 *system-extension*)))
2571 (or (when definition-pname ; given pathname for system def
2572 (probe-file definition-pname))
2573 ;; Then the central registry. Note that we also check the current
2574 ;; directory in the registry, but the above check is hard-coded.
2575 (cond (*central-registry*
2576 (if (listp *central-registry*)
2577 (dolist (registry *central-registry*)
2578 (let ((file (probe-file
2579 (append-directories (if (consp registry)
2580 (eval registry)
2581 registry)
2582 filename))))
2583 (when file (return file))))
2584 (probe-file (append-directories *central-registry*
2585 filename))))
2587 ;; No central registry. Assume current working directory.
2588 ;; Maybe this should be an error?
2589 (probe-file filename))))))
2593 (defvar *reload-systems-from-disk* t
2594 "If T, always tries to reload newer system definitions from disk.
2595 Otherwise first tries to find the system definition in the current
2596 environment.")
2598 (defun find-system (system-name &optional (mode :ask) definition-pname)
2599 "Returns the system named SYSTEM-NAME.
2600 If not already loaded, loads it, depending on the value of
2601 *RELOAD-SYSTEMS-FROM-DISK* and of the value of MODE. MODE can be :ASK,
2602 :ERROR, :LOAD-OR-NIL, or :LOAD. :ASK is the default.
2603 This allows OPERATE-ON-SYSTEM to work on non-loaded as well as
2604 loaded system definitions. DEFINITION-PNAME is the pathname for
2605 the system definition, if provided."
2606 (ecase mode
2607 (:ask
2608 (or (get-system system-name)
2609 (when (y-or-n-p-wait
2610 #\y 20
2611 "System ~A not loaded. Shall I try loading it? "
2612 system-name)
2613 (find-system system-name :load definition-pname))))
2614 (:error
2615 (or (get-system system-name)
2616 (error 'missing-system :name system-name)))
2617 (:load-or-nil
2618 (let ((system (get-system system-name)))
2619 (or (unless *reload-systems-from-disk* system)
2620 ;; If SYSTEM-NAME is a symbol, it will lowercase the
2621 ;; symbol's string.
2622 ;; If SYSTEM-NAME is a string, it doesn't change the case of the
2623 ;; string. So if case matters in the filename, use strings, not
2624 ;; symbols, wherever the system is named.
2625 (when (foreign-system-p system)
2626 (warn "Foreing system ~S cannot be reloaded by MK:DEFSYSTEM." system)
2627 (return-from find-system nil))
2628 (let ((path (compute-system-path system-name definition-pname)))
2629 (when (and path
2630 (or (null system)
2631 (null (component-load-time path))
2632 (< (component-load-time path)
2633 (file-write-date path))))
2634 (tell-user-generic
2635 (format nil "Loading system ~A from file ~A"
2636 system-name
2637 path))
2638 (load path)
2639 (setf system (get-system system-name))
2640 (when system
2641 (setf (component-load-time path)
2642 (file-write-date path))))
2643 system)
2644 system)))
2645 (:load
2646 (or (unless *reload-systems-from-disk* (get-system system-name))
2647 (when (foreign-system-p (get-system system-name))
2648 (warn "Foreign system ~S cannot be reloaded by MK:DEFSYSTEM." system-name)
2649 (return-from find-system nil))
2650 (or (find-system system-name :load-or-nil definition-pname)
2651 (error "Can't find system named ~s." system-name))))))
2654 (defun print-component (component stream depth)
2655 (declare (ignore depth))
2656 (format stream "#<~:@(~A~): ~A>"
2657 (component-type component)
2658 (component-name component)))
2661 (defun describe-system (name &optional (stream *standard-output*))
2662 "Prints a description of the system to the stream. If NAME is the
2663 name of a system, gets it and prints a description of the system.
2664 If NAME is a component, prints a description of the component."
2665 (let ((system (if (typep name 'component) name (find-system name :load))))
2666 (format stream "~&~A ~A: ~
2667 ~@[~& Host: ~A~]~
2668 ~@[~& Device: ~A~]~
2669 ~@[~& Package: ~A~]~
2670 ~& Source: ~@[~A~] ~@[~A~] ~@[~A~]~
2671 ~& Binary: ~@[~A~] ~@[~A~] ~@[~A~]~
2672 ~@[~& Depends On: ~A ~]~& Components:~{~15T~A~&~}"
2673 (component-type system)
2674 (component-name system)
2675 (component-host system)
2676 (component-device system)
2677 (component-package system)
2678 (component-root-dir system :source)
2679 (component-pathname system :source)
2680 (component-extension system :source)
2681 (component-root-dir system :binary)
2682 (component-pathname system :binary)
2683 (component-extension system :binary)
2684 (component-depends-on system)
2685 (component-components system))
2686 #||(when recursive
2687 (dolist (component (component-components system))
2688 (describe-system component stream recursive)))||#
2689 system))
2691 (defun canonicalize-component-name (component)
2692 ;; Within the component, the name is a string.
2693 (if (typep (component-name component) 'string)
2694 ;; Unnecessary to change it, so just return it, same case
2695 (component-name component)
2696 ;; Otherwise, make it a downcase string -- important since file
2697 ;; names are often constructed from component names, and unix
2698 ;; prefers lowercase as a default.
2699 (setf (component-name component)
2700 (string-downcase (string (component-name component))))))
2702 (defun component-pathname (component type)
2703 (when component
2704 (ecase type
2705 (:source (component-source-pathname component))
2706 (:binary (component-binary-pathname component))
2707 (:error (component-error-pathname component)))))
2708 (defun component-error-pathname (component)
2709 (let ((binary (component-pathname component :binary)))
2710 (new-file-type binary *compile-error-file-type*)))
2711 (defsetf component-pathname (component type) (value)
2712 `(when ,component
2713 (ecase ,type
2714 (:source (setf (component-source-pathname ,component) ,value))
2715 (:binary (setf (component-binary-pathname ,component) ,value)))))
2717 (defun component-root-dir (component type)
2718 (when component
2719 (ecase type
2720 (:source (component-source-root-dir component))
2721 ((:binary :error) (component-binary-root-dir component))
2723 (defsetf component-root-dir (component type) (value)
2724 `(when ,component
2725 (ecase ,type
2726 (:source (setf (component-source-root-dir ,component) ,value))
2727 (:binary (setf (component-binary-root-dir ,component) ,value)))))
2729 (defvar *source-pathnames-table* (make-hash-table :test #'equal)
2730 "Table which maps from components to full source pathnames.")
2731 (defvar *binary-pathnames-table* (make-hash-table :test #'equal)
2732 "Table which maps from cosmponents to full binary pathnames.")
2733 (defparameter *reset-full-pathname-table* t
2734 "If T, clears the full-pathname tables before each call to
2735 OPERATE-ON-SYSTEM. Setting this to NIL may yield faster performance
2736 after multiple calls to LOAD-SYSTEM and COMPILE-SYSTEM, but could
2737 result in changes to system and language definitions to not take
2738 effect, and so should be used with caution.")
2739 (defun clear-full-pathname-tables ()
2740 (clrhash *source-pathnames-table*)
2741 (clrhash *binary-pathnames-table*))
2743 (defun component-full-pathname (component type &optional (version *version*))
2744 (when component
2745 (case type
2746 (:source
2747 (let ((old (gethash component *source-pathnames-table*)))
2748 (or old
2749 (let ((new (component-full-pathname-i component type version)))
2750 (setf (gethash component *source-pathnames-table*) new)
2751 new))))
2752 (:binary
2753 (let ((old (gethash component *binary-pathnames-table*)))
2754 (or old
2755 (let ((new (component-full-pathname-i component type version)))
2756 (setf (gethash component *binary-pathnames-table*) new)
2757 new))))
2758 (otherwise
2759 (component-full-pathname-i component type version)))))
2761 (defun component-full-pathname-i (component type
2762 &optional (version *version*)
2763 &aux version-dir version-replace)
2764 ;; If the pathname-type is :binary and the root pathname is null,
2765 ;; distribute the binaries among the sources (= use :source pathname).
2766 ;; This assumes that the component's :source pathname has been set
2767 ;; before the :binary one.
2768 (if version
2769 (multiple-value-setq (version-dir version-replace)
2770 (translate-version version))
2771 (setq version-dir *version-dir* version-replace *version-replace*))
2772 ;; (format *trace-output* "~&>>>> VERSION COMPUTED ~S ~S~%" version-dir version-replace)
2773 (let ((pathname
2774 (append-directories
2775 (if version-replace
2776 version-dir
2777 (append-directories (component-root-dir component type)
2778 version-dir))
2779 (component-pathname component type))))
2781 ;; When a logical pathname is used, it must first be translated to
2782 ;; a physical pathname. This isn't strictly correct. What should happen
2783 ;; is we fill in the appropriate slots of the logical pathname, and
2784 ;; then return the logical pathname for use by compile-file & friends.
2785 ;; But calling translate-logical-pathname to return the actual pathname
2786 ;; should do for now.
2788 ;; (format t "pathname = ~A~%" pathname)
2789 ;; (format t "type = ~S~%" (component-extension component type))
2791 ;; 20000303 Marco Antoniotti
2792 ;; Changed the following according to suggestion by Ray Toy. I
2793 ;; just collapsed the tests for "logical-pathname-ness" into a
2794 ;; single test (heavy, but probably very portable) and added the
2795 ;; :name argument to the MAKE-PATHNAME in the MERGE-PATHNAMES
2796 ;; beacuse of possible null names (e.g. :defsystem components)
2797 ;; causing problems with the subsequenct call to NAMESTRING.
2798 ;; (format *trace-output* "~&>>>> PATHNAME is ~S~%" pathname)
2799 (cond #-scl
2800 ((pathname-logical-p pathname) ; See definition of test above.
2801 (setf pathname
2802 (merge-pathnames pathname
2803 (make-pathname
2804 :name (component-name component)
2805 :type (component-extension component
2806 type))))
2807 ;;(format t "new path = ~A~%" pathname)
2808 (namestring (translate-logical-pathname pathname)))
2809 #-scl
2811 (namestring
2812 (make-pathname :host (when (component-host component)
2813 ;; MCL2.0b1 and ACLPC cause an error on
2814 ;; (pathname-host nil)
2815 #+sbcl
2816 (component-host component)
2817 #+openmcl
2818 (component-host (if (eq component :unspecific) "" component))
2819 #-(or :sbcl :openmcl)
2820 (pathname-host (component-host component)))
2821 :directory (pathname-directory pathname)
2822 ;; Use :directory instead of :defaults
2823 :name (pathname-name pathname)
2824 :type (component-extension component type)
2825 :device
2826 #+sbcl
2827 :unspecific
2828 #-(or :sbcl)
2829 (let ((dev (component-device component)))
2830 (if dev
2831 (pathname-device dev
2832 #+scl :case #+scl :common
2834 (pathname-device pathname
2835 #+scl :case #+scl :common
2837 ;; :version :newest
2839 #+scl
2841 (make-pathname
2842 :name (component-name component)
2843 :type (component-extension component type)
2844 :defaults pathname
2845 :case :uri)))))
2847 ;;; What about CMU17 :device :unspecific in the above?
2849 #-lispworks
2850 (defun translate-version (version)
2851 ;; Value returns the version directory and whether it replaces
2852 ;; the entire root (t) or is a subdirectory.
2853 ;; Version may be nil to signify no subdirectory,
2854 ;; a symbol, such as alpha, beta, omega, :alpha, mark, which
2855 ;; specifies a subdirectory of the root, or
2856 ;; a string, which replaces the root.
2857 (cond ((null version)
2858 (values "" nil))
2859 ((symbolp version)
2860 (values (let ((sversion (string version)))
2861 (if (find-if #'lower-case-p sversion)
2862 sversion
2863 (string-downcase sversion)))
2864 nil))
2865 ((stringp version)
2866 (values version t))
2867 (t (error "~&; Illegal version ~S" version))))
2870 ;;; Looks like LW has a bug in MERGE-PATHNAMES.
2872 ;;; (merge-pathnames "" "LP:foo;bar;") ==> "LP:"
2874 ;;; Which is incorrect.
2875 ;;; The change here ensures that the result of TRANSLATE-VERSION is
2876 ;;; appropriate.
2878 #+lispworks
2879 (defun translate-version (version)
2880 ;; Value returns the version directory and whether it replaces
2881 ;; the entire root (t) or is a subdirectory.
2882 ;; Version may be nil to signify no subdirectory,
2883 ;; a symbol, such as alpha, beta, omega, :alpha, mark, which
2884 ;; specifies a subdirectory of the root, or
2885 ;; a string, which replaces the root.
2886 (cond ((null version)
2887 (values (pathname "") nil))
2888 ((symbolp version)
2889 (values (let ((sversion (string version)))
2890 (if (find-if #'lower-case-p sversion)
2891 (pathname sversion)
2892 (pathname (string-downcase sversion))))
2893 nil))
2894 ((stringp version)
2895 (values (pathname version) t))
2896 (t (error "~&; Illegal version ~S" version))))
2901 (defun component-extension (component type &key local)
2902 (ecase type
2903 (:source (or (component-source-extension component)
2904 (unless local
2905 (default-source-extension component)) ; system default
2906 ;; (and (component-language component))
2908 (:binary (or (component-binary-extension component)
2909 (unless local
2910 (default-binary-extension component)) ; system default
2911 ;; (and (component-language component))
2913 (:error *compile-error-file-type*)))
2916 (defsetf component-extension (component type) (value)
2917 `(ecase ,type
2918 (:source (setf (component-source-extension ,component) ,value))
2919 (:binary (setf (component-binary-extension ,component) ,value))
2920 (:error (setf *compile-error-file-type* ,value))))
2922 ;;; ********************************
2923 ;;; System Definition **************
2924 ;;; ********************************
2925 (defun create-component (type name definition-body &optional parent (indent 0))
2926 (let ((component (apply #'make-component
2927 :type type
2928 :name name
2929 :indent indent
2930 definition-body)))
2931 ;; Set up :load-only attribute
2932 (unless (find :load-only definition-body)
2933 ;; If the :load-only attribute wasn't specified,
2934 ;; inherit it from the parent. If no parent, default it to nil.
2935 (setf (component-load-only component)
2936 (when parent
2937 (component-load-only parent))))
2938 ;; Set up :compile-only attribute
2939 (unless (find :compile-only definition-body)
2940 ;; If the :compile-only attribute wasn't specified,
2941 ;; inherit it from the parent. If no parent, default it to nil.
2942 (setf (component-compile-only component)
2943 (when parent
2944 (component-compile-only parent))))
2946 ;; Set up :compiler-options attribute
2947 (unless (find :compiler-options definition-body)
2948 ;; If the :compiler-option attribute wasn't specified,
2949 ;; inherit it from the parent. If no parent, default it to NIL.
2950 (setf (component-compiler-options component)
2951 (when parent
2952 (component-compiler-options parent))))
2954 #|| ISI Extension ||#
2955 ;; Set up :load-always attribute
2956 (unless (find :load-always definition-body)
2957 ;; If the :load-always attribute wasn't specified,
2958 ;; inherit it from the parent. If no parent, default it to nil.
2959 (setf (component-load-always component)
2960 (when parent
2961 (component-load-always parent))))
2963 ;; Initializations/after makes
2964 (canonicalize-component-name component)
2966 ;; Inherit package from parent if not specified.
2967 (setf (component-package component)
2968 (or (component-package component)
2969 (when parent (component-package parent))))
2971 ;; Type specific setup:
2972 (when (or (eq type :defsystem) (eq type :system) (eq type :subsystem))
2973 (setf (get-system name) component)
2974 #|(unless (component-language component)
2975 (setf (component-language component) :lisp))|#)
2977 ;; Set up the component's pathname
2978 (create-component-pathnames component parent)
2980 ;; If there are any components of the component, expand them too.
2981 (expand-component-components component (+ indent 2))
2983 ;; Make depends-on refer to structs instead of names.
2984 (link-component-depends-on (component-components component))
2986 ;; Design Decision: Topologically sort the dependency graph at
2987 ;; time of definition instead of at time of use. Probably saves a
2988 ;; little bit of time for the user.
2990 ;; Topological Sort the components at this level.
2991 (setf (component-components component)
2992 (topological-sort (component-components component)))
2994 ;; Return the component.
2995 component))
2998 ;;; defsystem --
2999 ;;; The main macro.
3001 ;;; 2002-11-22 Marco Antoniotti
3002 ;;; Added code to achieve a first cut "pathname less" operation,
3003 ;;; following the ideas in ASDF. If the DEFSYSTEM form is loaded from
3004 ;;; a file, then the location of the file (intended as a directory) is
3005 ;;; computed from *LOAD-PATHNAME* and stored as the :SOURCE-PATHNAME
3006 ;;; of the system.
3008 (defmacro defsystem (name &rest definition-body)
3009 (unless (find :source-pathname definition-body)
3010 (setf definition-body
3011 (list* :source-pathname
3012 '(when #-gcl *load-pathname* #+gcl si::*load-pathname*
3013 (make-pathname :name nil
3014 :type nil
3015 :defaults #-gcl *load-pathname*
3016 #+gcl si::*load-pathname*))
3017 definition-body)))
3018 `(create-component :defsystem ',name ',definition-body nil 0))
3020 (defun create-component-pathnames (component parent)
3021 ;; Set up language-specific defaults
3023 (setf (component-language component)
3024 (or (component-language component) ; for local defaulting
3025 (when parent ; parent's default
3026 (component-language parent))))
3028 (setf (component-compiler component)
3029 (or (component-compiler component) ; for local defaulting
3030 (when parent ; parent's default
3031 (component-compiler parent))))
3032 (setf (component-loader component)
3033 (or (component-loader component) ; for local defaulting
3034 (when parent ; parent's default
3035 (component-loader parent))))
3037 ;; Evaluate the root dir arg
3038 (setf (component-root-dir component :source)
3039 (eval (component-root-dir component :source)))
3040 (setf (component-root-dir component :binary)
3041 (eval (component-root-dir component :binary)))
3043 ;; Evaluate the pathname arg
3044 (setf (component-pathname component :source)
3045 (eval (component-pathname component :source)))
3046 (setf (component-pathname component :binary)
3047 (eval (component-pathname component :binary)))
3049 ;; Pass along the host and devices
3050 (setf (component-host component)
3051 (or (component-host component)
3052 (when parent (component-host parent))
3053 (pathname-host *default-pathname-defaults*)))
3054 (setf (component-device component)
3055 (or (component-device component)
3056 (when parent (component-device parent))))
3058 ;; Set up extension defaults
3059 (setf (component-extension component :source)
3060 (or (component-extension component :source
3061 :local #| (component-language component) |#
3063 ) ; local default
3064 (when (component-language component)
3065 (default-source-extension component))
3066 (when parent ; parent's default
3067 (component-extension parent :source))))
3068 (setf (component-extension component :binary)
3069 (or (component-extension component :binary
3070 :local #| (component-language component) |#
3072 ) ; local default
3073 (when (component-language component)
3074 (default-binary-extension component))
3075 (when parent ; parent's default
3076 (component-extension parent :binary))))
3078 ;; Set up pathname defaults -- expand with parent
3079 ;; We must set up the source pathname before the binary pathname
3080 ;; to allow distribution of binaries among the sources to work.
3081 (generate-component-pathname component parent :source)
3082 (generate-component-pathname component parent :binary))
3085 ;; maybe file's inheriting of pathnames should be moved elsewhere?
3086 (defun generate-component-pathname (component parent pathname-type)
3087 ;; Pieces together a pathname for the component based on its component-type.
3088 ;; Assumes source defined first.
3089 ;; Null binary pathnames inherit from source instead of the component's
3090 ;; name. This allows binaries to be distributed among the source if
3091 ;; binary pathnames are not specified. Or if the root directory is
3092 ;; specified for binaries, but no module directories, it inherits
3093 ;; parallel directory structure.
3094 (case (component-type component)
3095 ((:defsystem :system) ; Absolute Pathname
3096 ;; Set the root-dir to be the absolute pathname
3097 (setf (component-root-dir component pathname-type)
3098 (or (component-pathname component pathname-type)
3099 (when (eq pathname-type :binary)
3100 ;; When the binary root is nil, use source.
3101 (component-root-dir component :source))) )
3102 ;; Set the relative pathname to be nil
3103 (setf (component-pathname component pathname-type)
3104 nil));; should this be "" instead?
3105 ;; If the name of the component-pathname is nil, it
3106 ;; defaults to the name of the component. Use "" to
3107 ;; avoid this defaulting.
3108 (:private-file ; Absolute Pathname
3109 ;; Root-dir is the directory part of the pathname
3110 (setf (component-root-dir component pathname-type)
3112 #+ignore(or (when (component-pathname component pathname-type)
3113 (pathname-directory
3114 (component-pathname component pathname-type)))
3115 (when (eq pathname-type :binary)
3116 ;; When the binary root is nil, use source.
3117 (component-root-dir component :source)))
3119 ;; If *SOURCE-PATHNAME-DEFAULT* or *BINARY-PATHNAME-DEFAULT* is "",
3120 ;; then COMPONENT-SOURCE-PATHNAME or COMPONENT-BINARY-PATHNAME could
3121 ;; wind up being "", which is wrong for :file components. So replace
3122 ;; them with NIL.
3123 (when (null-string (component-pathname component pathname-type))
3124 (setf (component-pathname component pathname-type) nil))
3125 ;; The relative pathname is the name part
3126 (setf (component-pathname component pathname-type)
3127 (or (when (and (eq pathname-type :binary)
3128 (null (component-pathname component :binary)))
3129 ;; When the binary-pathname is nil use source.
3130 (component-pathname component :source))
3131 (or (when (component-pathname component pathname-type)
3132 ; (pathname-name )
3133 (component-pathname component pathname-type))
3134 (component-name component)))))
3135 ((:module :subsystem) ; Pathname relative to parent.
3136 ;; Inherit root-dir from parent
3137 (setf (component-root-dir component pathname-type)
3138 (component-root-dir parent pathname-type))
3139 ;; Tack the relative-dir onto the pathname
3140 (setf (component-pathname component pathname-type)
3141 (or (when (and (eq pathname-type :binary)
3142 (null (component-pathname component :binary)))
3143 ;; When the binary-pathname is nil use source.
3144 (component-pathname component :source))
3145 (append-directories
3146 (component-pathname parent pathname-type)
3147 (or (component-pathname component pathname-type)
3148 (component-name component))))))
3149 (:file ; Pathname relative to parent.
3150 ;; Inherit root-dir from parent
3151 (setf (component-root-dir component pathname-type)
3152 (component-root-dir parent pathname-type))
3153 ;; If *SOURCE-PATHNAME-DEFAULT* or *BINARY-PATHNAME-DEFAULT* is "",
3154 ;; then COMPONENT-SOURCE-PATHNAME or COMPONENT-BINARY-PATHNAME could
3155 ;; wind up being "", which is wrong for :file components. So replace
3156 ;; them with NIL.
3157 (when (null-string (component-pathname component pathname-type))
3158 (setf (component-pathname component pathname-type) nil))
3159 ;; Tack the relative-dir onto the pathname
3160 (setf (component-pathname component pathname-type)
3161 (or (append-directories
3162 (component-pathname parent pathname-type)
3163 (or (component-pathname component pathname-type)
3164 (component-name component)
3165 (when (eq pathname-type :binary)
3166 ;; When the binary-pathname is nil use source.
3167 (component-pathname component :source)))))))
3170 #|| ;; old version
3171 (defun expand-component-components (component &optional (indent 0))
3172 (let ((definitions (component-components component)))
3173 (setf (component-components component)
3174 (remove-if #'null
3175 (mapcar #'(lambda (definition)
3176 (expand-component-definition definition
3177 component
3178 indent))
3179 definitions)))))
3181 ;; new version
3182 (defun expand-component-components (component &optional (indent 0))
3183 (let ((definitions (component-components component)))
3184 (if (eq (car definitions) :serial)
3185 (setf (component-components component)
3186 (expand-serial-component-chain (cdr definitions)
3187 component indent))
3188 (setf (component-components component)
3189 (expand-component-definitions definitions component indent)))))
3191 (defun expand-component-definitions (definitions parent &optional (indent 0))
3192 (let ((components nil))
3193 (dolist (definition definitions)
3194 (let ((new (expand-component-definition definition parent indent)))
3195 (when new (push new components))))
3196 (nreverse components)))
3198 (defun expand-serial-component-chain (definitions parent &optional (indent 0))
3199 (let ((previous nil)
3200 (components nil))
3201 (dolist (definition definitions)
3202 (let ((new (expand-component-definition definition parent indent)))
3203 (when new
3204 ;; Make this component depend on the previous one. Since
3205 ;; we don't know the form of the definition, we have to
3206 ;; expand it first.
3207 (when previous (pushnew previous (component-depends-on new)))
3208 ;; The dependencies will be linked later, so we use the name
3209 ;; instead of the actual component.
3210 (setq previous (component-name new))
3211 ;; Save the new component.
3212 (push new components))))
3213 ;; Return the list of expanded components, in appropriate order.
3214 (nreverse components)))
3217 (defparameter *enable-straz-absolute-string-hack* nil
3218 "Special hack requested by Steve Strassman, where the shorthand
3219 that specifies a list of components as a list of strings also
3220 recognizes absolute pathnames and treats them as files of type
3221 :private-file instead of type :file. Defaults to NIL, because I
3222 haven't tested this.")
3223 (defun absolute-file-namestring-p (string)
3224 ;; If a FILE namestring starts with a slash, or is a logical pathname
3225 ;; as implied by the existence of a colon in the filename, assume it
3226 ;; represents an absolute pathname.
3227 (or (find #\: string :test #'char=)
3228 (and (not (null-string string))
3229 (char= (char string 0) #\/))))
3231 (defun expand-component-definition (definition parent &optional (indent 0))
3232 ;; Should do some checking for malformed definitions here.
3233 (cond ((null definition) nil)
3234 ((stringp definition)
3235 ;; Strings are assumed to be of type :file
3236 (if (and *enable-straz-absolute-string-hack*
3237 (absolute-file-namestring-p definition))
3238 ;; Special hack for Straz
3239 (create-component :private-file definition nil parent indent)
3240 ;; Normal behavior
3241 (create-component :file definition nil parent indent)))
3242 ((and (listp definition)
3243 (not (member (car definition)
3244 '(:defsystem :system :subsystem
3245 :module :file :private-file))))
3246 ;; Lists whose first element is not a component type
3247 ;; are assumed to be of type :file
3248 (create-component :file
3249 (car definition)
3250 (cdr definition)
3251 parent
3252 indent))
3253 ((listp definition)
3254 ;; Otherwise, it is (we hope) a normal form definition
3255 (create-component (car definition) ; type
3256 (cadr definition) ; name
3257 (cddr definition) ; definition body
3258 parent ; parent
3259 indent) ; indent
3262 (defun link-component-depends-on (components)
3263 (dolist (component components)
3264 (unless (and *system-dependencies-delayed*
3265 (eq (component-type component) :defsystem))
3266 (setf (component-depends-on component)
3267 (mapcar #'(lambda (dependency)
3268 (let ((parent (find (string dependency) components
3269 :key #'component-name
3270 :test #'string-equal)))
3271 (cond (parent parent)
3272 ;; make it more intelligent about the following
3273 (t (warn "Dependency ~S of component ~S not found."
3274 dependency component)))))
3276 (component-depends-on component))))))
3278 ;;; ********************************
3279 ;;; Topological Sort the Graph *****
3280 ;;; ********************************
3282 ;;; New version of topological sort suggested by rs2. Even though
3283 ;;; this version avoids the call to sort, in practice it isn't faster. It
3284 ;;; does, however, eliminate the need to have a TIME slot in the
3285 ;;; topological-sort-node defstruct.
3286 (defun topological-sort (list &aux (sorted-list nil))
3287 (labels ((dfs-visit (znode)
3288 (setf (topsort-color znode) :gray)
3289 (unless (and *system-dependencies-delayed*
3290 (eq (component-type znode) :system))
3291 (dolist (child (component-depends-on znode))
3292 (cond ((eq (topsort-color child) :white)
3293 (dfs-visit child))
3294 ((eq (topsort-color child) :gray)
3295 (format t "~&Detected cycle containing ~A" child)))))
3296 (setf (topsort-color znode) :black)
3297 (push znode sorted-list)))
3298 (dolist (znode list)
3299 (setf (topsort-color znode) :white))
3300 (dolist (znode list)
3301 (when (eq (topsort-color znode) :white)
3302 (dfs-visit znode)))
3303 (nreverse sorted-list)))
3306 ;;; Older version of topological sort.
3307 (defun topological-sort (list &aux (time 0))
3308 ;; The algorithm works by calling depth-first-search to compute the
3309 ;; blackening times for each vertex, and then sorts the vertices into
3310 ;; reverse order by blackening time.
3311 (labels ((dfs-visit (node)
3312 (setf (topsort-color node) 'gray)
3313 (unless (and *system-dependencies-delayed*
3314 (eq (component-type node) :defsystem))
3315 (dolist (child (component-depends-on node))
3316 (cond ((eq (topsort-color child) 'white)
3317 (dfs-visit child))
3318 ((eq (topsort-color child) 'gray)
3319 (format t "~&Detected cycle containing ~A" child)))))
3320 (setf (topsort-color node) 'black)
3321 (setf (topsort-time node) time)
3322 (incf time)))
3323 (dolist (node list)
3324 (setf (topsort-color node) 'white))
3325 (dolist (node list)
3326 (when (eq (topsort-color node) 'white)
3327 (dfs-visit node)))
3328 (sort list #'< :key #'topsort-time)))
3331 ;;; ********************************
3332 ;;; Output to User *****************
3333 ;;; ********************************
3334 ;;; All output to the user is via the tell-user functions.
3336 (defun split-string (string &key (item #\space) (test #'char=))
3337 ;; Splits the string into substrings at spaces.
3338 (let ((len (length string))
3339 (index 0) result)
3340 (dotimes (i len
3341 (progn (unless (= index len)
3342 (push (subseq string index) result))
3343 (reverse result)))
3344 (when (funcall test (char string i) item)
3345 (unless (= index i);; two spaces in a row
3346 (push (subseq string index i) result))
3347 (setf index (1+ i))))))
3349 ;; probably should remove the ",1" entirely. But AKCL 1.243 dies on it
3350 ;; because of an AKCL bug.
3351 ;; KGK suggests using an 8 instead, but 1 does nicely.
3352 (defun prompt-string (component)
3353 (format nil "; ~:[~;TEST:~]~V,1@T "
3354 *oos-test*
3355 (component-indent component)))
3358 (defun format-justified-string (prompt contents)
3359 (format t (concatenate 'string
3360 "~%"
3361 prompt
3362 "-~{~<~%" prompt " ~1,80:; ~A~>~^~}")
3363 (split-string contents))
3364 (finish-output *standard-output*))
3367 (defun format-justified-string (prompt contents &optional (width 80)
3368 (stream *standard-output*))
3369 (let ((prompt-length (+ 2 (length prompt))))
3370 (cond ((< (+ prompt-length (length contents)) width)
3371 (format stream "~%~A- ~A" prompt contents))
3373 (format stream "~%~A-" prompt)
3374 (do* ((cursor prompt-length)
3375 (contents (split-string contents) (cdr contents))
3376 (content (car contents) (car contents))
3377 (content-length (1+ (length content)) (1+ (length content))))
3378 ((null contents))
3379 (cond ((< (+ cursor content-length) width)
3380 (incf cursor content-length)
3381 (format stream " ~A" content))
3383 (setf cursor (+ prompt-length content-length))
3384 (format stream "~%~A ~A" prompt content)))))))
3385 (finish-output stream))
3387 (defun tell-user (what component &optional type no-dots force)
3388 (when (or *oos-verbose* force)
3389 (format-justified-string (prompt-string component)
3390 (format nil "~A ~(~A~) ~@[\"~A\"~] ~:[~;...~]"
3391 ;; To have better messages, wrap the following around the
3392 ;; case statement:
3393 ;;(if (find (component-type component)
3394 ;; '(:defsystem :system :subsystem :module))
3395 ;; "Checking"
3396 ;; (case ...))
3397 ;; This gets around the problem of DEFSYSTEM reporting
3398 ;; that it's loading a module, when it eventually never
3399 ;; loads any of the files of the module.
3400 (case what
3401 ((compile :compile)
3402 (if (component-load-only component)
3403 ;; If it is :load-only t, we're loading.
3404 "Loading"
3405 ;; Otherwise we're compiling.
3406 "Compiling"))
3407 ((load :load) "Loading")
3408 (otherwise what))
3409 (component-type component)
3410 (or (when type
3411 (component-full-pathname component type))
3412 (component-name component))
3413 (and *tell-user-when-done*
3414 (not no-dots))))))
3416 (defun tell-user-done (component &optional force no-dots)
3417 ;; test is no longer really used, but we're leaving it in.
3418 (when (and *tell-user-when-done*
3419 (or *oos-verbose* force))
3420 (format t "~&~A~:[~;...~] Done."
3421 (prompt-string component) (not no-dots))
3422 (finish-output *standard-output*)))
3424 (defmacro with-tell-user ((what component &optional type no-dots force) &body body)
3425 `(progn
3426 (tell-user ,what ,component ,type ,no-dots ,force)
3427 ,@body
3428 (tell-user-done ,component ,force ,no-dots)))
3430 (defun tell-user-no-files (component &optional force)
3431 (when (or *oos-verbose* force)
3432 (format-justified-string (prompt-string component)
3433 (format nil "Source file ~A ~
3434 ~:[and binary file ~A ~;~]not found, not loading."
3435 (component-full-pathname component :source)
3436 (or *load-source-if-no-binary* *load-source-instead-of-binary*)
3437 (component-full-pathname component :binary)))))
3439 (defun tell-user-require-system (name parent)
3440 (when *oos-verbose*
3441 (format t "~&; ~:[~;TEST:~] - System ~A requires ~S"
3442 *oos-test* (component-name parent) name)
3443 (finish-output *standard-output*)))
3445 (defun tell-user-generic (string)
3446 (when *oos-verbose*
3447 (format t "~&; ~:[~;TEST:~] - ~A"
3448 *oos-test* string)
3449 (finish-output *standard-output*)))
3451 ;;; ********************************
3452 ;;; Y-OR-N-P-WAIT ******************
3453 ;;; ********************************
3454 ;;; Y-OR-N-P-WAIT is like Y-OR-N-P, but will timeout after a specified
3455 ;;; number of seconds. I should really replace this with a call to
3456 ;;; the Y-OR-N-P-WAIT defined in the query.cl package and include that
3457 ;;; instead.
3459 (defparameter *use-timeouts* t
3460 "If T, timeouts in Y-OR-N-P-WAIT are enabled. Otherwise it behaves
3461 like Y-OR-N-P. This is provided for users whose lisps don't handle
3462 read-char-no-hang properly.")
3464 (defparameter *clear-input-before-query* t
3465 "If T, y-or-n-p-wait will clear the input before printing the prompt
3466 and asking the user for input.")
3468 ;;; The higher *sleep-amount* is, the less consing, but the lower the
3469 ;;; responsiveness.
3470 (defparameter *sleep-amount* #-CMU 0.1 #+CMU 1.0
3471 "Amount of time to sleep between checking query-io. In multiprocessing
3472 Lisps, this allows other processes to continue while we busy-wait. If
3473 0, skips call to SLEEP.")
3475 (defun internal-real-time-in-seconds ()
3476 (get-universal-time))
3478 (defun read-char-wait (&optional (timeout 20) input-stream
3479 (eof-error-p t) eof-value
3480 &aux peek)
3481 (do ((start (internal-real-time-in-seconds)))
3482 ((or (setq peek (listen input-stream))
3483 (< (+ start timeout) (internal-real-time-in-seconds)))
3484 (when peek
3485 ;; was read-char-no-hang
3486 (read-char input-stream eof-error-p eof-value)))
3487 (unless (zerop *sleep-amount*)
3488 (sleep *sleep-amount*))))
3490 ;;; Lots of lisps, especially those that run on top of UNIX, do not get
3491 ;;; their input one character at a time, but a whole line at a time because
3492 ;;; of the buffering done by the UNIX system. This causes y-or-n-p-wait
3493 ;;; to not always work as expected.
3495 ;;; I wish lisp did all its own buffering (turning off UNIX input line
3496 ;;; buffering by putting the UNIX into CBREAK mode). Of course, this means
3497 ;;; that we lose input editing, but why can't the lisp implement this?
3499 (defun y-or-n-p-wait (&optional (default #\y) (timeout 20)
3500 format-string &rest args)
3501 "Y-OR-N-P-WAIT prints the message, if any, and reads characters from
3502 *QUERY-IO* until the user enters y, Y or space as an affirmative, or either
3503 n or N as a negative answer, or the timeout occurs. It asks again if
3504 you enter any other characters."
3505 (when *clear-input-before-query* (clear-input *query-io*))
3506 (when format-string
3507 (fresh-line *query-io*)
3508 (apply #'format *query-io* format-string args)
3509 ;; FINISH-OUTPUT needed for CMU and other places which don't handle
3510 ;; output streams nicely. This prevents it from continuing and
3511 ;; reading the query until the prompt has been printed.
3512 (finish-output *query-io*))
3513 (loop
3514 (let* ((read-char (if *use-timeouts*
3515 (read-char-wait timeout *query-io* nil nil)
3516 (read-char *query-io*)))
3517 (char (or read-char default)))
3518 ;; We need to ignore #\newline because otherwise the bugs in
3519 ;; clear-input will cause y-or-n-p-wait to print the "Type ..."
3520 ;; message every time... *sigh*
3521 ;; Anyway, we might want to use this to ignore whitespace once
3522 ;; clear-input is fixed.
3523 (unless (find char '(#\tab #\newline #\return))
3524 (when (null read-char)
3525 (format *query-io* "~@[~A~]" default)
3526 (finish-output *query-io*))
3527 (cond ((null char) (return t))
3528 ((find char '(#\y #\Y #\space) :test #'char=) (return t))
3529 ((find char '(#\n #\N) :test #'char=) (return nil))
3531 (when *clear-input-before-query* (clear-input *query-io*))
3532 (format *query-io* "~&Type \"y\" for yes or \"n\" for no. ")
3533 (when format-string
3534 (fresh-line *query-io*)
3535 (apply #'format *query-io* format-string args))
3536 (finish-output *query-io*)))))))
3539 (y-or-n-p-wait #\y 20 "What? ")
3540 (progn (format t "~&hi") (finish-output)
3541 (y-or-n-p-wait #\y 10 "1? ")
3542 (y-or-n-p-wait #\n 10 "2? "))
3544 ;;; ********************************
3545 ;;; Operate on System **************
3546 ;;; ********************************
3547 ;;; Operate-on-system
3548 ;;; Operation is :compile, 'compile, :load or 'load
3549 ;;; Force is :all or :new-source or :new-source-and-dependents or a list of
3550 ;;; specific modules.
3551 ;;; :all (or T) forces a recompilation of every file in the system
3552 ;;; :new-source-and-dependents compiles only those files whose
3553 ;;; sources have changed or who depend on recompiled files.
3554 ;;; :new-source compiles only those files whose sources have changed
3555 ;;; A list of modules means that only those modules and their
3556 ;;; dependents are recompiled.
3557 ;;; Test is T to print out what it would do without actually doing it.
3558 ;;; Note: it automatically sets verbose to T if test is T.
3559 ;;; Verbose is T to print out what it is doing (compiling, loading of
3560 ;;; modules and files) as it does it.
3561 ;;; Dribble should be the pathname of the dribble file if you want to
3562 ;;; dribble the compilation.
3563 ;;; Load-source-instead-of-binary is T to load .lisp instead of binary files.
3564 ;;; Version may be nil to signify no subdirectory,
3565 ;;; a symbol, such as alpha, beta, omega, :alpha, mark, which
3566 ;;; specifies a subdirectory of the root, or
3567 ;;; a string, which replaces the root.
3569 (defun operate-on-system (name operation
3570 &key
3571 force
3572 (version *version*)
3573 (test *oos-test*) (verbose *oos-verbose*)
3574 (load-source-instead-of-binary
3575 *load-source-instead-of-binary*)
3576 (load-source-if-no-binary
3577 *load-source-if-no-binary*)
3578 (bother-user-if-no-binary
3579 *bother-user-if-no-binary*)
3580 (compile-during-load *compile-during-load*)
3581 dribble
3582 (minimal-load *minimal-load*)
3583 (override-compilation-unit t)
3585 (declare #-(or :cltl2 :ansi-cl) (ignore override-compilation-unit))
3586 (unwind-protect
3587 ;; Protect the undribble.
3588 (#+(and (or :cltl2 :ansi-cl) (not :gcl)) with-compilation-unit
3589 #+(and (or :cltl2 :ansi-cl) (not :gcl)) (:override override-compilation-unit)
3590 #-(and (or :cltl2 :ansi-cl) (not :gcl)) progn
3591 (when *reset-full-pathname-table* (clear-full-pathname-tables))
3592 (when dribble (dribble dribble))
3593 (when test (setq verbose t))
3594 (when (null force) ; defaults
3595 (case operation
3596 ((load :load) (setq force :all))
3597 ((compile :compile) (setq force :new-source-and-dependents))
3598 (t (setq force :all))))
3599 ;; Some CL implementations have a variable called *compile-verbose*
3600 ;; or *compile-file-verbose*.
3601 (multiple-value-bind (*version-dir* *version-replace*)
3602 (translate-version version)
3603 ;; CL implementations may uniformly default this to nil
3604 (let (
3605 #-(or MCL CMU CLISP ECL :sbcl lispworks scl)
3606 (*compile-file-verbose* t) ; nil
3607 #+common-lisp-controller
3608 (*compile-print* nil)
3609 #+(and common-lisp-controller cmu)
3610 (ext:*compile-progress* nil)
3611 #+(and common-lisp-controller cmu)
3612 (ext:*require-verbose* nil)
3613 #+(and common-lisp-controller cmu)
3614 (ext:*gc-verbose* nil)
3616 (*version* version)
3617 (*oos-verbose* verbose)
3618 (*oos-test* test)
3619 (*load-source-if-no-binary* load-source-if-no-binary)
3620 (*compile-during-load* compile-during-load)
3621 (*bother-user-if-no-binary* bother-user-if-no-binary)
3622 (*load-source-instead-of-binary* load-source-instead-of-binary)
3623 (*minimal-load* minimal-load)
3624 (system (if (and (component-p name)
3625 (member (component-type name)
3626 '(:system :defsystem :subsystem)))
3627 name
3628 (find-system name :load))))
3629 #-(or CMU CLISP :sbcl :lispworks :cormanlisp scl)
3630 (declare (special *compile-verbose* #-MCL *compile-file-verbose*)
3631 #-openmcl (ignore *compile-verbose*
3632 #-MCL *compile-file-verbose*)
3633 #-openmcl (optimize (inhibit-warnings 3)))
3634 (unless (component-operation operation)
3635 (error "Operation ~A undefined." operation))
3636 (operate-on-component system operation force))))
3637 (when dribble (dribble))))
3640 (defun compile-system (name &key force
3641 (version *version*)
3642 (test *oos-test*) (verbose *oos-verbose*)
3643 (load-source-instead-of-binary
3644 *load-source-instead-of-binary*)
3645 (load-source-if-no-binary
3646 *load-source-if-no-binary*)
3647 (bother-user-if-no-binary
3648 *bother-user-if-no-binary*)
3649 (compile-during-load *compile-during-load*)
3650 dribble
3651 (minimal-load *minimal-load*))
3652 ;; For users who are confused by OOS.
3653 (operate-on-system
3654 name :compile
3655 :force force
3656 :version version
3657 :test test
3658 :verbose verbose
3659 :load-source-instead-of-binary load-source-instead-of-binary
3660 :load-source-if-no-binary load-source-if-no-binary
3661 :bother-user-if-no-binary bother-user-if-no-binary
3662 :compile-during-load compile-during-load
3663 :dribble dribble
3664 :minimal-load minimal-load))
3666 (defun load-system (name &key force
3667 (version *version*)
3668 (test *oos-test*) (verbose *oos-verbose*)
3669 (load-source-instead-of-binary
3670 *load-source-instead-of-binary*)
3671 (load-source-if-no-binary *load-source-if-no-binary*)
3672 (bother-user-if-no-binary *bother-user-if-no-binary*)
3673 (compile-during-load *compile-during-load*)
3674 dribble
3675 (minimal-load *minimal-load*))
3676 ;; For users who are confused by OOS.
3677 (operate-on-system
3678 name :load
3679 :force force
3680 :version version
3681 :test test
3682 :verbose verbose
3683 :load-source-instead-of-binary load-source-instead-of-binary
3684 :load-source-if-no-binary load-source-if-no-binary
3685 :bother-user-if-no-binary bother-user-if-no-binary
3686 :compile-during-load compile-during-load
3687 :dribble dribble
3688 :minimal-load minimal-load))
3690 (defun clean-system (name &key (force :all)
3691 (version *version*)
3692 (test *oos-test*) (verbose *oos-verbose*)
3693 dribble)
3694 "Deletes all the binaries in the system."
3695 ;; For users who are confused by OOS.
3696 (operate-on-system
3697 name :delete-binaries
3698 :force force
3699 :version version
3700 :test test
3701 :verbose verbose
3702 :dribble dribble))
3704 (defun edit-system
3705 (name &key force
3706 (version *version*)
3707 (test *oos-test*)
3708 (verbose *oos-verbose*)
3709 dribble)
3711 (operate-on-system
3712 name :edit
3713 :force force
3714 :version version
3715 :test test
3716 :verbose verbose
3717 :dribble dribble))
3719 (defun hardcopy-system
3720 (name &key force
3721 (version *version*)
3722 (test *oos-test*)
3723 (verbose *oos-verbose*)
3724 dribble)
3726 (operate-on-system
3727 name :hardcopy
3728 :force force
3729 :version version
3730 :test test
3731 :verbose verbose
3732 :dribble dribble))
3735 ;;; ensure-external-system-def-loaded component --
3736 ;;; Let's treat definition clauses of the form
3738 ;;; (:system "name")
3739 ;;; i.e.
3741 ;;; (:system "name" :components nil)
3743 ;;; in a special way.
3744 ;;; When encountered, MK:DEFSYSTEM tries to FIND-SYSTEM
3745 ;;; the system named "name" (by forcing a reload from disk).
3746 ;;; This may be more "natural".
3748 (defun ensure-external-system-def-loaded (component)
3749 (assert (member (component-type component)
3750 '(:subsystem :system)))
3751 (when (null (component-components component))
3752 (let ((cname (component-name component)))
3753 ;; First we ensure that we reload the system definition.
3754 (undefsystem cname)
3755 (let* ((*reload-systems-from-disk* t)
3756 (system-component
3757 (find-system (component-name component)
3758 :load
3760 ;; Let's not supply the def-pname
3761 ;; yet.
3762 #+not-yet
3763 (merge-pathname
3764 (make-pathname :name cname
3765 :type "system"
3766 :directory ())
3767 (component-full-pathname component
3768 :source))
3773 ;; Now we have a problem.
3774 ;; We have just ensured that a system definition is
3775 ;; loaded, however, the COMPONENT at hand is different
3776 ;; from SYSTEM-COMPONENT.
3777 ;; To fix this problem we just use the following
3778 ;; kludge. This should prevent re-entering in this
3779 ;; code branch, while actually preparing the COMPONENT
3780 ;; for operation.
3781 (setf (component-components component)
3782 (list system-component))
3783 ))))
3786 (defun operate-on-component (component operation force &aux changed)
3787 ;; Returns T if something changed and had to be compiled.
3788 (let ((type (component-type component))
3789 (old-package (package-name *package*)))
3791 (unwind-protect
3792 ;; Protect old-package.
3793 (progn
3794 ;; Use the correct package.
3795 (when (component-package component)
3796 (tell-user-generic (format nil "Using package ~A"
3797 (component-package component)))
3798 (unless *oos-test*
3799 (unless (find-package (component-package component))
3800 ;; If the package name is the same as the name of the system,
3801 ;; and the package is not defined, this would lead to an
3802 ;; infinite loop, so bomb out with an error.
3803 (when (string-equal (string (component-package component))
3804 (component-name component))
3805 (format t "~%Component ~A not loaded:~%"
3806 (component-name component))
3807 (error " Package ~A is not defined"
3808 (component-package component)))
3809 ;; If package not found, try using REQUIRE to load it.
3810 (new-require (component-package component)))
3811 ;; This was USE-PACKAGE, but should be IN-PACKAGE.
3812 ;; Actually, CLtL2 lisps define in-package as a macro,
3813 ;; so we'll set the package manually.
3814 ;; (in-package (component-package component))
3815 (let ((package (find-package (component-package component))))
3816 (when package
3817 (setf *package* package)))))
3819 ;; Marco Antoniotti 20040609
3820 ;; New feature. Try to FIND-SYSTEM :system components if
3821 ;; they have no local :components definition.
3822 ;; OPERATE-ON-SYSTEM-DEPENDENCIES should still work as
3823 ;; advertised, given the small change made there.
3825 (when (or (eq type :system) (eq type :subsystem))
3826 (ensure-external-system-def-loaded component))
3828 (when (or (eq type :defsystem) (eq type :system))
3829 (operate-on-system-dependencies component operation force))
3831 ;; Do any compiler proclamations
3832 (when (component-proclamations component)
3833 (tell-user-generic (format nil "Doing proclamations for ~A"
3834 (component-name component)))
3835 (or *oos-test*
3836 (proclaim (component-proclamations component))))
3838 ;; Do any initial actions
3839 (when (component-initially-do component)
3840 (tell-user-generic (format nil "Doing initializations for ~A"
3841 (component-name component)))
3842 (or *oos-test*
3843 (eval (component-initially-do component))))
3845 ;; If operation is :compile and load-only is T, this would change
3846 ;; the operation to load. Only, this would mean that a module would
3847 ;; be considered to have changed if it was :load-only and had to be
3848 ;; loaded, and then dependents would be recompiled -- this doesn't
3849 ;; seem right. So instead, we propagate the :load-only attribute
3850 ;; to the components, and modify compile-file-operation so that
3851 ;; it won't compile the files (and modify tell-user to say "Loading"
3852 ;; instead of "Compiling" for load-only modules).
3854 (when (and (find operation '(:compile compile))
3855 (component-load-only component))
3856 (setf operation :load))
3859 ;; Do operation and set changed flag if necessary.
3860 (setq changed
3861 (case type
3862 ((:file :private-file)
3863 (funcall (component-operation operation) component force))
3864 ((:module :system :subsystem :defsystem)
3865 (operate-on-components component operation force changed))))
3867 ;; Do any final actions
3868 (when (component-finally-do component)
3869 (tell-user-generic (format nil "Doing finalizations for ~A"
3870 (component-name component)))
3871 (or *oos-test*
3872 (eval (component-finally-do component))))
3874 ;; add the banner if needed
3875 #+(or cmu scl)
3876 (when (component-banner component)
3877 (unless (stringp (component-banner component))
3878 (error "The banner should be a string, it is: ~S"
3879 (component-banner component)))
3880 (setf (getf ext:*herald-items*
3881 (intern (string-upcase (component-name component))
3882 (find-package :keyword)))
3883 (list
3884 (component-banner component)))))
3886 ;; Reset the package. (Cleanup form of unwind-protect.)
3887 ;;(in-package old-package)
3888 (setf *package* (find-package old-package)))
3890 ;; Provide the loaded system
3891 (when (or (eq type :defsystem) (eq type :system) (eq type :subsystem))
3892 (tell-user-generic (format nil "Providing system ~A~%"
3893 (component-name component)))
3894 (or *oos-test*
3895 (provide (canonicalize-system-name (component-name component))))))
3897 ;; Return non-NIL if something changed in this component and hence had
3898 ;; to be recompiled. This is only used as a boolean.
3899 changed)
3901 (defvar *force* nil)
3902 (defvar *providing-blocks-load-propagation* t
3903 "If T, if a system dependency exists on *modules*, it is not loaded.")
3905 (defun operate-on-system-dependencies (component operation &optional force)
3906 (when *system-dependencies-delayed*
3907 (let ((*force* force))
3908 (dolist (system (component-depends-on component))
3909 ;; For each system that this system depends on, if it is a
3910 ;; defined system (either via defsystem or component type :system),
3911 ;; and propagation is turned on, propagates the operation to the
3912 ;; subsystem. Otherwise runs require (my version) on that system
3913 ;; to load it (needed since we may be depending on a lisp
3914 ;; dependent package).
3915 ;; Explores the system tree in a DFS manner.
3917 ;; Do not try to do anything with non system components.
3918 (cond ((and *operations-propagate-to-subsystems*
3919 (not (listp system))
3920 (or (stringp system) (symbolp system))
3921 ;; The subsystem is a defined system.
3922 (find-system system :load-or-nil))
3923 ;; Call OOS on it. Since *system-dependencies-delayed* is
3924 ;; T, the :depends-on slot is filled with the names of
3925 ;; systems, not defstructs.
3926 ;; Aside from system, operation, force, for everything else
3927 ;; we rely on the globals.
3928 (unless (and *providing-blocks-load-propagation*
3929 ;; If *providing-blocks-load-propagation* is T,
3930 ;; the system dependency must not exist in the
3931 ;; *modules* for it to be loaded. Note that
3932 ;; the dependencies are implicitly systems.
3933 (find operation '(load :load))
3934 ;; (or (eq force :all) (eq force t))
3935 (find (canonicalize-system-name system)
3936 *modules* :test #'string-equal))
3938 (operate-on-system system operation :force force)))
3940 ((listp system)
3941 ;; If the SYSTEM is a list then its contents are as follows.
3943 ;; (<name> <definition-pathname> <action> &optional <version>)
3946 (destructuring-bind (system-name definition-pathname action
3947 &optional version)
3948 system
3949 (tell-user-require-system
3950 (if (and (null system-name)
3951 (null definition-pathname))
3952 action
3953 system)
3954 component)
3955 (or *oos-test* (new-require system-name
3957 (eval definition-pathname)
3958 action
3959 (or version *version*)))))
3960 ((and (component-p system)
3961 (not (member (component-type system)
3962 '(:defsystem :subsystem :system))))
3963 ;; Do nothing for non system components.
3966 (tell-user-require-system system component)
3967 (or *oos-test* (new-require system))))
3968 ))))
3970 ;;; Modules can depend only on siblings. If a module should depend
3971 ;;; on an uncle, then the parent module should depend on that uncle
3972 ;;; instead. Likewise a module should depend on a sibling, not a niece
3973 ;;; or nephew. Modules also cannot depend on cousins. Modules cannot
3974 ;;; depend on parents, since that is circular.
3976 (defun module-depends-on-changed (module changed)
3977 (dolist (dependent (component-depends-on module))
3978 (when (member dependent changed)
3979 (return t))))
3981 (defun operate-on-components (component operation force changed)
3982 (with-tell-user (operation component)
3983 (if (component-components component)
3984 (dolist (module (component-components component))
3985 (when (operate-on-component module operation
3986 (cond ((and (module-depends-on-changed module changed)
3987 #||(some #'(lambda (dependent)
3988 (member dependent changed))
3989 (component-depends-on module))||#
3990 (or (non-empty-listp force)
3991 (eq force :new-source-and-dependents)))
3992 ;; The component depends on a changed file
3993 ;; and force agrees.
3994 (if (eq force :new-source-and-dependents)
3995 :new-source-all
3996 :all))
3997 ((and (non-empty-listp force)
3998 (member (component-name module) force
3999 :test #'string-equal :key #'string))
4000 ;; Force is a list of modules
4001 ;; and the component is one of them.
4002 :all)
4003 (t force)))
4004 (push module changed)))
4005 (case operation
4006 ((compile :compile)
4007 (eval (component-compile-form component)))
4008 ((load :load)
4009 (eval (component-load-form component))))))
4010 ;; This is only used as a boolean.
4011 changed)
4013 ;;; ********************************
4014 ;;; New Require ********************
4015 ;;; ********************************
4017 ;;; This needs cleaning. Obviously the code is a left over from the
4018 ;;; time people did not know how to use packages in a proper way or
4019 ;;; CLs were shaky in their implementation.
4021 ;;; First of all we need this. (Commented out for the time being)
4022 ;;; (shadow '(cl:require))
4025 (defvar *old-require* nil)
4027 ;;; All calls to require in this file have been replaced with calls
4028 ;;; to new-require to avoid compiler warnings and make this less of
4029 ;;; a tangled mess.
4031 (defun new-require (module-name
4032 &optional
4033 pathname
4034 definition-pname
4035 default-action
4036 (version *version*))
4037 ;; If the pathname is present, this behaves like the old require.
4038 (unless (and module-name
4039 (find (string module-name)
4040 *modules* :test #'string=))
4041 (handler-case
4042 (cond (pathname
4043 (funcall *old-require* module-name pathname))
4044 ;; If the system is defined, load it.
4045 ((find-system module-name :load-or-nil definition-pname)
4046 (operate-on-system
4047 module-name :load
4048 :force *force*
4049 :version version
4050 :test *oos-test*
4051 :verbose *oos-verbose*
4052 :load-source-if-no-binary *load-source-if-no-binary*
4053 :bother-user-if-no-binary *bother-user-if-no-binary*
4054 :compile-during-load *compile-during-load*
4055 :load-source-instead-of-binary *load-source-instead-of-binary*
4056 :minimal-load *minimal-load*))
4057 ;; If there's a default action, do it. This could be a progn which
4058 ;; loads a file that does everything.
4059 ((and default-action
4060 (eval default-action)))
4061 ;; If no system definition file, try regular require.
4062 ;; had last arg PATHNAME, but this wasn't really necessary.
4063 ((funcall *old-require* module-name))
4064 ;; If no default action, print a warning or error message.
4067 (format t "~&Warning: System ~A doesn't seem to be defined..."
4068 module-name)
4070 (error 'missing-system :name module-name)))
4071 (missing-module (mmc) (signal mmc)) ; Resignal.
4072 (error (e)
4073 (declare (ignore e))
4074 ;; Signal a (maybe wrong) MISSING-SYSTEM.
4075 (error 'missing-system :name module-name)))
4079 ;;; Note that in some lisps, when the compiler sees a REQUIRE form at
4080 ;;; top level it immediately executes it. This is as if an
4081 ;;; (eval-when (compile load eval) ...) were wrapped around the REQUIRE
4082 ;;; form. I don't see any easy way to do this without making REQUIRE
4083 ;;; a macro.
4085 ;;; For example, in VAXLisp, if a (require 'streams) form is at the top of
4086 ;;; a file in the system, compiling the system doesn't wind up loading the
4087 ;;; streams module. If the (require 'streams) form is included within an
4088 ;;; (eval-when (compile load eval) ...) then everything is OK.
4090 ;;; So perhaps we should replace the redefinition of lisp:require
4091 ;;; with the following macro definition:
4093 (unless *old-require*
4094 (setf *old-require*
4095 (symbol-function #-(or :lispworks
4096 :sbcl
4097 (and :excl :allegro-v4.0)) 'lisp:require
4098 #+:sbcl 'cl:require
4099 #+:lispworks 'system:::require
4100 #+(and :excl :allegro-v4.0) 'cltl1:require))
4102 (let (#+:CCL (ccl:*warn-if-redefine-kernel* nil))
4103 ;; Note that lots of lisps barf if we redefine a function from
4104 ;; the LISP package. So what we do is define a macro with an
4105 ;; unused name, and use (setf macro-function) to redefine
4106 ;; lisp:require without compiler warnings. If the lisp doesn't
4107 ;; do the right thing, try just replacing require-as-macro
4108 ;; with lisp:require.
4109 (defmacro require-as-macro (module-name
4110 &optional pathname definition-pname
4111 default-action (version '*version*))
4112 `(eval-when (compile load eval)
4113 (new-require ,module-name ,pathname ,definition-pname
4114 ,default-action ,version)))
4115 (setf (macro-function #-(and :excl :sbcl :allegro-v4.0) 'lisp:require
4116 #+:sbcl 'cl:require
4117 #+(and :excl :allegro-v4.0) 'cltl1:require)
4118 (macro-function 'require-as-macro))))
4120 ;;; This will almost certainly fix the problem, but will cause problems
4121 ;;; if anybody does a funcall on #'require.
4123 ;;; Redefine old require to call the new require.
4124 (eval-when #-(or :lucid) (:load-toplevel :execute)
4125 #+(or :lucid) (load eval)
4126 (unless *old-require*
4127 (setf *old-require*
4128 (symbol-function
4129 #-(or (and :excl :allegro-v4.0) :ecl :mcl :sbcl :scl :lispworks :abcl :openmcl) 'lisp:require
4130 #+(and :excl :allegro-v4.0) 'cltl1:require
4131 #+(or :ecl :sbcl :scl) 'cl:require
4132 #+(or :lispworks3.1 :abcl) 'common-lisp::require
4133 #+(and :lispworks (not :lispworks3.1)) 'system::require
4134 #+:openmcl 'cl:require
4135 #+(and :mcl (not :openmcl)) 'ccl:require
4138 (unless *dont-redefine-require*
4139 (let (#+(or :mcl (and :CCL (not :lispworks)))
4140 (ccl:*warn-if-redefine-kernel* nil))
4141 #-(or :ecl (and allegro-version>= (version>= 4 1)) :lispworks)
4142 (setf (symbol-function
4143 #-(or (and :excl :allegro-v4.0) :mcl :sbcl :scl :lispworks :abcl :openmcl) 'lisp:require
4144 #+(and :excl :allegro-v4.0) 'cltl1:require
4145 #+(or :lispworks3.1 :abcl) 'common-lisp::require
4146 #+(or :sbcl :scl) 'cl:require
4147 #+(and :lispworks (not :lispworks3.1)) 'system::require
4148 #+:openmcl 'cl:require
4149 #+(and :mcl (not :openmcl)) 'ccl:require
4151 (symbol-function 'new-require))
4152 #+:ecl
4153 (progn
4154 (ext:package-lock "CL" nil)
4155 (setf (symbol-function 'lisp:require)
4156 (symbol-function 'new-require))
4157 (ext:package-lock "CL" t))
4158 #+:lispworks
4159 (let ((warn-packs system::*packages-for-warn-on-redefinition*))
4160 (declare (special system::*packages-for-warn-on-redefinition*))
4161 (setq system::*packages-for-warn-on-redefinition* nil)
4162 (setf (symbol-function
4163 #+:lispworks3.1 'common-lisp::require
4164 #-:lispworks3.1 'system::require
4166 (symbol-function 'new-require))
4167 (setq system::*packages-for-warn-on-redefinition* warn-packs))
4168 #+(and allegro-version>= (version>= 4 1))
4169 (excl:without-package-locks
4170 (setf (symbol-function 'lisp:require)
4171 (symbol-function 'new-require))))))
4175 ;;; Well, let's add some more REQUIRE hacking; specifically for SBCL,
4176 ;;; and, eventually, for CMUCL.
4178 #+sbcl
4179 (eval-when (:compile-toplevel :load-toplevel :execute)
4181 (defun sbcl-mk-defsystem-module-provider (name)
4182 ;; Let's hope things go smoothly.
4183 (let ((module-name (string-downcase (string name))))
4184 (when (mk:find-system module-name :load-or-nil)
4185 (mk:load-system module-name
4186 :compile-during-load t
4187 :verbose nil))))
4189 (pushnew 'sbcl-mk-defsystem-module-provider sb-ext:*module-provider-functions*)
4192 #+#.(cl:if (cl:and (cl:find-package :ext) (cl:find-symbol "*MODULE-PROVIDER-FUNCTIONS*" :ext)) '(and) '(or))
4193 (progn
4194 (defun cmucl-mk-defsystem-module-provider (name)
4195 (let ((module-name (string-downcase (string name))))
4196 (when (mk:find-system module-name :load-or-nil)
4197 (mk:load-system module-name
4198 :compile-during-load t
4199 :verbose nil))))
4201 (pushnew 'cmucl-mk-defsystem-module-provider ext:*module-provider-functions*)
4207 ;;; ********************************
4208 ;;; Language-Dependent Characteristics
4209 ;;; ********************************
4210 ;;; This section is used for defining language-specific behavior of
4211 ;;; defsystem. If the user changes a language definition, it should
4212 ;;; take effect immediately -- they shouldn't have to reload the
4213 ;;; system definition file for the changes to take effect.
4215 (defvar *language-table* (make-hash-table :test #'equal)
4216 "Hash table that maps from languages to language structures.")
4217 (defun find-language (name)
4218 (gethash name *language-table*))
4220 (defstruct (language (:print-function print-language))
4221 name ; The name of the language (a keyword)
4222 compiler ; The function used to compile files in the language
4223 loader ; The function used to load files in the language
4224 source-extension ; Filename extensions for source files
4225 binary-extension ; Filename extensions for binary files
4228 (defun print-language (language stream depth)
4229 (declare (ignore depth))
4230 (format stream "#<~:@(~A~): ~A ~A>"
4231 (language-name language)
4232 (language-source-extension language)
4233 (language-binary-extension language)))
4235 (defun compile-function (component)
4236 (or (component-compiler component)
4237 (let ((language (find-language (or (component-language component)
4238 :lisp))))
4239 (when language (language-compiler language)))
4240 #'compile-file))
4242 (defun load-function (component)
4243 (or (component-loader component)
4244 (let ((language (find-language (or (component-language component)
4245 :lisp))))
4246 (when language (language-loader language)))
4247 #'load))
4249 (defun default-source-extension (component)
4250 (let ((language (find-language (or (component-language component)
4251 :lisp))))
4252 (or (when language (language-source-extension language))
4253 (car *filename-extensions*))))
4255 (defun default-binary-extension (component)
4256 (let ((language (find-language (or (component-language component)
4257 :lisp))))
4258 (or (when language (language-binary-extension language))
4259 (cdr *filename-extensions*))))
4261 (defmacro define-language (name &key compiler loader
4262 source-extension binary-extension)
4263 (let ((language (gensym (symbol-name '#:language))))
4264 `(let ((,language (make-language :name ,name
4265 :compiler ,compiler
4266 :loader ,loader
4267 :source-extension ,source-extension
4268 :binary-extension ,binary-extension)))
4269 (setf (gethash ,name *language-table*) ,language)
4270 ,name)))
4273 ;;; Test System for verifying multi-language capabilities.
4274 (defsystem foo
4275 :language :lisp
4276 :components ((:module c :language :c :components ("foo" "bar"))
4277 (:module lisp :components ("baz" "barf"))))
4281 ;;; *** Lisp Language Definition
4282 (define-language :lisp
4283 :compiler #'compile-file
4284 :loader #'load
4285 :source-extension (car *filename-extensions*)
4286 :binary-extension (cdr *filename-extensions*))
4288 ;;; *** PseudoScheme Language Definition
4289 (defun scheme-compile-file (filename &rest args)
4290 (let ((scheme-package (find-package '#:scheme)))
4291 (apply (symbol-function (find-symbol (symbol-name 'compile-file)
4292 scheme-package))
4293 filename
4294 (funcall (symbol-function
4295 (find-symbol (symbol-name '#:interaction-environment)
4296 scheme-package)))
4297 args)))
4299 (define-language :scheme
4300 :compiler #'scheme-compile-file
4301 :loader #'load
4302 :source-extension "scm"
4303 :binary-extension "bin")
4305 ;;; *** C Language Definition
4307 ;;; This is very basic. Somebody else who needs it can add in support
4308 ;;; for header files, libraries, different C compilers, etc. For example,
4309 ;;; we might add a COMPILER-OPTIONS slot to the component defstruct.
4311 (defparameter *c-compiler* "gcc")
4312 #-(or symbolics (and :lispworks :harlequin-pc-lisp ))
4314 (defun run-unix-program (program arguments)
4315 ;; arguments should be a list of strings, where each element is a
4316 ;; command-line option to send to the program.
4317 #+:lucid (run-program program :arguments arguments)
4318 #+:allegro (excl:run-shell-command
4319 (format nil "~A~@[ ~{~A~^ ~}~]"
4320 program arguments))
4321 #+(or :kcl :ecl) (system (format nil "~A~@[ ~{~A~^ ~}~]" program arguments))
4322 #+(or :cmu :scl) (extensions:run-program program arguments)
4323 #+:openmcl (ccl:run-program program arguments)
4324 #+:sbcl (sb-ext:run-program program arguments)
4325 #+:lispworks (foreign:call-system-showing-output
4326 (format nil "~A~@[ ~{~A~^ ~}~]" program arguments))
4327 #+clisp (#+lisp=cl ext:run-program #-lisp=cl lisp:run-program
4328 program :arguments arguments)
4331 #+(or symbolics (and :lispworks :harlequin-pc-lisp))
4332 (defun run-unix-program (program arguments)
4333 (declare (ignore program arguments))
4334 (error "MK::RUN-UNIX-PROGRAM: this does not seem to be a UN*X system.")
4338 (defun c-compile-file (filename &rest args &key output-file error-file)
4339 ;; gcc -c foo.c -o foo.o
4340 (declare (ignore args))
4341 (run-unix-program *c-compiler*
4342 (format nil "-c ~A~@[ -o ~A~]"
4343 filename
4344 output-file)))
4348 (defun c-compile-file (filename &rest args &key output-file error-file)
4349 ;; gcc -c foo.c -o foo.o
4350 (declare (ignore args error-file))
4351 (run-unix-program *c-compiler*
4352 `("-c" ,filename ,@(if output-file `("-o" ,output-file)))))
4356 ;;; The following code was inserted to improve C compiler support (at
4357 ;;; least under Linux/GCC).
4358 ;;; Thanks to Espen S Johnsen.
4360 ;;; 20001118 Marco Antoniotti.
4362 (defun default-output-pathname (path1 path2 type)
4363 (if (eq path1 t)
4364 (translate-logical-pathname
4365 (merge-pathnames (make-pathname :type type) (pathname path2)))
4366 (translate-logical-pathname (pathname path1))))
4369 (defun run-compiler (program
4370 arguments
4371 output-file
4372 error-file
4373 error-output
4374 verbose)
4375 #-(or cmu scl) (declare (ignore error-file error-output))
4377 (flet ((make-useable-stream (&rest streams)
4378 (apply #'make-broadcast-stream (delete nil streams)))
4380 (let (#+(or cmu scl) (error-file error-file)
4381 #+(or cmu scl) (error-file-stream nil)
4382 (verbose-stream nil)
4383 (old-timestamp (file-write-date output-file))
4384 (fatal-error nil)
4385 (output-file-written nil)
4387 (unwind-protect
4388 (progn
4389 #+(or cmu scl)
4390 (setf error-file
4391 (when error-file
4392 (default-output-pathname error-file
4393 output-file
4394 *compile-error-file-type*))
4396 error-file-stream
4397 (and error-file
4398 (open error-file
4399 :direction :output
4400 :if-exists :supersede)))
4402 (setf verbose-stream
4403 (make-useable-stream
4404 #+(or cmu scl) error-file-stream
4405 (and verbose *trace-output*)))
4407 (format verbose-stream "Running ~A~@[ ~{~A~^ ~}~]~%"
4408 program
4409 arguments)
4411 (setf fatal-error
4412 #-(or cmu scl)
4413 (and (run-unix-program program arguments) nil) ; Incomplete.
4414 #+(or cmu scl)
4415 (let* ((error-output
4416 (make-useable-stream error-file-stream
4417 (if (eq error-output t)
4418 *error-output*
4419 error-output)))
4420 (process
4421 (ext:run-program program arguments
4422 :error error-output)))
4423 (not (zerop (ext:process-exit-code process)))))
4425 (setf output-file-written
4426 (and (probe-file output-file)
4427 (not (eql old-timestamp
4428 (file-write-date output-file)))))
4431 (when output-file-written
4432 (format verbose-stream "~A written~%" output-file))
4433 (format verbose-stream "Running of ~A finished~%"
4434 program)
4435 (values (and output-file-written output-file)
4436 fatal-error
4437 fatal-error))
4439 #+(or cmu scl)
4440 (when error-file
4441 (close error-file-stream)
4442 (unless (or fatal-error (not output-file-written))
4443 (delete-file error-file)))
4445 (values (and output-file-written output-file)
4446 fatal-error
4447 fatal-error)))))
4450 ;;; C Language definitions.
4452 (defun c-compile-file (filename &rest args
4453 &key
4454 (output-file t)
4455 (error-file t)
4456 (error-output t)
4457 (verbose *compile-verbose*)
4458 debug
4459 link
4460 optimize
4461 cflags
4462 definitions
4463 include-paths
4464 library-paths
4465 libraries
4466 (error t))
4467 (declare (ignore args))
4469 (flet ((map-options (flag options &optional (func #'identity))
4470 (mapcar #'(lambda (option)
4471 (format nil "~A~A" flag (funcall func option)))
4472 options))
4474 (let* ((output-file (default-output-pathname output-file filename "o"))
4475 (arguments
4476 `(,@(when (not link) '("-c"))
4477 ,@(when debug '("-g"))
4478 ,@(when optimize (list (format nil "-O~D" optimize)))
4479 ,@cflags
4480 ,@(map-options
4481 "-D" definitions
4482 #'(lambda (definition)
4483 (if (atom definition)
4484 definition
4485 (apply #'format nil "~A=~A" definition))))
4486 ,@(map-options "-I" include-paths #'truename)
4487 ,(namestring (truename filename))
4488 "-o"
4489 ,(namestring (translate-logical-pathname output-file))
4490 ,@(map-options "-L" library-paths #'truename)
4491 ,@(map-options "-l" libraries))))
4493 (multiple-value-bind (output-file warnings fatal-errors)
4494 (run-compiler *c-compiler*
4495 arguments
4496 output-file
4497 error-file
4498 error-output
4499 verbose)
4500 (if (and error (or (not output-file) fatal-errors))
4501 (error "Compilation failed")
4502 (values output-file warnings fatal-errors))))))
4505 (define-language :c
4506 :compiler #'c-compile-file
4507 :loader #+:lucid #'load-foreign-files
4508 #+:allegro #'load
4509 #+(or :cmu :scl) #'alien:load-foreign
4510 #+:sbcl #'sb-alien:load-foreign
4511 #+(and :lispworks :unix (not :linux) (not :macosx)) #'link-load:read-foreign-modules
4512 #+(and :lispworks :unix (or :linux :macosx)) #'fli:register-module
4513 #+(and :lispworks :win32) #'fli:register-module
4514 #+(or :ecl :gcl :kcl) #'load ; should be enough.
4515 #-(or :lucid
4516 :allegro
4517 :cmu
4518 :sbcl
4519 :scl
4520 :lispworks
4521 :ecl :gcl :kcl)
4522 (lambda (&rest args)
4523 (declare (ignore args))
4524 (cerror "Continue returning NIL."
4525 "Loader not defined for C foreign libraries in ~A ~A."
4526 (lisp-implementation-type)
4527 (lisp-implementation-version)))
4528 :source-extension "c"
4529 :binary-extension "o")
4532 ;;; Fortran Language definitions.
4533 ;;; From Matlisp.
4535 (export '(*fortran-compiler* *fortran-options*))
4537 (defparameter *fortran-compiler* "g77")
4538 (defparameter *fortran-options* '("-O"))
4540 (defun fortran-compile-file (filename &rest args
4541 &key output-file error-file
4542 &allow-other-keys)
4543 (declare (ignore error-file args))
4544 (let ((arg-list
4545 (append *fortran-options*
4546 `("-c" ,filename ,@(if output-file `("-o" ,output-file))))))
4547 (run-unix-program *fortran-compiler* arg-list)))
4550 (mk:define-language :fortran
4551 :compiler #'fortran-compile-file
4552 :loader #'identity
4553 :source-extension "f"
4554 :binary-extension "o")
4557 ;;; AR support.
4558 ;; How to create a library (archive) of object files
4560 (export '(*ar-program* build-lib))
4562 (defparameter *ar-program* "ar")
4564 (defun build-lib (libname directory)
4565 (let ((args (list "rv" (truename libname))))
4566 (format t ";;; Building archive ~A~%" libname)
4567 (run-unix-program *ar-program*
4568 (append args
4569 (mapcar #'truename (directory directory))))))
4572 ;;; ********************************
4573 ;;; Component Operations ***********
4574 ;;; ********************************
4575 ;;; Define :compile/compile and :load/load operations
4576 (eval-when (load eval)
4577 (component-operation :compile 'compile-and-load-operation)
4578 (component-operation 'compile 'compile-and-load-operation)
4579 (component-operation :load 'load-file-operation)
4580 (component-operation 'load 'load-file-operation)
4583 (defun compile-and-load-operation (component force)
4584 ;; FORCE was CHANGED. this caused defsystem during compilation to only
4585 ;; load files that it immediately compiled.
4586 (let ((changed (compile-file-operation component force)))
4587 ;; Return T if the file had to be recompiled and reloaded.
4588 (if (and changed (component-compile-only component))
4589 ;; For files which are :compile-only T, compiling the file
4590 ;; satisfies the need to load.
4591 changed
4592 ;; If the file wasn't compiled, or :compile-only is nil,
4593 ;; check to see if it needs to be loaded.
4594 (and (load-file-operation component force) ; FORCE was CHANGED ???
4595 changed))))
4597 (defun unmunge-lucid (namestring)
4598 ;; Lucid's implementation of COMPILE-FILE is non-standard, in that
4599 ;; when the :output-file is a relative pathname, it tries to munge
4600 ;; it with the directory of the source file. For example,
4601 ;; (compile-file "src/globals.lisp" :output-file "bin/globals.sbin")
4602 ;; tries to stick the file in "./src/bin/globals.sbin" instead of
4603 ;; "./bin/globals.sbin" like any normal lisp. This hack seems to fix the
4604 ;; problem. I wouldn't have expected this problem to occur with any
4605 ;; use of defsystem, but some defsystem users are depending on
4606 ;; using relative pathnames (at least three folks reported the problem).
4607 (cond ((null-string namestring) namestring)
4608 ((char= (char namestring 0) #\/)
4609 ;; It's an absolute namestring
4610 namestring)
4612 ;; Ugly, but seems to fix the problem.
4613 (concatenate 'string "./" namestring))))
4615 ;; Define our own version of ensure-directories-exist for gcl, if gcl
4616 ;; doesn't have it. (gcl 2.6.10 has ensure-directories-exist).
4617 #+#.(cl:if (cl:and (cl:member :gcl cl:*features*) (cl:not (cl:fboundp (cl:find-symbol "ENSURE-DIRECTORIES-EXIST" "COMMON-LISP")))) '(and) '(or))
4618 (defun ensure-directories-exist (pathspec &key verbose)
4619 (declare (ignore verbose))
4620 ;; A very gross implementation of ensure-directories-exist. Just
4621 ;; call /bin/mkdir with our desired path.
4622 (let* ((dir (make-pathname :host (pathname-host pathspec)
4623 :device (pathname-device pathspec)
4624 :directory (pathname-directory pathspec)))
4625 (cmd (if (member :win32 *features*)
4626 (format nil "mkdir \"~a\""
4627 (coerce (subst #\\ #\/ (coerce (namestring dir) 'list)) 'string))
4628 (format nil "/bin/mkdir -p ~S" (namestring dir)))))
4629 (unless (directory dir)
4630 (lisp:system cmd))
4631 ;; The second return value is supposed to be T if directories were
4632 ;; created. I don't know how to tell that, so we just return T.
4633 ;; (Would NIL be better?)
4634 (values pathspec t)))
4636 (defun compile-file-operation (component force)
4637 ;; Returns T if the file had to be compiled.
4638 (let ((must-compile
4639 ;; For files which are :load-only T, loading the file
4640 ;; satisfies the demand to recompile.
4641 (and (null (component-load-only component)) ; not load-only
4642 (or (find force '(:all :new-source-all t) :test #'eq)
4643 (and (find force '(:new-source :new-source-and-dependents)
4644 :test #'eq)
4645 (needs-compilation component nil)))))
4646 (source-pname (component-full-pathname component :source)))
4648 (cond ((and must-compile (probe-file source-pname))
4649 (with-tell-user ("Compiling source" component :source)
4650 (let ((output-file
4651 #+:lucid
4652 (unmunge-lucid (component-full-pathname component
4653 :binary))
4654 #-:lucid
4655 (component-full-pathname component :binary)))
4657 ;; make certain the directory we need to write to
4658 ;; exists [pvaneynd@debian.org 20001114]
4659 ;; Added PATHNAME-HOST following suggestion by John
4660 ;; DeSoi [marcoxa@sourceforge.net 20020529]
4662 (ensure-directories-exist
4663 (make-pathname :name nil
4664 :type nil
4665 :version nil
4666 :defaults output-file))
4668 (or *oos-test*
4669 (apply (compile-function component)
4670 source-pname
4671 :output-file
4672 output-file
4673 #+(or :cmu :scl) :error-file
4674 #+(or :cmu :scl) (and *cmu-errors-to-file*
4675 (component-full-pathname component
4676 :error))
4677 #+CMU
4678 :error-output
4679 #+CMU
4680 *cmu-errors-to-terminal*
4681 (component-compiler-options component)
4682 ))))
4683 must-compile)
4684 (must-compile
4685 (tell-user "Source file not found. Not compiling"
4686 component :source :no-dots :force)
4687 nil)
4688 (t nil))))
4690 ;; see CLOCC/PORT/sys.lisp:compiled-file-p
4691 (eval-when (load eval compile)
4692 (when (find-package :port)
4693 (import (find-symbol (symbol-name '#:compiled-file-p) :port))))
4694 (unless (fboundp 'compiled-file-p)
4695 (defun compiled-file-p (file-name)
4696 "Return T if the FILE-NAME is a filename designator for a valid compiled.
4697 Signal an error when it is not a filename designator.
4698 Return NIL when the file does not exist, or is not readable,
4699 or does not contain valid compiled code."
4700 (declare (ignorable file-name))
4701 #+clisp
4702 (with-open-file (in file-name :direction :input :if-does-not-exist nil)
4703 (and in (char= #\( (peek-char nil in))
4704 (let ((form (ignore-errors (read in nil nil))))
4705 (and (consp form)
4706 (eq (car form) 'SYSTEM::VERSION)
4707 (null (nth-value 1 (ignore-errors (eval form))))))))
4708 #-clisp t))
4710 (defun needs-compilation (component force)
4711 ;; If there is no binary, or it is older than the source
4712 ;; file, then the component needs to be compiled.
4713 ;; Otherwise we only need to recompile if it depends on a file that changed.
4714 (declare (ignore force))
4715 (let ((source-pname (component-full-pathname component :source))
4716 (binary-pname (component-full-pathname component :binary)))
4717 (and
4718 ;; source must exist
4719 (probe-file source-pname)
4721 ;; We force recompilation.
4722 #|(find force '(:all :new-source-all) :test #'eq)|#
4723 ;; no binary
4724 (null (probe-file binary-pname))
4725 ;; old binary
4726 (< (file-write-date binary-pname)
4727 (file-write-date source-pname))
4728 ;; invalid binary
4729 #+clisp (not (compiled-file-p binary-pname))))))
4732 (defun needs-loading (component &optional (check-source t) (check-binary t))
4733 ;; Compares the component's load-time against the file-write-date of
4734 ;; the files on disk.
4735 (let ((load-time (component-load-time component))
4736 (source-pname (component-full-pathname component :source))
4737 (binary-pname (component-full-pathname component :binary)))
4739 #|| ISI Extension ||#
4740 (component-load-always component)
4742 ;; File never loaded.
4743 (null load-time)
4744 ;; Binary is newer.
4745 (when (and check-binary
4746 (probe-file binary-pname))
4747 (< load-time
4748 (file-write-date binary-pname)))
4749 ;; Source is newer.
4750 (when (and check-source
4751 (probe-file source-pname))
4752 (< load-time
4753 (file-write-date source-pname))))))
4755 ;;; Need to completely rework this function...
4756 (defun load-file-operation (component force)
4757 ;; Returns T if the file had to be loaded
4758 (let* ((binary-pname (component-full-pathname component :binary))
4759 (source-pname (component-full-pathname component :source))
4760 (binary-exists (probe-file binary-pname))
4761 (source-exists (probe-file source-pname))
4762 (source-needs-loading (needs-loading component t nil))
4763 (binary-needs-loading (needs-loading component nil t))
4764 ;; needs-compilation has an implicit source-exists in it.
4765 (needs-compilation (if (component-load-only component)
4766 source-needs-loading
4767 (needs-compilation component force)))
4768 (check-for-new-source
4769 ;; If force is :new-source*, we're checking for files
4770 ;; whose source is newer than the compiled versions.
4771 (find force '(:new-source :new-source-and-dependents :new-source-all)
4772 :test #'eq))
4773 (load-binary (or (find force '(:all :new-source-all t) :test #'eq)
4774 binary-needs-loading))
4775 (load-source
4776 (or *load-source-instead-of-binary*
4777 (and load-binary (component-load-only component))
4778 (and check-for-new-source needs-compilation)))
4779 (compile-and-load
4780 (and needs-compilation
4781 (or load-binary check-for-new-source)
4782 (compile-and-load-source-if-no-binary component)))
4784 ;; When we're trying to minimize the files loaded to only those
4785 ;; that need be, restrict the values of load-source and load-binary
4786 ;; so that we only load the component if the files are newer than
4787 ;; the load-time.
4788 (when (and *minimal-load*
4789 (not (find force '(:all :new-source-all)
4790 :test #'eq)))
4791 (when load-source (setf load-source source-needs-loading))
4792 (when load-binary (setf load-binary binary-needs-loading)))
4794 (when (or load-source load-binary compile-and-load)
4795 (cond (compile-and-load
4796 ;; If we're loading the binary and it is old or nonexistent,
4797 ;; and the user says yes, compile and load the source.
4798 (compile-file-operation component t)
4799 (with-tell-user ("Loading binary" component :binary)
4800 (or *oos-test*
4801 (progn
4802 (funcall (load-function component) binary-pname)
4803 (setf (component-load-time component)
4804 (file-write-date binary-pname)))))
4806 ((and source-exists
4807 (or (and load-source ; implicit needs-comp...
4808 (or *load-source-instead-of-binary*
4809 (component-load-only component)
4810 (not *compile-during-load*)))
4811 (and load-binary
4812 (not binary-exists)
4813 (load-source-if-no-binary component))))
4814 ;; Load the source if the source exists and:
4815 ;; o we're loading binary and it doesn't exist
4816 ;; o we're forcing it
4817 ;; o we're loading new source and user wasn't asked to compile
4818 (with-tell-user ("Loading source" component :source)
4819 (or *oos-test*
4820 (progn
4821 (funcall (load-function component) source-pname)
4822 (setf (component-load-time component)
4823 (file-write-date source-pname)))))
4825 ((and binary-exists load-binary)
4826 (with-tell-user ("Loading binary" component :binary)
4827 (or *oos-test*
4828 (progn
4829 (funcall (load-function component) binary-pname)
4830 (setf (component-load-time component)
4831 (file-write-date binary-pname)))))
4833 ((and (not binary-exists) (not source-exists))
4834 (tell-user-no-files component :force)
4835 (when *files-missing-is-an-error*
4836 (cerror "Continue, ignoring missing files."
4837 "~&Source file ~S ~:[and binary file ~S ~;~]do not exist."
4838 source-pname
4839 (or *load-source-if-no-binary*
4840 *load-source-instead-of-binary*)
4841 binary-pname))
4842 nil)
4844 nil)))))
4846 (eval-when (load eval)
4847 (component-operation :clean 'delete-binaries-operation)
4848 (component-operation 'clean 'delete-binaries-operation)
4849 (component-operation :delete-binaries 'delete-binaries-operation)
4850 (component-operation 'delete-binaries 'delete-binaries-operation)
4852 (defun delete-binaries-operation (component force)
4853 (when (or (eq force :all)
4854 (eq force t)
4855 (and (find force '(:new-source :new-source-and-dependents
4856 :new-source-all)
4857 :test #'eq)
4858 (needs-compilation component nil)))
4859 (let ((binary-pname (component-full-pathname component :binary)))
4860 (when (probe-file binary-pname)
4861 (with-tell-user ("Deleting binary" component :binary)
4862 (or *oos-test*
4863 (delete-file binary-pname)))))))
4866 ;; when the operation = :compile, we can assume the binary exists in test mode.
4867 ;; ((and *oos-test*
4868 ;; (eq operation :compile)
4869 ;; (probe-file (component-full-pathname component :source)))
4870 ;; (with-tell-user ("Loading binary" component :binary)))
4872 (defun binary-exists (component)
4873 (probe-file (component-full-pathname component :binary)))
4875 ;;; or old-binary
4876 (defun compile-and-load-source-if-no-binary (component)
4877 (when (not (or *load-source-instead-of-binary*
4878 (and *load-source-if-no-binary*
4879 (not (binary-exists component)))))
4880 (cond ((component-load-only component)
4882 (let ((prompt (prompt-string component)))
4883 (format t "~A- File ~A is load-only, ~
4884 ~&~A not compiling."
4885 prompt
4886 (component-full-pathname component :source)
4887 prompt))
4889 nil)
4890 ((eq *compile-during-load* :query)
4891 (let* ((prompt (prompt-string component))
4892 (compile-source
4893 (y-or-n-p-wait
4894 #\y 30
4895 "~A- Binary file ~A is old or does not exist. ~
4896 ~&~A Compile (and load) source file ~A instead? "
4897 prompt
4898 (component-full-pathname component :binary)
4899 prompt
4900 (component-full-pathname component :source))))
4901 (unless (y-or-n-p-wait
4902 #\y 30
4903 "~A- Should I bother you if this happens again? "
4904 prompt)
4905 (setq *compile-during-load*
4906 (y-or-n-p-wait
4907 #\y 30
4908 "~A- Should I compile while loading the system? "
4909 prompt))) ; was compile-source, then t
4910 compile-source))
4911 (*compile-during-load*)
4912 (t nil))))
4914 (defun load-source-if-no-binary (component)
4915 (and (not *load-source-instead-of-binary*)
4916 (or (and *load-source-if-no-binary*
4917 (not (binary-exists component)))
4918 (component-load-only component)
4919 (when *bother-user-if-no-binary*
4920 (let* ((prompt (prompt-string component))
4921 (load-source
4922 (y-or-n-p-wait #\y 30
4923 "~A- Binary file ~A does not exist. ~
4924 ~&~A Load source file ~A instead? "
4925 prompt
4926 (component-full-pathname component :binary)
4927 prompt
4928 (component-full-pathname component :source))))
4929 (setq *bother-user-if-no-binary*
4930 (y-or-n-p-wait #\n 30
4931 "~A- Should I bother you if this happens again? "
4932 prompt ))
4933 (unless *bother-user-if-no-binary*
4934 (setq *load-source-if-no-binary* load-source))
4935 load-source)))))
4937 ;;; ********************************
4938 ;;; Allegro Toplevel Commands ******
4939 ;;; ********************************
4940 ;;; Creates toplevel command aliases for Allegro CL.
4941 #+:allegro
4942 (top-level:alias ("compile-system" 8)
4943 (system &key force (minimal-load mk:*minimal-load*)
4944 test verbose version)
4945 "Compile the specified system"
4947 (mk:compile-system system :force force
4948 :minimal-load minimal-load
4949 :test test :verbose verbose
4950 :version version))
4952 #+:allegro
4953 (top-level:alias ("load-system" 5)
4954 (system &key force (minimal-load mk:*minimal-load*)
4955 (compile-during-load mk:*compile-during-load*)
4956 test verbose version)
4957 "Compile the specified system"
4959 (mk:load-system system :force force
4960 :minimal-load minimal-load
4961 :compile-during-load compile-during-load
4962 :test test :verbose verbose
4963 :version version))
4965 #+:allegro
4966 (top-level:alias ("show-system" 5) (system)
4967 "Show information about the specified system."
4969 (mk:describe-system system))
4971 #+:allegro
4972 (top-level:alias ("describe-system" 9) (system)
4973 "Show information about the specified system."
4975 (mk:describe-system system))
4977 #+:allegro
4978 (top-level:alias ("system-source-size" 9) (system)
4979 "Show size information about source files in the specified system."
4981 (mk:system-source-size system))
4983 #+:allegro
4984 (top-level:alias ("clean-system" 6)
4985 (system &key force test verbose version)
4986 "Delete binaries in the specified system."
4988 (mk:clean-system system :force force
4989 :test test :verbose verbose
4990 :version version))
4992 #+:allegro
4993 (top-level:alias ("edit-system" 7)
4994 (system &key force test verbose version)
4995 "Load system source files into Emacs."
4997 (mk:edit-system system :force force
4998 :test test :verbose verbose
4999 :version version))
5001 #+:allegro
5002 (top-level:alias ("hardcopy-system" 9)
5003 (system &key force test verbose version)
5004 "Hardcopy files in the specified system."
5006 (mk:hardcopy-system system :force force
5007 :test test :verbose verbose
5008 :version version))
5010 #+:allegro
5011 (top-level:alias ("make-system-tag-table" 13) (system)
5012 "Make an Emacs TAGS file for source files in specified system."
5014 (mk:make-system-tag-table system))
5017 ;;; ********************************
5018 ;;; Allegro Make System Fasl *******
5019 ;;; ********************************
5020 #+:excl
5021 (defun allegro-make-system-fasl (system destination
5022 &optional (include-dependents t))
5023 (excl:shell
5024 (format nil "rm -f ~A; cat~{ ~A~} > ~A"
5025 destination
5026 (if include-dependents
5027 (files-in-system-and-dependents system :all :binary)
5028 (files-in-system system :all :binary))
5029 destination)))
5031 (defun files-which-need-compilation (system)
5032 (mapcar #'(lambda (comp) (component-full-pathname comp :source))
5033 (remove nil
5034 (file-components-in-component
5035 (find-system system :load) :new-source))))
5037 (defun files-in-system-and-dependents (name &optional (force :all)
5038 (type :source) version)
5039 ;; Returns a list of the pathnames in system and dependents in load order.
5040 (let ((system (find-system name :load)))
5041 (multiple-value-bind (*version-dir* *version-replace*)
5042 (translate-version version)
5043 (let ((*version* version))
5044 (let ((result (file-pathnames-in-component system type force)))
5045 (dolist (dependent (reverse (component-depends-on system)))
5046 (setq result
5047 (append (files-in-system-and-dependents dependent
5048 force type version)
5049 result)))
5050 result)))))
5052 (defun files-in-system (name &optional (force :all) (type :source) version)
5053 ;; Returns a list of the pathnames in system in load order.
5054 (let ((system (if (and (component-p name)
5055 (member (component-type name) '(:defsystem :system :subsystem)))
5056 name
5057 (find-system name :load))))
5058 (multiple-value-bind (*version-dir* *version-replace*)
5059 (translate-version version)
5060 (let ((*version* version))
5061 (file-pathnames-in-component system type force)))))
5063 (defun file-pathnames-in-component (component type &optional (force :all))
5064 (mapcar #'(lambda (comp) (component-full-pathname comp type))
5065 (file-components-in-component component force)))
5067 (defun file-components-in-component (component &optional (force :all)
5068 &aux result changed)
5069 (case (component-type component)
5070 ((:file :private-file)
5071 (when (setq changed
5072 (or (find force '(:all t) :test #'eq)
5073 (and (not (non-empty-listp force))
5074 (needs-compilation component nil))))
5075 (setq result
5076 (list component))))
5077 ((:module :system :subsystem :defsystem)
5078 (dolist (module (component-components component))
5079 (multiple-value-bind (r c)
5080 (file-components-in-component
5081 module
5082 (cond ((and (some #'(lambda (dependent)
5083 (member dependent changed))
5084 (component-depends-on module))
5085 (or (non-empty-listp force)
5086 (eq force :new-source-and-dependents)))
5087 ;; The component depends on a changed file and force agrees.
5088 :all)
5089 ((and (non-empty-listp force)
5090 (member (component-name module) force
5091 :test #'string-equal :key #'string))
5092 ;; Force is a list of modules and the component is
5093 ;; one of them.
5094 :all)
5095 (t force)))
5096 (when c
5097 (push module changed)
5098 (setq result (append result r)))))))
5099 (values result changed))
5101 (setf (symbol-function 'oos) (symbol-function 'operate-on-system))
5103 ;;; ********************************
5104 ;;; Additional Component Operations
5105 ;;; ********************************
5107 ;;; *** Edit Operation ***
5109 ;;; Should this conditionalization be (or :mcl (and :CCL (not :lispworks)))?
5111 #+:ccl
5112 (defun edit-operation (component force)
5113 "Always returns nil, i.e. component not changed."
5114 (declare (ignore force))
5116 (let* ((full-pathname (make::component-full-pathname component :source))
5117 (already-editing\? #+:mcl (dolist (w (CCL:windows :class
5118 'fred-window))
5119 (when (equal (CCL:window-filename w)
5120 full-pathname)
5121 (return w)))
5122 #-:mcl nil))
5123 (if already-editing\?
5124 #+:mcl (CCL:window-select already-editing\?) #-:mcl nil
5125 (ed full-pathname)))
5126 nil)
5128 #+:allegro
5129 (defun edit-operation (component force)
5130 "Edit a component - always returns nil, i.e. component not changed."
5131 (declare (ignore force))
5132 (let ((full-pathname (component-full-pathname component :source)))
5133 (ed full-pathname))
5134 nil)
5136 #+(or :ccl :allegro)
5137 (make::component-operation :edit 'edit-operation)
5138 #+(or :ccl :allegro)
5139 (make::component-operation 'edit 'edit-operation)
5142 ;;; *** Hardcopy System ***
5143 (defparameter *print-command* "enscript -2Gr" ; "lpr"
5144 "Command to use for printing files on UNIX systems.")
5145 #+:allegro
5146 (defun hardcopy-operation (component force)
5147 "Hardcopy a component - always returns nil, i.e. component not changed."
5148 (declare (ignore force))
5149 (let ((full-pathname (component-full-pathname component :source)))
5150 (excl:run-shell-command (format nil "~A ~A"
5151 *print-command* full-pathname)))
5152 nil)
5154 #+:allegro
5155 (make::component-operation :hardcopy 'hardcopy-operation)
5156 #+:allegro
5157 (make::component-operation 'hardcopy 'hardcopy-operation)
5160 ;;; *** System Source Size ***
5162 (defun system-source-size (system-name &optional (force :all))
5163 "Prints a short report and returns the size in bytes of the source files in
5164 <system-name>."
5165 (let* ((file-list (files-in-system system-name force :source))
5166 (total-size (file-list-size file-list)))
5167 (format t "~&~a/~a (~:d file~:p) totals ~:d byte~:p (~:d kB)"
5168 system-name force (length file-list)
5169 total-size (round total-size 1024))
5170 total-size))
5172 (defun file-list-size (file-list)
5173 "Returns the size in bytes of the files in <file-list>."
5175 (let ((total-size 0))
5176 (dolist (file file-list)
5177 (with-open-file (stream file)
5178 (incf total-size (file-length stream))))
5179 total-size))
5181 ;;; *** System Tag Table ***
5183 #+:allegro
5184 (defun make-system-tag-table (system-name)
5185 "Makes an Emacs tag table using the GNU etags program."
5186 (let ((files-in-system (files-in-system system-name :all :source)))
5188 (format t "~&Making tag table...")
5189 (excl:run-shell-command (format nil "etags ~{~a ~}" files-in-system))
5190 (format t "done.~%")))
5193 ;;; end of file -- defsystem.lisp --