home *** CD-ROM | disk | FTP | other *** search
/ vis-ftp.cs.umass.edu / vis-ftp.cs.umass.edu.tar / vis-ftp.cs.umass.edu / pub / Software / ASCENDER / ascendMar8.tar / UMass / ISR / mk-defsystem.lisp < prev    next >
Text File  |  1995-04-11  |  115KB  |  2,678 lines

  1. ;;; -*- Mode: LISP; Syntax: Common-Lisp -*-
  2. ;;; Wed May 22 19:33:59 1991 by Mark Kantrowitz <mkant@GLINDA.OZ.CS.CMU.EDU>
  3. ;;; defsystem.lisp
  4.  
  5. ;;; ********************************************************************
  6. ;;; Portable Mini-DefSystem ********************************************
  7. ;;; ********************************************************************
  8.  
  9. ;;; This is a portable system definition facility for Common Lisp. 
  10. ;;; Though home-grown, the syntax was inspired by fond memories of the
  11. ;;; defsystem facility on Symbolics 3600's. The exhaustive lists of
  12. ;;; filename extensions for various lisps and the idea to have one
  13. ;;; "operate-on-system" function instead of separate "compile-system"
  14. ;;; and "load-system" functions were taken from Xerox Corp.'s PCL 
  15. ;;; system.
  16.  
  17. ;;; This system improves on both PCL and Symbolics defsystem utilities
  18. ;;; by performing a topological sort of the graph of file-dependency 
  19. ;;; constraints. Thus, the components of the system need not be listed
  20. ;;; in any special order, because the defsystem command reorganizes them
  21. ;;; based on their constraints. It includes all the standard bells and
  22. ;;; whistles, such as not recompiling a binary file that is up to date
  23. ;;; (unless the user specifies that all files should be recompiled).
  24.  
  25. ;;; Written by Mark Kantrowitz, School of Computer Science, 
  26. ;;; Carnegie Mellon University, October 1989.
  27.  
  28. ;;; Copyright (c) 1989, 1990 by Mark Kantrowitz. All rights reserved.
  29.  
  30. ;;; Use and copying of this software and preparation of derivative works
  31. ;;; based upon this software are permitted, so long as the following
  32. ;;; conditions are met:
  33. ;;;      o no fees or compensation are charged for use, copies, or
  34. ;;;        access to this software
  35. ;;;      o this copyright notice is included intact.
  36. ;;; This software is made available AS IS, and no warranty is made about 
  37. ;;; the software or its performance. 
  38.  
  39. ;;; Please send bug reports, comments and suggestions to mkant@cs.cmu.edu. 
  40.  
  41. ;;; ********************************
  42. ;;; Change Log *********************
  43. ;;; ********************************
  44. ;;;
  45. ;;; Note: Several of the fixes from 30-JAN-91 and 31-JAN-91 were done in
  46. ;;; September and October 1990, but not documented until January 1991. 
  47. ;;;
  48. ;;; hkt = Rick Taube <hkt@cm-next-8.stanford.edu>
  49. ;;; brad = Brad Miller <miller@cs.rochester.edu>
  50. ;;; toni = Anton Beschta <toni%l4@ztivax.siemens.com>
  51. ;;; bw   = Robert Wilhelm <wilhelm@rpal.rockwell.com>
  52. ;;; rs   = Ralph P. Sobek <ralph@vega.laas.fr>
  53. ;;; gi   = Gabriel Inaebnit <inaebnit@research.abb.ch>
  54. ;;; djc  = Daniel J. Clancy <clancy@cs.utexas.edu>
  55. ;;; mc   = Matthew Cornell <cornell@unix1.cs.umass.edu>
  56. ;;; ik   = Ik Su Yoo <ik@ctt.bellcore.com>
  57. ;;; gc   = Guillaume Cartier <cartier@math.uqam.ca>
  58. ;;; Thanks to Steve Strassmann <straz@media-lab.media.mit.edu> and
  59. ;;; Sean Boisen <sboisen@BBN.COM> for detailed bug reports and 
  60. ;;; miscellaneous assistance. Thanks also to Gabriel Inaebnit
  61. ;;; <inaebnit@research.abb.ch> for help with VAXLisp bugs.
  62. ;;;
  63. ;;; 05-NOV-90  hkt  Changed canonicalize-system-name to make system
  64. ;;;                 names package independent. Interns them in the
  65. ;;;                 keyword package. Thus either strings or symbols may
  66. ;;;                 be used to name systems from the user's point of view.
  67. ;;; 05-NOV-90  hkt  Added definition FIND-SYSTEM to allow OOS to
  68. ;;;                 work on systems whose definition hasn't been loaded yet.
  69. ;;; 05-NOV-90  hkt  Added definitions COMPILE-SYSTEM and LOAD-SYSTEM
  70. ;;;                 as alternates to OOS for naive users.
  71. ;;; 05-NOV-90  hkt  Shadowing-import of 'defsystem in Allegro CL 3.1 [NeXT]
  72. ;;;                 into USER package instead of import.
  73. ;;; 15-NOV-90  mk   Changed package name to "MAKE", eliminating "DEFSYSTEM"
  74. ;;;                 to avoid conflicts with allegro, symbolics packages
  75. ;;;                 named "DEFSYSTEM".
  76. ;;; 30-JAN-91  mk   Modified append-directories to work with the 
  77. ;;;                 logical-pathnames system.
  78. ;;; 30-JAN-91  mk   Append-directories now works with Sun CL4.0. Also, fixed
  79. ;;;                 bug wrt Lucid 4.0's pathnames (which changed from lcl3.0
  80. ;;;                 -- 4.0 uses a list for the directory slot, whereas
  81. ;;;                 3.0 required a string). Possible fix to symbolics bug.
  82. ;;; 30-JAN-91  mk   Defined NEW-REQUIRE to make redefinition of REQUIRE
  83. ;;;                 cleaner. Replaced all calls to REQUIRE in this file with
  84. ;;;                 calls to NEW-REQUIRE, which should avoid compiler warnings.
  85. ;;; 30-JAN-91  mk   In VAXLisp, when we redefine lisp:require, the compiler
  86. ;;;                 no longer automatically executes require forms when it
  87. ;;;                 encounters them in a file. The user can always wrap an
  88. ;;;                 (eval-when (compile load eval) ...) around the require
  89. ;;;                 form. Alternately, see commented out code near the
  90. ;;;                 redefinition of lisp:require which redefines it as a
  91. ;;;                 macro instead.
  92. ;;; 30-JAN-91  mk   Added parameter :version to operate-on-system. If it is
  93. ;;;                 a number, that number is used as part of the binary
  94. ;;;                 directory name as the place to store and load files.
  95. ;;;                 If NIL (the default), uses regular binary directory.
  96. ;;;                 If T, tries to find the most recent version of the
  97. ;;;                 binary directory.
  98. ;;; 30-JAN-91  mk   Added global variable *use-timeouts* (default: t), which
  99. ;;;                 specifies whether timeouts should be used in
  100. ;;;                 Y-OR-N-P-WAIT. This is provided for users whose lisps
  101. ;;;                 don't handle read-char-no-hang properly, so that they
  102. ;;;                 can set it to NIL to disable the timeouts. Usually the
  103. ;;;                 reason for this is the lisp is run on top of UNIX,
  104. ;;;                 which buffers input LINES (and provides input editing).
  105. ;;;                 To get around this we could always turn CBREAK mode
  106. ;;;                 on and off, but there's no way to do this in a portable
  107. ;;;                 manner.
  108. ;;; 30-JAN-91  mk   Fixed bug where in :test t mode it was actually providing
  109. ;;;                 the system, instead of faking it.
  110. ;;; 30-JAN-91  mk   Changed storage of system definitions to a hash table.
  111. ;;;                 Changed canonicalize-system-name to coerce the system
  112. ;;;                 names to uppercase strings. Since we're no longer using
  113. ;;;                 get, there's no need to intern the names as symbols,
  114. ;;;                 and strings don't have packages to cause problems.
  115. ;;;                 Added UNDEFSYSTEM, DEFINED-SYSTEMS, and DESCRIBE-SYSTEM.
  116. ;;;                 Added :delete-binaries command. 
  117. ;;; 31-JAN-91  mk   Franz Allegro CL has a defsystem in the USER package,
  118. ;;;                 so we need to do a shadowing import to avoid name
  119. ;;;                 conflicts.
  120. ;;; 31-JAN-91  mk   Fixed bug in compile-and-load-operation where it was
  121. ;;;                 only loading newly compiled files.
  122. ;;; 31-JAN-91  mk   Added :load-time slot to components to record the
  123. ;;;                 file-write-date of the binary/source file that was loaded.
  124. ;;;                 Now knows "when" (which date version) the file was loaded.
  125. ;;;                 Added keyword :minimal-load and global *minimal-load*
  126. ;;;                 to enable defsystem to avoid reloading unmodified files.
  127. ;;;                 Note that if B depends on A, but A is up to date and
  128. ;;;                 loaded and the user specified :minimal-load T, then A
  129. ;;;                 will not be loaded even if B needs to be compiled. So
  130. ;;;                 if A is an initializations file, say, then the user should
  131. ;;;                 not specify :minimal-load T.
  132. ;;; 31-JAN-91  mk   Added :load-only slot to components. If this slot is
  133. ;;;                 specified as non-NIL, skips over any attempts to compile
  134. ;;;                 the files in the component. (Loading the file satisfies
  135. ;;;                 the need to recompile.)
  136. ;;; 31-JAN-91  mk   Eliminated use of set-alist-lookup and alist-lookup,
  137. ;;;                 replacing it with hash tables. It was too much bother,
  138. ;;;                 and rather brittle too.
  139. ;;; 31-JAN-91  mk   Defined #@ macro character for use with AFS @sys
  140. ;;;                 feature simulator. #@"directory" is then synonymous
  141. ;;;                 with (afs-binary-directory "directory").
  142. ;;; 31-JAN-91  mk   Added :private-file type of module. It is similar to
  143. ;;;                 :file, but has an absolute pathname. This allows you
  144. ;;;                 to specify a different version of a file in a system
  145. ;;;                 (e.g., if you're working on the file in your home
  146. ;;;                 directory) without completely rewriting the system
  147. ;;;                 definition.
  148. ;;; 31-JAN-91  mk   Operations on systems, such as :compile and :load,
  149. ;;;                 now propagate to subsystems the system depends on
  150. ;;;                 if *operations-propagate-to-subsystems* is T (the default)
  151. ;;;                 and the systems were defined using either defsystem
  152. ;;;                 or as a :system component of another system. Thus if
  153. ;;;                 a system depends on another, it can now recompile the 
  154. ;;;                 other.
  155. ;;; 01-FEB-91  mk   Added default definitions of PROVIDE/REQUIRE/*MODULES*
  156. ;;;                 for lisps that have thrown away these definitions in
  157. ;;;                 accordance with CLtL2.
  158. ;;; 01-FEB-91  mk   Added :compile-only slot to components. Analogous to
  159. ;;;                 :load-only. If :compile-only is T, will not load the
  160. ;;;                 file on operation :compile. Either compiles or loads
  161. ;;;                 the file, but not both. In other words, compiling the
  162. ;;;                 file satisfies the demand to load it. This is useful
  163. ;;;                 for PCL defmethod and defclass definitions, which wrap  
  164. ;;;                 an (eval-when (compile load eval) ...) around the body
  165. ;;;                 of the definition -- we save time by not loading the
  166. ;;;                 compiled code, since the eval-when forces it to be
  167. ;;;                 loaded. Note that this may not be entirely safe, since
  168. ;;;                 CLtL2 has added a :load keyword to compile-file, and
  169. ;;;                 some lisps may maintain a separate environment for
  170. ;;;                 the compiler. This feature is for the person who asked
  171. ;;;                 that a :COMPILE-SATISFIES-LOAD keyword be added to
  172. ;;;                 modules. It's named :COMPILE-ONLY instead to match 
  173. ;;;                 :LOAD-ONLY.
  174. ;;; 11-FEB-91  mk   Now adds :mk-defsystem to features list, to allow
  175. ;;;                 special cased loading of defsystem if not already
  176. ;;;                 present.
  177. ;;; 19-FEB-91  duff Added filename extension for hp9000/300's running Lucid.
  178. ;;; 26-FEB-91  mk   Distinguish between toplevel systems (defined with
  179. ;;;                 defsystem) and systems defined as a :system module
  180. ;;;                 of a defsystem. The former can depend only on systems,
  181. ;;;                 while the latter can depend on anything at the same
  182. ;;;                 level.
  183. ;;; 12-MAR-91  mk   Added :subsystem component type to be a system with
  184. ;;;                 pathnames relative to its parent component.
  185. ;;; 12-MAR-91  mk   Uncommented :device :absolute for CMU pathnames, so
  186. ;;;                 that the leading slash is included.
  187. ;;; 12-MAR-91  brad Patches for Allegro 4.0.1 on Sparc. 
  188. ;;; 12-MAR-91  mk   Changed definition of format-justified-string so that
  189. ;;;                 it no longer depends on the ~<~> format directives,
  190. ;;;                 because Allegro 4.0.1 has a bug which doesn't support
  191. ;;;                 them. Anyway, the new definition is twice as fast
  192. ;;;                 and conses half as much as FORMAT.
  193. ;;; 12-MAR-91 toni  Remove nils from list in expand-component-components.
  194. ;;; 12-MAR-91 bw    If the default-package and system have the same name,
  195. ;;;                 and the package is not loaded, this could lead to
  196. ;;;                 infinite loops, so we bomb out with an error.
  197. ;;;                 Fixed bug in default packages.
  198. ;;; 13-MAR-91 mk    Added global *providing-blocks-load-propagation* to
  199. ;;;                 control whether system dependencies are loaded if they
  200. ;;;                 have already been provided.
  201. ;;; 13-MAR-91 brad  In-package is a macro in CLtL2 lisps, so we change
  202. ;;;                 the package manually in operate-on-component.
  203. ;;; 15-MAR-91 mk    Modified *central-registry* to be either a single
  204. ;;;                 directory pathname, or a list of directory pathnames
  205. ;;;                 to be checked in order.
  206. ;;; 15-MAR-91 rs    Added afs-source-directory to handle versions when
  207. ;;;                 compiling C code under lisp. Other minor changes to
  208. ;;;                 translate-version and operate-on-system.
  209. ;;; 21-MAR-91 gi    Fixed bug in defined-systems. 
  210. ;;; 22-MAR-91 mk    Replaced append-directories with new version that works
  211. ;;;                 by actually appending the directories, after massaging
  212. ;;;                 them into the proper format. This should work for all
  213. ;;;                 CLtL2-compliant lisps.
  214. ;;; 09-APR-91 djc   Missing package prefix for lp:pathname-host-type.
  215. ;;;                 Modified component-full-pathname to work for logical
  216. ;;;                 pathnames.
  217. ;;; 09-APR-91 mk    Added *dont-redefine-require* to control whether
  218. ;;;                 REQUIRE is redefined. Fixed minor bugs in redefinition
  219. ;;;                 of require.
  220. ;;; 12-APR-91 mk    (pathname-host nil) causes an error in MCL 2.0b1
  221. ;;; 12-APR-91 mc    Ported to MCL2.0b1.
  222. ;;; 16-APR-91 mk    Fixed bug in needs-loading where load-time and
  223. ;;;                 file-write-date got swapped.
  224. ;;; 16-APR-91 mk    If the component is load-only, defsystem shouldn't
  225. ;;;                 tell you that there is no binary and ask you if you
  226. ;;;                 want to load the source.  
  227. ;;; 17-APR-91 mc    Two additional operations for MCL.
  228. ;;; 21-APR-91 mk    Added feature requested by ik. *files-missing-is-an-error*
  229. ;;;                 new global variable which controls whether files (source
  230. ;;;                 and binary) missing cause a continuable error or just a
  231. ;;;                 warning.
  232. ;;; 21-APR-91 mk    Modified load-file-operation to allow compilation of source
  233. ;;;                 files during load if the binary files are old or
  234. ;;;                 non-existent. This adds a :compile-during-load keyword to
  235. ;;;                 oos, and load-system. Global *compile-during-load* sets
  236. ;;;                 the default (currently :query).
  237. ;;; 21-APR-91 mk    Modified find-system so that there is a preference for
  238. ;;;                 loading system files from disk, even if the system is
  239. ;;;                 already defined in the environment.
  240. ;;; 25-APR-91 mk    Removed load-time slot from component defstruct and added
  241. ;;;                 function COMPONENT-LOAD-TIME to store the load times in a
  242. ;;;                 hash table. This is safer than the old definition because
  243. ;;;                 it doesn't wipe out load times every time the system is
  244. ;;;                 redefined.
  245. ;;; 25-APR-91 mk    Completely rewrote load-file-operation. Fixed some bugs
  246. ;;;                 in :compile-during-load and in the behavior of defsystem
  247. ;;;                 when multiple users are compiling and loading a system
  248. ;;;                 instead of just a single user.
  249. ;;; 16-MAY-91 mk    Modified FIND-SYSTEM to do the right thing if the system
  250. ;;;                 definition file cannot be found.
  251. ;;; 16-MAY-91 mk    Added globals *source-pathname-default* and
  252. ;;;                 *binary-pathname-default* to contain default values for
  253. ;;;                 :source-pathname and :binary-pathname. For example, set
  254. ;;;                 *source-pathname-default* to "" to avoid having to type
  255. ;;;                 :source-pathname "" all the time.
  256. ;;; 27-MAY-91 mk    Fixed bug in new-append-directories where directory
  257. ;;;                 components of the form "foo4.0" would appear as "foo4",
  258. ;;;                 since pathname-name truncates the type. Changed
  259. ;;;                 pathname-name to file-namestring.
  260. ;;;  3-JUN-91 gc    Small bug in new-append-directories; replace (when
  261. ;;;                 abs-name) with (when (not (null-string abs-name)))
  262. ;;;  4-JUN-91 mk    Additional small change to new-append-directories for
  263. ;;;                 getting the device from the relative pname if the abs
  264. ;;;                 pname is "". This is to fix a small behavior in CMU CL old
  265. ;;;                 compiler. Also changed (when (not (null-string abs-name)))
  266. ;;;                 to have an (and abs-name) in there.
  267.  
  268.  
  269.  
  270. ;;; ********************************
  271. ;;; To Do **************************
  272. ;;; ********************************
  273. ;;;
  274. ;;; Need way to load old binaries even if source is newer.
  275. ;;;
  276. ;;; Load a system (while not loading anything already loaded)
  277. ;;; and inform the user of out of date fasls with the choice
  278. ;;; to load the old fasl or recompile and then load the new
  279. ;;; fasl?
  280. ;;; 
  281. ;;; modify compile-file-operation to handle a query keyword....
  282. ;;;
  283. ;;; Perhaps systems should keep around the file-write-date of the system
  284. ;;; definition file, to prevent excessive reloading of the system definition?
  285. ;;;
  286. ;;; load-file-operation needs to be completely reworked to simplify the
  287. ;;; logic of when files get loaded or not.
  288. ;;;
  289. ;;; Need to revamp output: Nesting and indenting verbose output doesn't
  290. ;;; seem cool, especially when output overflows the 80-column margins.
  291. ;;;
  292. ;;; Document various ways of writing a system. simple (short) form
  293. ;;; (where :components is just a list of filenames) in addition to verbose.
  294. ;;; Put documentation strings in code.
  295. ;;;
  296. ;;; :load-time for modules and systems -- maybe record the time the system
  297. ;;; was loaded/compiled here and print it in describe-system?
  298. ;;;
  299. ;;; Make it easy to define new functions that operate on a system. For 
  300. ;;; example, a function that prints out a list of files that have changed, 
  301. ;;; hardcopy-system, edit-system, etc.
  302. ;;;
  303. ;;; If a user wants to have identical systems for different lisps, do we 
  304. ;;; force the user to use logical pathnames? Or maybe we should write a 
  305. ;;; generic-pathnames package that parses any pathname format into a 
  306. ;;; uniform underlying format (i.e., pull the relevant code out of
  307. ;;; logical-pathnames.lisp and clean it up a bit).
  308. ;;;
  309. ;;;    Verify that Mac pathnames now work with append-directories.
  310. ;;;
  311. ;;; A common human error is to violate the modularization by making a file
  312. ;;; in one module depend on a file in another module, instead of making
  313. ;;; one module depend on the other. This is caught because the dependency
  314. ;;; isn't found. However, is there any way to provide a more informative
  315. ;;; error message? Probably not, especially if the system has multiple
  316. ;;; files of the same name.
  317. ;;; 
  318. ;;; For a module none of whose files needed to be compiled, have it print out
  319. ;;; "no files need recompilation".
  320. ;;; 
  321. ;;; Write a system date/time to a file? (version information) I.e., if the
  322. ;;; filesystem supports file version numbers, write an auxiliary file to
  323. ;;; the system definition file that specifies versions of the system and
  324. ;;; the version numbers of the associated files. 
  325. ;;; 
  326. ;;; Add idea of a patch directory.
  327. ;;; 
  328. ;;; In verbose printout, have it log a date/time at start and end of
  329. ;;; compilation: 
  330. ;;;     Compiling system "test" on 31-Jan-91 21:46:47 
  331. ;;;     by Defsystem version v2.0 01-FEB-91.
  332. ;;; 
  333. ;;; Define other :force options:
  334. ;;;    :query    allows user to specify that a file not normally compiled
  335. ;;;              should be. OR
  336. ;;;    :confirm  allows user to specify that a file normally compiled
  337. ;;;              shouldn't be. AND
  338. ;;; 
  339. ;;; We currently assume that compilation-load dependencies and if-changed
  340. ;;; dependencies are identical. However, in some cases this might not be
  341. ;;; true. For example, if we change a macro we have to recompile functions
  342. ;;; that depend on it (except in lisps that automatically do this, such
  343. ;;; as the new CMU Common Lisp), but not if we change a function. Splitting
  344. ;;; these apart (with appropriate defaulting) would be nice, but not worth
  345. ;;; doing immediately since it may save only a couple of file recompilations,
  346. ;;; while making defsystem much more complex than it already is. 
  347. ;;; 
  348.  
  349. ;;; ********************************
  350. ;;; Notes **************************
  351. ;;; ********************************
  352. ;;;
  353. ;;;    DEFSYSTEM has been tested (successfully) in the following lisps:
  354. ;;;       CMU Common Lisp (M2.9 15-Aug-90, Compiler M1.8 15-Aug-90)
  355. ;;;       CMU Common Lisp (14-Dec-90 beta, Python Compiler 0.0 PMAX/Mach)
  356. ;;;       ExCL (Franz Allegro CL 3.1.12 [DEC 3100] 3/30/90)
  357. ;;;       ExCL (Franz Allegro CL 4.0.1 [SPARC])
  358. ;;;       Lucid CL (Version 2.1 6-DEC-87)
  359. ;;;       Lucid Common Lisp (3.0 [SPARC,SUN3]) 
  360. ;;;       Lucid Common Lisp (4.0 [SPARC,SUN3])
  361. ;;;       VAXLisp (v2.2) [VAX/VMS]
  362. ;;;       VAXLisp (v3.1)
  363. ;;;
  364. ;;;    DEFSYSTEM needs to be tested in the following lisps:
  365. ;;;       Symbolics Common Lisp (8.0)
  366. ;;;       Macintosh Allegro Common Lisp (1.3.2)
  367. ;;;       KCL (June 3, 1987 or later)
  368. ;;;       AKCL (1.86, June 30, 1987 or later)
  369. ;;;       TI (Release 4.1 or later)
  370. ;;;       Ibuki Common Lisp (01/01, October 15, 1987)
  371. ;;;       Golden Common Lisp (3.1 IBM-PC)
  372. ;;;       HP Common Lisp (same as Lucid?)
  373. ;;;       Procyon Common Lisp
  374.  
  375.  
  376. ;;; ********************************************************************
  377. ;;; How to Use this System *********************************************
  378. ;;; ********************************************************************
  379.  
  380. ;;; To use this system,
  381. ;;; 1. If you want to have a central registry of system definitions, 
  382. ;;;    modify the value of the variable *central-registry* below.
  383. ;;; 2. Load this file (defsystem.lisp) in either source or compiled form,
  384. ;;; 3. Load the file containing the "defsystem" definition of your system,
  385. ;;; 4. Use the function "operate-on-system" to do things to your system.
  386.  
  387. ;;; For more information, see the documentation and examples in defsystem.text.
  388.  
  389. ;;; ****************************************************************
  390. ;;; Lisp Code ******************************************************
  391. ;;; ****************************************************************
  392.  
  393. ;;; ********************************
  394. ;;; Massage CLtL2 onto *features* **
  395. ;;; ********************************
  396. ;;; Let's be smart about CLtL2 compatible Lisps:
  397. (eval-when (compile load eval)
  398.   #+(or (and :excl :allegro-v4.0) :mcl)
  399.   (pushnew :cltl2 *features*))
  400.  
  401. ;;; ********************************
  402. ;;; Provide/Require/*modules* ******
  403. ;;; ********************************
  404.  
  405. ;;; Since CLtL2 has dropped require and provide from the language, some
  406. ;;; lisps may not have the functions PROVIDE and REQUIRE and the
  407. ;;; global *MODULES*. So if lisp::provide and user::provide are not
  408. ;;; defined, we define our own.
  409.  
  410. ;;; Hmmm. CMU CL old compiler gives bogus warnings here about functions
  411. ;;; and variables not being declared or bound, apparently because it
  412. ;;; sees that (or (fboundp 'lisp::require) (fboundp 'user::require)) returns
  413. ;;; T, so it doesn't really bother when compiling the body of the unless.
  414. ;;; The new compiler does this properly, so I'm not going to bother
  415. ;;; working around this.
  416.  
  417. #-(or (and :CMU (not :new-compiler)) :vms :mcl)
  418. (eval-when (compile load eval)
  419.   (unless (or (fboundp 'lisp::require) (fboundp 'user::require)
  420.           #+(and :excl :allegro-v4.0) (fboundp 'cltl1::require))
  421.     (in-package "LISP")
  422.     (export '(*modules* provide require))
  423.  
  424.     ;; Documentation strings taken almost literally from CLtL1.
  425.   
  426.     (defvar *MODULES* ()
  427.       "List of names of the modules that have been loaded into Lisp so far.
  428.      It is used by PROVIDE and REQUIRE.")
  429.  
  430.     ;; We provide two different ways to define modules. The default way
  431.     ;; is to put either a source or binary file with the same name
  432.     ;; as the module in the library directory. The other way is to define
  433.     ;; the list of files in the module with defmodule.
  434.  
  435.     ;; The directory listed in *library* is implementation dependent,
  436.     ;; and is intended to be used by Lisp manufacturers as a place to
  437.     ;; store their implementation dependent packages. 
  438.     ;; Lisp users should use systems and *central-registry* to store
  439.     ;; their packages -- it is intended that *central-registry* is
  440.     ;; set by the user, while *library* is set by the lisp.
  441.  
  442.     (defvar *library* nil        ; "/usr/local/lisp/Modules/"
  443.       "Directory within the file system containing files, where the name
  444.      of a file is the same as the name of the module it contains.")
  445.  
  446.     (defun canonicalize-module-name (name)
  447.       ;; if symbol, string-downcase the printrep to make nicer filenames.
  448.       (if (stringp name) name (string-downcase (string name))))
  449.  
  450.     (defvar *module-files* (make-hash-table :test #'equal)
  451.       "Hash table mapping from module names to list of files for the
  452.      module. REQUIRE loads these files in order.")
  453.     (defmacro defmodule (name &rest files)
  454.       "Defines a module NAME to load the specified FILES in order."
  455.       `(setf (gethash (canonicalize-module-name ,name) *module-files*)
  456.          ',files))
  457.     (defun module-files (name)
  458.       (gethash name *module-files*))
  459.  
  460.     (defun PROVIDE (name)
  461.       "Adds a new module name to the list of modules maintained in the
  462.      variable *modules*, thereby indicating that the module has been 
  463.      loaded. Name may be a string or symbol -- strings are case-senstive,
  464.      while symbols are treated like lowercase strings. Returns T if
  465.      NAME was not already present, NIL otherwise."
  466.       (let ((module (canonicalize-module-name name)))
  467.     (unless (find module *modules* :test #'string=)
  468.       ;; Module not present. Add it and return T to signify that it 
  469.       ;; was added.
  470.       (push module *modules*)
  471.       t)))
  472.  
  473.     (defun REQUIRE (name &optional pathname)
  474.       "Tests whether a module is already present. If the module is not
  475.      present, loads the appropriate file or set of files. The pathname
  476.      argument, if present, is a single pathname or list of pathnames
  477.      whose files are to be loaded in order, left to right. If the
  478.      pathname is nil, the system first checks if a module was defined
  479.      using defmodule and uses the pathnames so defined. If that fails,
  480.      it looks in the library directory for a file with name the same
  481.      as that of the module. Returns T if it loads the module."
  482.       (let ((module (canonicalize-module-name name)))
  483.     (unless (find module *modules* :test #'string=)
  484.       ;; Module is not already present.
  485.       (when (and pathname (not (listp pathname)))
  486.         ;; If there's a pathname or pathnames, ensure that it's a list.
  487.         (setf pathname (list pathname)))
  488.       (unless pathname 
  489.         ;; If there's no pathname, try for a defmodule definition.
  490.         (setf pathname (module-files module)))
  491.       (unless pathname
  492.         ;; If there's still no pathname, try the library directory.
  493.         (when *library*
  494.           (setf pathname (concatenate 'string *library* module))
  495.           ;; Test if the file exists.
  496.           ;; We assume that the lisp will default the file type 
  497.           ;; appropriately. If it doesn't, use #+".fasl" or some
  498.           ;; such in the concatenate form above.
  499.           (if (probe-file pathname)
  500.           ;; If it exists, ensure we've got a list
  501.           (setf pathname (list pathname))
  502.           ;; If the library file doesn't exist, we don't want
  503.           ;; a load error.
  504.           (setf pathname nil))))
  505.       ;; Now that we've got the list of pathnames, let's load them.
  506.       (dolist (pname pathname T)
  507.         (load pname :verbose nil)))))))
  508.  
  509. ;;; ********************************
  510. ;;; Set up Package *****************
  511. ;;; ********************************
  512.  
  513.  
  514. ;;; Unfortunately, lots of lisps have their own defsystems, some more
  515. ;;; primitive than others, all uncompatible, and all in the DEFSYSTEM
  516. ;;; package. To avoid name conflicts, we've decided to name this the
  517. ;;; MAKE package. A nice side-effect is that the short nickname
  518. ;;; MK is my initials.
  519.  
  520. #-:cltl2
  521. (in-package "MAKE" :nicknames '("MK"))
  522.  
  523. ;;; For CLtL2 compatible lisps...
  524. #+(and :excl :allegro-v4.0 :cltl2)
  525. (defpackage "MAKE" (:nicknames "MK") (:use "COMMON-LISP") 
  526.   (:import-from cltl1 *modules* provide require))
  527. #+:mcl                                  
  528. (defpackage "MAKE" (:nicknames "MK") (:use "COMMON-LISP") 
  529.   (:import-from ccl *modules* provide require))
  530. #+(and :cltl2 (not (or (and :excl :allegro-v4.0) :mcl)))   
  531. (unless (find-package "MAKE") 
  532.   (make-package "MAKE" :nicknames '("MK") :use '("COMMON-LISP")))
  533.  
  534. #+:cltl2
  535. (in-package "MAKE")
  536.  
  537. #+(and :excl :allegro-v4.0 :cltl2)
  538. (cltl1:provide 'make)
  539. #+:mcl
  540. (ccl:provide 'make)
  541. #+(and :cltl2 (not (or (and :excl :allegro-v4.0) :mcl)))
  542. (provide 'make)
  543. #-:cltl2
  544. (provide 'make)
  545.  
  546. (pushnew :mk-defsystem *features*)
  547.  
  548. (eval-when (compile load eval)
  549.   (defvar *special-exports*
  550.     '(defsystem compile-system load-system))
  551.    (defvar *exports*
  552.      '(operate-on-system oos afs-binary-directory afs-source-directory
  553.              files-in-system))
  554.  
  555.    (defvar *other-exports* 
  556.      '(*central-registry* *bin-subdir* 
  557.               machine-type-translation software-type-translation
  558.                     ;require
  559.               allegro-make-system-fasl 
  560.               files-which-need-compilation  
  561.               undefsystem
  562.               defined-systems
  563.               describe-system
  564.               *defsystem-version*
  565.               *compile-during-load*
  566.               *minimal-load*
  567.               *dont-redefine-require*
  568.               *files-missing-is-an-error*
  569.               *reload-systems-from-disk*
  570.               *source-pathname-default*
  571.               *binary-pathname-default*
  572.               )))
  573.  
  574. ;;; The external interface consists of *exports* and *other-exports*.
  575. (eval-when (compile load eval)
  576.    (export *exports*)
  577.    (export *special-exports*)
  578.    (export *other-exports*))
  579.  
  580. ;;; We import these symbols into the USER package to make them
  581. ;;; easier to use. Since some lisps have already defined defsystem
  582. ;;; in the user package, we may have to shadowing-import it.
  583. #-(OR :CMU :CCL :ALLEGRO :EXCL)
  584. (eval-when (compile load eval)
  585.   (import *exports* #-:cltl2 "USER" #+:cltl2 "COMMON-LISP-USER")
  586.   (import *special-exports* #-:cltl2 "USER" #+:cltl2 "COMMON-LISP-USER"))
  587. #+(OR :CMU :CCL :ALLEGRO :EXCL)
  588. (eval-when (compile load eval)
  589.   (import *exports* #-:cltl2 "USER" #+:cltl2 "COMMON-LISP-USER")
  590.   (shadowing-import *special-exports* 
  591.             #-:cltl2 "USER" 
  592.             #+:cltl2 "COMMON-LISP-USER"))
  593.  
  594. #-PCL(when (find-package "PCL") 
  595.        (pushnew :pcl *modules*)
  596.        (pushnew :pcl *features*))
  597.  
  598. ;;; ********************************
  599. ;;; Defsystem Version **************
  600. ;;; ********************************
  601. (defvar *defsystem-version* "v2.4 22-MAY-91"
  602.   "Current version number/date for Defsystem.")
  603.  
  604. ;;; ********************************
  605. ;;; Customizable System Parameters *
  606. ;;; ********************************
  607.  
  608. (defvar *dont-redefine-require* nil
  609.   "If T, prevents the redefinition of REQUIRE. This is useful for
  610.    lisps that treat REQUIRE specially in the compiler.")
  611.  
  612. ;;; Change this variable to set up the location of a central
  613. ;;; repository for system definitions if you want one.
  614. (defvar *central-registry* '() 
  615.   "Central directory of system definitions. May be either a single
  616.    directory pathname, or a list of directory pathnames to be checked
  617.    after the local directory.")
  618. ;;; (setq *central-registry* "/usr/local/lisp/Registry/")
  619.  
  620. (defvar *bin-subdir* ".bin/"
  621.   "The subdirectory of an AFS directory where the binaries are really kept.")
  622.  
  623. ;;; These variables set up defaults for operate-on-system, and are used 
  624. ;;; for communication in lieu of parameter passing. Yes, this is bad,
  625. ;;; but it keeps the interface small. Also, in the case of the -if-no-binary
  626. ;;; variables, parameter passing would require multiple value returns
  627. ;;; from some functions. Why make life complicated?
  628. (defvar *tell-user-when-done* nil
  629.   "If T, system will print ...DONE at the end of an operation")
  630. (defvar *oos-verbose* nil 
  631.   "Operate on System Verbose Mode")
  632. (defvar *oos-test* nil 
  633.   "Operate on System Test Mode")
  634. (defvar *load-source-if-no-binary* nil
  635.   "If T, system will try loading the source if the binary is missing")
  636. (defvar *bother-user-if-no-binary* t
  637.   "If T, the system will ask the user whether to load the source if 
  638.    the binary is missing")
  639. (defvar *load-source-instead-of-binary* nil
  640.   "If T, the system will load the source file instead of the binary.")
  641. (defvar *compile-during-load* :query
  642.   "If T, the system will compile source files during load if the
  643.    binary file is missing. If :query, it will ask the user for
  644.    permission first.")
  645. (defvar *minimal-load* nil
  646.   "If T, the system tries to avoid reloading files that were already loaded
  647.    and up to date.")
  648.  
  649. (defvar *files-missing-is-an-error* t
  650.   "If both the source and binary files are missing, signal a continuable 
  651.    error instead of just a warning.")
  652.  
  653. (defvar *operations-propagate-to-subsystems* t
  654.   "If T, operations like :COMPILE and :LOAD propagate to subsystems
  655.    of a system that are defined either using a component-type of :system
  656.    or by another defsystem form.")
  657.  
  658. ;;; Particular to CMULisp
  659. (defvar *compile-error-file-type* "err"
  660.   "File type of compilation error file in cmulisp")
  661. (defvar *cmu-errors-to-terminal* t
  662.   "Argument to :errors-to-terminal in compile-file in cmulisp")
  663. (defvar *cmu-errors-to-file* t
  664.   "If T, cmulisp will write an error file during compilation")
  665.  
  666. ;;; ********************************
  667. ;;; Global Variables ***************
  668. ;;; ********************************
  669.  
  670. ;;; Massage people's *features* into better shape.
  671. (eval-when (compile load eval)  
  672.   (dolist (feature *features*)
  673.     (when (and (symbolp feature)   ; 3600
  674.                (equal (symbol-name feature) "CMU"))
  675.       (pushnew :CMU *features*)))
  676.   
  677.   #+Lucid
  678.   (when (search "IBM RT PC" (machine-type))
  679.     (pushnew :ibm-rt-pc *features*))
  680.   )
  681.  
  682. ;;; *filename-extensions* is a cons of the source and binary extensions.
  683. (defvar *filename-extensions*
  684.   (car '(#+(and Symbolics Lispm)              ("lisp" . "bin")
  685.          #+(and dec common vax (not ultrix))  ("LSP"  . "FAS")
  686.          #+(and dec common vax ultrix)        ("lsp"  . "fas")
  687.          #+KCL                                ("lsp"  . "o")
  688.          #+IBCL                               ("lsp"  . "o")
  689.          #+Xerox                              ("lisp" . "dfasl")
  690.      ;; the entry for (and lucid hp300) must precede
  691.      ;; that of (and lucid mc68000) for hp9000/300's running lucid,
  692.      ;; since *features* on hp9000/300's also include the :mc68000
  693.      ;; feature.
  694.      #+(and lucid hp300)                  ("lisp" . "6bin")
  695.          #+(and Lucid MC68000)                ("lisp" . "lbin")
  696.          #+(and Lucid Vax)                    ("lisp" . "vbin")   
  697.          #+(and Lucid Prime)                  ("lisp" . "pbin")
  698.          #+(and Lucid SUNRise)                ("lisp" . "sbin")
  699.          #+(and Lucid SPARC)                  ("lisp" . "sbin")
  700.          #+(and Lucid :IBM-RT-PC)              ("lisp" . "bbin")
  701.      ;; PA is Precision Architecture, HP's 9000/800 RISC cpu
  702.      #+(and Lucid PA)                    ("lisp" . "hbin")   
  703.          #+excl                               ("cl"   . "fasl")
  704.          #+:CMU                               ("lisp" . "fasl")
  705.      #+PRIME                              ("lisp" . "pbin")
  706.          #+HP                                 ("l"    . "b")
  707.          #+TI ("lisp" . #.(string (si::local-binary-file-type)))
  708.          #+:gclisp                            ("LSP"  . "F2S")
  709.          #+pyramid                            ("clisp" . "o")
  710.          #+:coral                             ("lisp" . "fasl")
  711.      ;; Harlequin LispWorks on Mips M2000
  712.      #+(and :mips :lispworks)           ("lisp" . "mfasl")
  713.          
  714.          ;; Otherwise,
  715.          ("lisp" . "lbin")))
  716.   "Filename extensions for Common Lisp. A cons of the form
  717.    (Source-Extension . Binary-Extension). If the system is 
  718.    unknown (as in *features* not known), defaults to lisp and lbin.")
  719.  
  720. ;;; There is no real support for this variable being nil, so don't change it.
  721. ;;; Note that in any event, the toplevel system (defined with defsystem)
  722. ;;; will have its dependencies delayed. Not having dependencies delayed
  723. ;;; might be useful if we define several systems within one defsystem.
  724. (defvar *system-dependencies-delayed* t 
  725.   "If T, system dependencies are expanded at run time")
  726.  
  727. ;;; Replace this with consp, dammit!
  728. (defun non-empty-listp (list)
  729.   (and list (listp list)))
  730.  
  731. ;;; ********************************
  732. ;;; Component Operation Definition *
  733. ;;; ********************************
  734. (defvar *component-operations* (make-hash-table :test #'equal)
  735.   "Hash table of (operation-name function) pairs.")
  736. (defun component-operation (name &optional operation)
  737.   (if operation
  738.       (setf (gethash name *component-operations*) operation)
  739.       (gethash name *component-operations*)))
  740.  
  741. ;;; ********************************
  742. ;;; AFS @sys immitator *************
  743. ;;; ********************************
  744.  
  745. ;;; mc 11-Apr-91: Bashes MCL's point reader, so commented out.
  746. #-:mcl 
  747. (eval-when (compile load eval)
  748.   ;; Define #@"foo" as a shorthand for (afs-binary-directory "foo").
  749.   ;; For example,
  750.   ;;    <cl> #@"foo"
  751.   ;;    "foo/.bin/rt_mach/"
  752.   (set-dispatch-macro-character 
  753.    #\# #\@ 
  754.    #'(lambda (stream char arg)
  755.        (declare (ignore char arg))
  756.        `(afs-binary-directory ',(read stream t nil t)))))
  757.  
  758. (defun afs-binary-directory (root-directory)
  759.   ;; Function for obtaining the directory AFS's @sys feature would have
  760.   ;; chosen when we're not in AFS. This function is useful as the argument
  761.   ;; to :binary-pathname in defsystem. For example,
  762.   ;; :binary-pathname (afs-binary-directory "scanner/")
  763.   (let ((machine (machine-type-translation (machine-type)))
  764.     (software (software-type-translation (software-type))))
  765.     ;; pmax_mach rt_mach sun3_35 sun3_mach vax_mach
  766.     (setq root-directory (namestring root-directory))
  767.     (setq root-directory (ensure-trailing-slash root-directory))
  768.     (format nil "~A~@[~A~]~@[~A/~]" 
  769.         root-directory
  770.         *bin-subdir*
  771.         (afs-component machine software))))
  772.  
  773. (defun afs-source-directory (root-directory &optional version-flag)
  774.   ;; Function for obtaining the directory AFS's @sys feature would have
  775.   ;; chosen when we're not in AFS. This function is useful as the argument
  776.   ;; to :source-pathname in defsystem.
  777.   (setq root-directory (namestring root-directory))
  778.   (setq root-directory (ensure-trailing-slash root-directory))
  779.   (format nil "~A~@[~A/~]" 
  780.           root-directory
  781.           (and version-flag (translate-version *version*))))
  782.  
  783. (defun null-string (s)
  784.   (string-equal s ""))
  785.  
  786. (defun ensure-trailing-slash (dir)
  787.   (if (and dir 
  788.        (not (null-string dir))
  789.        (not (char= (char dir
  790.                  (1- (length dir)))
  791.                #\/)))
  792.       (concatenate 'string dir "/")
  793.       dir))
  794.  
  795. (defun afs-component (machine software)
  796.   (format nil "~@[~A~]~@[_~A~]" 
  797.         machine 
  798.         (or software "mach")))
  799.  
  800. (defvar *machine-type-alist* (make-hash-table :test #'equal)
  801.   "Hash table for retrieving the machine-type")
  802. (defun machine-type-translation (name &optional operation)
  803.   (if operation
  804.       (setf (gethash (string-upcase name) *machine-type-alist*) operation)
  805.       (gethash (string-upcase name) *machine-type-alist*)))
  806.  
  807. (machine-type-translation "IBM RT PC"   "rt")
  808. (machine-type-translation "DEC 3100"    "pmax")
  809. (machine-type-translation "DEC VAX-11"  "vax")
  810. (machine-type-translation "Sun3"        "sun3")
  811. (machine-type-translation "Sun-4"       "sun4")
  812. #+(and :lucid :sun :mc68000)
  813. (machine-type-translation "unknown"     "sun3")
  814.  
  815.  
  816. (defvar *software-type-alist* (make-hash-table :test #'equal)
  817.   "Hash table for retrieving the software-type")
  818. (defun software-type-translation (name &optional operation)
  819.   (if operation
  820.       (setf (gethash (string-upcase name) *software-type-alist*) operation)
  821.       (gethash (string-upcase name) *software-type-alist*)))
  822.  
  823. (software-type-translation "BSD UNIX" "mach") ; "unix"
  824. (software-type-translation "Ultrix" "mach") ; "ultrix"
  825. (software-type-translation "SunOS" "SunOS")
  826. (software-type-translation "MACH/4.3BSD" "mach")
  827. #+:lucid
  828. (software-type-translation "Unix" 
  829.                #+:lcl4.0 "4.0"
  830.                #+(and :lcl3.0 (not :lcl4.0)) "3.0")
  831.  
  832. ;;; ********************************
  833. ;;; System Names *******************
  834. ;;; ********************************
  835. (defun canonicalize-system-name (name)
  836.   ;; Originally we were storing systems using GET. This meant that the
  837.   ;; name of a system had to be a symbol, so we interned the symbols
  838.   ;; in the keyword package to avoid package dependencies. Now that we're
  839.   ;; storing the systems in a hash table, we've switched to using strings.
  840.   ;; Since the hash table is case sensitive, we use uppercase strings.
  841.   ;; (Names of modules and files may be symbols or strings.)
  842.   #|(if (keywordp name)
  843.       name
  844.       (intern (string-upcase (string name)) "KEYWORD"))|#
  845.   (if (stringp name) name (string-upcase (string name))))
  846.  
  847. (defvar *defined-systems* (make-hash-table :test #'equal)
  848.   "Hash table containing the definitions of all known systems.")
  849.  
  850. (defun get-system (name)
  851.   "Returns the definition of the system named NAME."
  852.   (gethash (canonicalize-system-name name) *defined-systems*))
  853.  
  854. (defsetf get-system (name) (value)
  855.   `(setf (gethash (canonicalize-system-name ,name) *defined-systems*) ,value))
  856.  
  857. (defun undefsystem (name)
  858.   "Removes the definition of the system named NAME."
  859.   (setf (get-system name) nil))
  860.  
  861. (defun defined-systems ()
  862.   "Returns a list of defined systems."
  863.   (let ((result nil))
  864.     (maphash #'(lambda (key value)
  865.          (declare (ignore key))
  866.          (push value result))
  867.          *defined-systems*)
  868.     result))
  869.  
  870. ;;; ********************************
  871. ;;; Directory Pathname Hacking *****
  872. ;;; ********************************
  873.  
  874. ;;; Unix example: An absolute directory starts with / while a 
  875. ;;; relative directory doesn't. A directory ends with /, while
  876. ;;; a file's pathname doesn't. This is important 'cause
  877. ;;; (pathname-directory "foo/bar") will return "foo" and not "foo/".
  878.  
  879. ;;; I haven't been able to test the fix to the problem with symbolics
  880. ;;; hosts. Essentially, append-directories seems to have been tacking
  881. ;;; the default host onto the front of the pathname (e.g., mk::source-pathname
  882. ;;; gets a "B:" on front) and this overrides the :host specified in the
  883. ;;; component. The value of :host should override that specified in
  884. ;;; the :source-pathname and the default file server. If this doesn't
  885. ;;; fix things, specifying the host in the root pathname "F:>root-dir>"
  886. ;;; may be a good workaround.
  887.  
  888. ;;; Need to verify that merging of pathnames where modules are located
  889. ;;; on different devices (in VMS-based VAXLisp) now works.
  890.  
  891. ;;; Merge-pathnames works for VMS systems. In VMS systems, the directory
  892. ;;; part is enclosed in square brackets, e.g.,
  893. ;;;     "[root.child.child_child]" or "[root.][child.][child_child]"
  894. ;;; To concatenate directories merge-pathnames works as follows:
  895. ;;;     (merge-pathnames "" "[root]")               ==> "[root]"
  896. ;;;     (merge-pathnames "[root.]" "[son]file.ext") ==> "[root.son]file.ext"
  897. ;;;     (merge-pathnames "[root.]file.ext" "[son]") ==> "[root.son]file.ext"
  898. ;;;     (merge-pathnames "[root]file.ext" "[son]")  ==> "[root]file.ext"
  899. ;;; Thus the problem with the #-VMS code was that it was merging x y into
  900. ;;; [[x]][y] instead of [x][y] or [x]y. 
  901.  
  902. ;;; Miscellaneous notes:
  903. ;;;   On GCLisp, the following are equivalent:
  904. ;;;       "\\root\\subdir\\BAZ"
  905. ;;;       "/root/subdir/BAZ"
  906. ;;;   On VAXLisp, the following are equivalent:
  907. ;;;       "[root.subdir]BAZ"
  908. ;;;       "[root.][subdir]BAZ"
  909. ;;; Use #+:vaxlisp for VAXLisp 3.0, #+(and vms dec common vax) for v2.2
  910.  
  911. (defun new-append-directories (absolute-dir relative-dir)
  912.   ;; Version of append-directories for CLtL2-compliant lisps. In particular,
  913.   ;; they must conform to section 23.1.3 "Structured Directories". We are
  914.   ;; willing to fix minor aberations in this function, but not major ones.
  915.   ;; Tested in Allegro CL 4.0 [SPARC], Allegro CL 3.1.12 [DEC 3100], 
  916.   ;; CMU CL old and new compilers, Lucid 3.0, Lucid 4.0.
  917.   (setf absolute-dir (or absolute-dir "")
  918.     relative-dir (or relative-dir ""))
  919.   (let* ((abs-dir (pathname absolute-dir))
  920.      (rel-dir (pathname relative-dir))
  921.      (host (pathname-host abs-dir))
  922.      (device (if (null-string absolute-dir) ; fix for CMU CL old compiler
  923.              (pathname-device rel-dir)
  924.            (pathname-device abs-dir)))
  925.      (abs-directory (coerce (pathname-directory abs-dir) 'list))
  926.      (abs-keyword (when (keywordp (car abs-directory))
  927.             (pop abs-directory)))
  928.      (abs-name (file-namestring abs-dir)) ; was pathname-name
  929.      (rel-directory (coerce (pathname-directory rel-dir) 'list))
  930.      (rel-keyword (when (keywordp (car rel-directory))
  931.             (pop rel-directory)))
  932.      (rel-file (file-namestring rel-dir))
  933.      (directory nil))
  934.     ;; Allegro v4.0 parses "/foo" into :directory '(:absolute :root)
  935.     ;; and filename "foo". The namestring of a pathname with 
  936.     ;; directory '(:absolute :root "foo") ignores everything after the
  937.     ;; :root.
  938.     #+:allegro-v4.0(when (eq (car abs-directory) :root) (pop abs-directory))
  939.     #+:allegro-v4.0(when (eq (car rel-directory) :root) (pop rel-directory))
  940.     (when (and abs-name (not (null-string abs-name))) ; was abs-name
  941.       (cond ((and (null abs-directory) (null abs-keyword))
  942.          #-:lucid (setf abs-keyword :relative)
  943.          (setf abs-directory (list abs-name)))
  944.         (t
  945.          (setf abs-directory (append abs-directory (list abs-name))))))
  946.     (when (and (null abs-directory) (null abs-keyword) rel-keyword)
  947.       (setf abs-keyword rel-keyword))
  948.     (setf directory (append abs-directory rel-directory))
  949.     (when abs-keyword (setf directory (cons abs-keyword directory)))
  950.     (namestring 
  951.      (make-pathname :host host
  952.             :device device
  953.             :directory #-:cmu directory
  954.                        #+:cmu (coerce directory 'simple-vector)
  955.             :name rel-file))))
  956.  
  957. (defvar *append-dirs-tests* 
  958.   '("~/foo/" "baz/bar.lisp"
  959.      "~/foo" "baz/bar.lisp"
  960.      "/foo/bar/" "baz/barf.lisp"
  961.      "/foo/bar/" "/baz/barf.lisp"
  962.      "foo/bar/" "baz/barf.lisp"
  963.      "foo/bar" "baz/barf.lisp"
  964.      "foo/bar" "/baz/barf.lisp"
  965.      "foo/bar/" "/baz/barf.lisp"
  966.      "/foo/bar/" nil
  967.      "foo/bar/" nil
  968.      "foo/bar" nil
  969.      nil "baz/barf.lisp"
  970.      nil nil))
  971.  
  972. (defun test-new-append-directories (&optional (test-dirs *append-dirs-tests*))
  973.   (do* ((dir-list test-dirs (cddr dir-list))
  974.     (abs-dir (car dir-list) (car dir-list))
  975.     (rel-dir (cadr dir-list) (cadr dir-list)))
  976.       ((null dir-list) (values))
  977.     (format t "~&ABS: ~S ~18TREL: ~S ~41TResult: ~S"
  978.         abs-dir rel-dir (new-append-directories abs-dir rel-dir))))
  979.  
  980. #|
  981. <cl> (test-new-append-directories) 
  982.  
  983. ABS: "~/foo/"     REL: "baz/bar.lisp"    Result: "/usr0/mkant/foo/baz/bar.lisp"
  984. ABS: "~/foo"      REL: "baz/bar.lisp"    Result: "/usr0/mkant/foo/baz/bar.lisp"
  985. ABS: "/foo/bar/"  REL: "baz/barf.lisp"   Result: "/foo/bar/baz/barf.lisp"
  986. ABS: "/foo/bar/"  REL: "/baz/barf.lisp"  Result: "/foo/bar/baz/barf.lisp"
  987. ABS: "foo/bar/"   REL: "baz/barf.lisp"   Result: "foo/bar/baz/barf.lisp"
  988. ABS: "foo/bar"    REL: "baz/barf.lisp"   Result: "foo/bar/baz/barf.lisp"
  989. ABS: "foo/bar"    REL: "/baz/barf.lisp"  Result: "foo/bar/baz/barf.lisp"
  990. ABS: "foo/bar/"   REL: "/baz/barf.lisp"  Result: "foo/bar/baz/barf.lisp"
  991. ABS: "/foo/bar/"  REL: NIL               Result: "/foo/bar/"
  992. ABS: "foo/bar/"   REL: NIL               Result: "foo/bar/"
  993. ABS: "foo/bar"    REL: NIL               Result: "foo/bar/"
  994. ABS: NIL          REL: "baz/barf.lisp"   Result: "baz/barf.lisp"
  995. ABS: NIL          REL: NIL               Result: ""
  996.  
  997. |#
  998.  
  999. (defun append-directories (absolute-directory relative-directory)
  1000.   "There is no CL primitive for tacking a subdirectory onto a directory.
  1001.    We need such a function because defsystem has both absolute and
  1002.    relative pathnames in the modules. This is a somewhat ugly hack which
  1003.    seems to work most of the time. We assume that ABSOLUTE-DIRECTORY
  1004.    is a directory, with no filename stuck on the end. Relative-directory,
  1005.    however, may have a filename stuck on the end."
  1006.   (when (or absolute-directory relative-directory)
  1007.     (cond 
  1008.      #+:logical-pathnames-mk
  1009.      ((eq (lp:pathname-host-type absolute-directory) :logical)
  1010.       ;; For use with logical pathnames package.
  1011.       (lp:append-logical-directories absolute-directory relative-directory))
  1012.      (t
  1013.       ;; In VMS, merge-pathnames actually does what we want!!!
  1014.       #+:VMS(namestring (merge-pathnames (or absolute-directory "")
  1015.                      (or relative-directory "")))
  1016.       ;; Cross your fingers and pray.
  1017.       #-:VMS
  1018.       (new-append-directories absolute-directory relative-directory)))))
  1019.  
  1020. #|
  1021. (defun append-directories (absolute-directory relative-directory)
  1022.   "There is no CL primitive for tacking a subdirectory onto a directory.
  1023.    We need such a function because defsystem has both absolute and
  1024.    relative pathnames in the modules. This is a very gross hack which
  1025.    seems to work most of the time. We assume that ABSOLUTE-DIRECTORY
  1026.    is a directory, with no filename stuck on the end. Relative-directory,
  1027.    however, may have a filename stuck on the end. We assume that 
  1028.    if we do a (make-pathname :directory abs-directory :name rel-directory)
  1029.    it will do what we want. The #+ and #-'s that appear before this
  1030.    form are used to massage abs-directory and rel-directory into a
  1031.    format acceptable to make-pathname in the particular lisp."
  1032.   (when (or absolute-directory relative-directory)
  1033.     (cond 
  1034.      #+:logical-pathnames-mk
  1035.      ((eq (pathname-host-type absolute-directory) :logical)
  1036.       ;; For use with logical pathnames package.
  1037.       (lp::append-logical-directories absolute-directory relative-directory))
  1038.      (t
  1039.       ;; Allegro CL barfs if abs-dir is "", so we replace it with NIL.
  1040.       #+:ExCL(when (and (stringp absolute-directory)
  1041.             (null-string absolute-directory))
  1042.            (setq absolute-directory nil))
  1043.       ;; CMU CL needs a / at the end of absolute directory, so we
  1044.       ;; coerce abs-dir to a namestring and then check the last character
  1045.       ;; of the namestring. An alternate method of doing this might
  1046.       ;; be to break the directory into components, cons :absolute or
  1047.       ;; :relative on the front, and hand that off to make-pathname.
  1048.       #+:CMU(when (pathnamep absolute-directory) 
  1049.           (setq absolute-directory (namestring absolute-directory)))
  1050.       #+:CMU(when (and absolute-directory 
  1051.                (not (null-string absolute-directory))
  1052.                (not (char= (char absolute-directory
  1053.                      (1- (length absolute-directory)))
  1054.                    #\/)))
  1055.           (setq absolute-directory 
  1056.             (concatenate 'string absolute-directory "/")))
  1057.       #+:CMU(when (pathnamep relative-directory) 
  1058.           (setq relative-directory (namestring relative-directory)))
  1059.       ;; In VMS, merge-pathnames actually does what we want!!!
  1060.       #+:VMS(namestring (merge-pathnames (or absolute-directory "")
  1061.                      (or relative-directory "")))
  1062.       ;; For Sun Common Lisp 4.0, which is the same as Lucid 4.0.
  1063.       ;; For this one, we need to break the string up into components,
  1064.       ;; and tack a :ROOT on the front.
  1065.       ;; The :lucid probably should be removed below for it to work properly
  1066.       ;; in Lucid 3.0.
  1067.       #+(or (and (not :excl) :SUN) :lcl4.0 :lucid)
  1068.       (namestring (make-pathname 
  1069.            :directory (cons :ROOT
  1070.                     (parse-slashed-pathname
  1071.                      (merge-pathnames absolute-directory)))
  1072.                  :name relative-directory))
  1073.       #|(namestring (make-pathname
  1074.            :directory (list :ROOT (or absolute-directory ""))
  1075.            :name relative-directory))|#
  1076.       ;; Cross your fingers and pray.
  1077.       #-(or :VMS (and (not :excl) :SUN) :lcl4.0 :lucid)
  1078.       (namestring (make-pathname :directory absolute-directory
  1079.                  #+:cmu :device #+:cmu :absolute
  1080.                  #+:symbolics :host #+:symbolics nil
  1081.                  :name relative-directory))))))
  1082.  
  1083. (defun parse-with-delimiter (line &optional (delim #\/))
  1084.   (let ((pos (position delim line)))
  1085.     (cond (pos
  1086.            (cons (subseq line 0 pos)
  1087.                  (parse-with-delimiter (subseq line (1+ pos)) delim)))
  1088.           (t
  1089.            (list line)))))
  1090.  
  1091. (defun parse-slashed-pathname (directory)
  1092.   "Parses strings like \"/usr/mkant/Public/\" into a list of
  1093.    the directory components: '(\"usr\" \"mkant\" \"Public\"),
  1094.    with null components (\"\") removed."
  1095.   (if directory
  1096.       (remove-if #'(lambda (string) (string-equal string ""))
  1097.          (parse-with-delimiter directory #\/))
  1098.       (list "")))
  1099. |#
  1100.  
  1101. #|
  1102. ;;; This was a try at appending a subdirectory onto a directory.
  1103. ;;; It failed. We're keeping this around to prevent future mistakes
  1104. ;;; of a similar sort.
  1105. (defun merge-directories (absolute-directory relative-directory)
  1106.   ;; replace concatenate with something more intelligent
  1107.   ;; i.e., concatenation won't work with some directories.
  1108.   ;; it should also behave well if the parent directory 
  1109.   ;; has a filename at the end, or if the relative-directory ain't relative
  1110.   (when absolute-directory 
  1111.     (setq absolute-directory (pathname-directory absolute-directory)))
  1112.   (concatenate 'string 
  1113.            (or absolute-directory "")
  1114.            (or relative-directory "")))
  1115. |#
  1116.  
  1117.  
  1118.  
  1119. #|
  1120. <cl> (defun d (d n) (namestring (make-pathname :directory d :name n)))
  1121.  
  1122. D
  1123. <cl> (d "~/foo/" "baz/bar.lisp")
  1124. "/usr0/mkant/foo/baz/bar.lisp" 
  1125.  
  1126. <cl> (d "~/foo" "baz/bar.lisp")
  1127. "/usr0/mkant/foo/baz/bar.lisp" 
  1128.  
  1129. <cl> (d "/foo/bar/" "baz/barf.lisp")
  1130. "/foo/bar/baz/barf.lisp"
  1131.  
  1132. <cl> (d "foo/bar/" "baz/barf.lisp")
  1133. "foo/bar/baz/barf.lisp"
  1134.  
  1135. <cl> (d "foo/bar" "baz/barf.lisp")
  1136. "foo/bar/baz/barf.lisp"
  1137.  
  1138. <cl> (d "foo/bar" "/baz/barf.lisp")
  1139. "foo/bar//baz/barf.lisp"
  1140.  
  1141. <cl> (d "foo/bar" nil)
  1142. "foo/bar/"
  1143.  
  1144. <cl> (d nil "baz/barf.lisp")
  1145. "baz/barf.lisp"
  1146.  
  1147. <cl> (d nil nil)
  1148. ""
  1149.  
  1150. |#
  1151.  
  1152.  
  1153. (defun namestring-or-nil (pathname)
  1154.   (when pathname
  1155.     (namestring pathname)))
  1156.  
  1157. (defun new-file-type (pathname type)
  1158.   (make-pathname
  1159.    :host (pathname-host pathname)
  1160.    :device (pathname-device pathname)
  1161.    :directory (pathname-directory pathname)
  1162.    :name (pathname-name pathname)
  1163.    :type type
  1164.    :version (pathname-version pathname)))
  1165.  
  1166.  
  1167.  
  1168. ;;; ********************************
  1169. ;;; Component Defstruct ************
  1170. ;;; ********************************
  1171. (defvar *source-pathname-default* nil
  1172.   "Default value of :source-pathname keyword in DEFSYSTEM. Set this to
  1173.    \"\" to avoid having to type :source-pathname \"\" all the time.")
  1174. (defvar *binary-pathname-default* nil
  1175.   "Default value of :binary-pathname keyword in DEFSYSTEM.")
  1176.  
  1177. (defstruct (topological-sort-node (:conc-name topsort-))
  1178.   color
  1179.   time)
  1180.  
  1181. (defstruct (component (:include topological-sort-node)
  1182.                       (:print-function print-component))
  1183.   type                ; :defsystem, :system, :subsystem, :module, :file, or :private-file
  1184.   name                ; a symbol or string
  1185.   indent              ; number of characters of indent in verbose output to the user.
  1186.   host                ; the pathname host (i.e., "/../a")
  1187.   device              ; the pathname device
  1188.   source-root-dir
  1189.   ;; relative or absolute (starts with "/"), directory or file (ends with "/")
  1190.   (source-pathname *source-pathname-default*)
  1191.   source-extension    ; a string, e.g., "lisp". If nil, uses default for machine-type
  1192.   (binary-pathname *binary-pathname-default*)
  1193.   binary-root-dir
  1194.   binary-extension    ; a string, e.g., "fasl". If nil, uses default for machine-type
  1195.   package             ; package for use-package
  1196.   components          ; a list of components comprising this component's definition
  1197.   depends-on          ; a list of the components this one depends on. may refer only
  1198.                       ; to the components at the same level as this one.
  1199.   initially-do        ; form to evaluate before the operation
  1200.   finally-do          ; form to evaluate after the operation
  1201.   compile-form        ; for foreign libraries
  1202.   load-form           ; for foreign libraries
  1203. ;  load-time           ; The file-write-date of the binary/source file loaded.
  1204.   ;; If load-only is T, will not compile the file on operation :compile.
  1205.   ;; In other words, for files which are :load-only T, loading the file
  1206.   ;; satisfies any demand to recompile.
  1207.   load-only           ; If T, will not compile this file on operation :compile.
  1208.   ;; If compile-only is T, will not load the file on operation :compile.
  1209.   ;; Either compiles or loads the file, but not both. In other words,
  1210.   ;; compiling the file satisfies the demand to load it. This is useful
  1211.   ;; for PCL defmethod and defclass definitions, which wrap a 
  1212.   ;; (eval-when (compile load eval) ...) around the body of the definition.
  1213.   ;; This saves time in some lisps.
  1214.   compile-only        ; If T, will not load this file on operation :compile.
  1215. )
  1216.  
  1217. (defvar *file-load-time-table* (make-hash-table :test #'equal)
  1218.   "Hash table of file-write-dates for the system definitions and 
  1219.    files in the system definitions.")
  1220. (defun component-load-time (component)
  1221.   (when component
  1222.     (etypecase component
  1223.       (string    (gethash component *file-load-time-table*))
  1224.       (pathname (gethash (namestring component) *file-load-time-table*))
  1225.       (component 
  1226.        (ecase (component-type component)
  1227.      (:defsystem
  1228.       (let ((name (component-name component))
  1229.         (path nil))
  1230.         (when (and name
  1231.                (setf path (compute-system-path name nil)))
  1232.           (gethash (namestring path) *file-load-time-table*))))
  1233.      ((:file :private-file)
  1234.       ;; Use only :source pathname to identify component's
  1235.       ;; load time.
  1236.       (let ((path (component-full-pathname component :source)))
  1237.         (when path
  1238.           (gethash (namestring path) *file-load-time-table*)))))))))
  1239. (defsetf component-load-time (component) (value)
  1240.   `(when ,component
  1241.     (etypecase ,component
  1242.       (string   (setf (gethash ,component *file-load-time-table*) ,value))
  1243.       (pathname (setf (gethash (namestring ,component) *file-load-time-table*)
  1244.               ,value))
  1245.       (component 
  1246.        (ecase (component-type ,component)
  1247.      (:defsystem
  1248.       (let ((name (component-name ,component))
  1249.         (path nil))
  1250.         (when (and name
  1251.                (setf path (compute-system-path name nil)))
  1252.           (setf (gethash (namestring path) *file-load-time-table*)
  1253.             ,value))))
  1254.      ((:file :private-file)
  1255.       ;; Use only :source pathname to identify file.
  1256.       (let ((path (component-full-pathname ,component :source)))
  1257.         (when path
  1258.           (setf (gethash (namestring path) *file-load-time-table*)
  1259.             ,value)))))))))
  1260.  
  1261. (defun compute-system-path (module-name definition-pname)
  1262.   (let* ((filename (format nil "~A.system" 
  1263.                (if (symbolp module-name)
  1264.                    (string-downcase (string module-name))
  1265.                    module-name))))
  1266.     (or (when definition-pname        ; given pathname for system def
  1267.       (probe-file definition-pname))
  1268.     (probe-file filename)        ; try current dir
  1269.     (when *central-registry*    ; central registry
  1270.       (if (listp *central-registry*)
  1271.           (dolist (registry *central-registry*)
  1272.         (let ((file (probe-file (append-directories registry
  1273.                                 filename))))
  1274.           (when file (return file))))
  1275.           (probe-file (append-directories *central-registry* filename)))) 
  1276.     )))
  1277.  
  1278. (defvar *reload-systems-from-disk* t
  1279.   "If T, always tries to reload newer system definitions from disk.
  1280.    Otherwise first tries to find the system definition in the current
  1281.    environment.")
  1282.  
  1283. (defun FIND-SYSTEM (system-name &optional (mode :ask) definition-pname)
  1284.   "Returns the system named SYSTEM-NAME. If not already loaded, loads it.
  1285.    This allows operate-on-system to work on non-loaded as well as
  1286.    loaded system definitions. DEFINITION-PNAME is the pathname for
  1287.    the system definition, if provided."
  1288.   (ecase mode
  1289.     (:ASK
  1290.      (or (get-system system-name)
  1291.      (when (y-or-n-p-wait 
  1292.         #\y 20
  1293.         "System ~A not loaded. Shall I try loading it? "
  1294.         system-name)
  1295.        (find-system system-name :load definition-pname))))
  1296.     (:ERROR
  1297.      (or (get-system system-name)
  1298.      (error "Can't find system named ~s." system-name)))
  1299.     (:LOAD-OR-NIL
  1300.      (let ((system (get-system system-name)))
  1301.        (or (unless *reload-systems-from-disk* system)
  1302.        (let ((path (compute-system-path system-name definition-pname)))
  1303.          (when (and path
  1304.             (or (null system)
  1305.                 (null (component-load-time path))
  1306.                 (< (component-load-time path)
  1307.                    (file-write-date path))))
  1308.            (load path)
  1309.            (setf system (get-system system-name))
  1310.            (when system
  1311.              (setf (component-load-time path)
  1312.                    (file-write-date path))))
  1313.          system)
  1314.        system)))
  1315.     (:LOAD
  1316.      (or (unless *reload-systems-from-disk* (get-system system-name))
  1317.      (or (find-system system-name :load-or-nil definition-pname)
  1318.          (error "Can't find system named ~s." system-name))))))
  1319.  
  1320. (defun print-component (component stream depth)
  1321.   (declare (ignore depth))
  1322.   (format stream "#<~:@(~A~): ~A>"
  1323.           (component-type component)
  1324.           (component-name component)))
  1325.  
  1326. (defun describe-system (name &optional (stream *standard-output*))
  1327.   "Prints a description of the system to the stream. If NAME is the
  1328.    name of a system, gets it and prints a description of the system.
  1329.    If NAME is a component, prints a description of the component."
  1330.   (let ((system (if (typep name 'component) name (find-system name :load))))
  1331.     (format stream "~&~A ~A: ~
  1332.                     ~@[~&   Host: ~A~]~
  1333.                     ~@[~&   Device: ~A~]~
  1334.                     ~@[~&   Package: ~A~]~
  1335.                     ~&   Source: ~@[~A~] ~@[~A~] ~@[~A~]~
  1336.                     ~&   Binary: ~@[~A~] ~@[~A~] ~@[~A~]~
  1337.                     ~@[~&   Depends On: ~A ~]~&   Components: ~{~15T~A~&~}"
  1338.         (component-type system)
  1339.         (component-name system)
  1340.         (component-host system)
  1341.         (component-device system)
  1342.         (component-package system)
  1343.         (component-root-dir system :source)
  1344.         (component-pathname system :source)
  1345.         (component-extension system :source)
  1346.         (component-root-dir system :binary)
  1347.         (component-pathname system :binary)
  1348.         (component-extension system :binary)
  1349.         (component-depends-on system)
  1350.         (component-components system))
  1351.     #|(when recursive
  1352.       (dolist (component (component-components system))
  1353.     (describe-system component stream recursive)))|#      
  1354.     system))
  1355.  
  1356. (defun canonicalize-component-name (component)
  1357.   ;; Within the component, the name is a string.
  1358.   (if (typep (component-name component) 'string)
  1359.       ;; Unnecessary to change it, so just return it, same case
  1360.       (component-name component)
  1361.     ;; Otherwise, make it a downcase string
  1362.     (setf (component-name component) 
  1363.       (string-downcase (string (component-name component))))))
  1364.  
  1365. (defun component-pathname (component type)
  1366.   (when component
  1367.     (case type
  1368.       (:source (component-source-pathname component))
  1369.       (:binary (component-binary-pathname component))
  1370.       (:error  (component-error-pathname component)))))
  1371. (defun component-error-pathname (component)
  1372.   (let ((binary (component-pathname component :binary)))
  1373.     (new-file-type binary *compile-error-file-type*)))
  1374. (defsetf component-pathname (component type) (value)
  1375.   `(when ,component
  1376.      (case ,type
  1377.        (:source (setf (component-source-pathname ,component) ,value))
  1378.        (:binary (setf (component-binary-pathname ,component) ,value)))))
  1379.  
  1380. (defun component-root-dir (component type)
  1381.   (when component
  1382.     (case type
  1383.       (:source (component-source-root-dir component))
  1384.       ((:binary :error) (component-binary-root-dir component))
  1385.       )))
  1386. (defsetf component-root-dir (component type) (value)
  1387.   `(when ,component
  1388.      (case ,type
  1389.        (:source (setf (component-source-root-dir ,component) ,value))
  1390.        (:binary (setf (component-binary-root-dir ,component) ,value)))))
  1391.  
  1392. (defvar *version-dir* nil
  1393.   "The version subdir. bound in oos.")
  1394. (defvar *version-replace* nil
  1395.   "The version replace. bound in oos.")
  1396. (defvar *version* nil
  1397.   "Default version")
  1398. (defun component-full-pathname (component type &optional (version *version*)
  1399.                       &aux version-dir replace)
  1400.   (when component
  1401.     ;; If the pathname-type is :binary and the root pathname is null,
  1402.     ;; distribute the binaries among the sources (= use :source pathname).
  1403.     ;; This assumes that the component's :source pathname has been set
  1404.     ;; before the :binary one.
  1405.     (if version
  1406.     (multiple-value-setq (version-dir replace) (translate-version version))
  1407.       (setq version-dir *version-dir* replace *version-replace*))
  1408.     (let ((pathname
  1409.        (append-directories 
  1410.         (if replace
  1411.         version-dir
  1412.           (append-directories (component-root-dir component type)
  1413.                   version-dir))
  1414.         (component-pathname component type))))
  1415.       ;; When a logical pathname is used, it must first be translated to
  1416.       ;; a physical pathname. This isn't strictly correct. What should happen
  1417.       ;; is we fill in the appropriate slots of the logical pathname, and
  1418.       ;; then return the logical pathname for use by compile-file & friends.
  1419.       ;; But calling translate-logical-pathname to return the actual pathname
  1420.       ;; should do for now.
  1421.       #+:logical-pathnames-mk
  1422.       (when (eq (lp:pathname-host-type pathname) :logical)
  1423.     ;;(setf (lp::%logical-pathname-type pathname)
  1424.     ;;      (component-extension component type))
  1425.     (setf pathname (lp:translate-logical-pathname pathname)))
  1426.  
  1427.       (make-pathname :name (pathname-name pathname)
  1428.              :type (component-extension component type)
  1429.              :host (when (component-host component)
  1430.                  ;; MCL2.0b1 causes an error on
  1431.                  ;; (pathname-host nil)
  1432.                  (pathname-host (component-host component)))
  1433.              :device #+CMU :absolute
  1434.              #-CMU (pathname-device (component-device component))
  1435.              ;; :version :newest
  1436.              ;; Use :directory instead of :defaults
  1437.              :directory (pathname-directory pathname)))))
  1438.  
  1439. (defun translate-version (version)
  1440.   ;; Value returns the version directory and whether it replaces 
  1441.   ;; the entire root (t) or is a subdirectory.
  1442.   ;; Version may be nil to signify no subdirectory,
  1443.   ;; a symbol, such as alpha, beta, omega, :alpha, mark, which
  1444.   ;; specifies a subdirectory of the root, or
  1445.   ;; a string, which replaces the root.
  1446.   (cond ((null version) 
  1447.      (values "" nil))
  1448.     ((symbolp version)
  1449.      (values (let ((sversion (string version)))
  1450.            (if (find-if #'lower-case-p sversion)
  1451.                sversion
  1452.                (string-downcase sversion))) 
  1453.          nil))
  1454.     ((stringp version)
  1455.      (values version t))
  1456.     (t (error "~&; Illegal version ~S" version))))
  1457.  
  1458. (defun component-extension (component type)
  1459.   (case type
  1460.     (:source (component-source-extension component))
  1461.     (:binary (component-binary-extension component))
  1462.     (:error  *compile-error-file-type*)))
  1463. (defsetf component-extension (component type) (value)
  1464.   `(case ,type
  1465.      (:source (setf (component-source-extension ,component) ,value))
  1466.      (:binary (setf (component-binary-extension ,component) ,value))
  1467.      (:error  (setf *compile-error-file-type* ,value))))
  1468.  
  1469. ;;; ********************************
  1470. ;;; System Definition **************
  1471. ;;; ********************************
  1472. (defmacro defsystem (name &rest definition-body)    
  1473.   `(create-component :defsystem ',name ',definition-body nil 0))
  1474.  
  1475. (defun create-component (type name definition-body &optional parent (indent 0))
  1476.   (let ((component (apply #'make-component :type type :name name :indent indent definition-body)))
  1477.     ;; Set up :load-only attribute
  1478.     (unless (find :load-only definition-body)
  1479.       ;; If the :load-only attribute wasn't specified, 
  1480.       ;; inherit it from the parent. If no parent, default it to nil.
  1481.       (setf (component-load-only component) 
  1482.         (when parent
  1483.           (component-load-only parent))))
  1484.     ;; Set up :compile-only attribute
  1485.     (unless (find :compile-only definition-body)
  1486.       ;; If the :compile-only attribute wasn't specified, 
  1487.       ;; inherit it from the parent. If no parent, default it to nil.
  1488.       (setf (component-compile-only component) 
  1489.         (when parent
  1490.           (component-compile-only parent))))
  1491.  
  1492.     ;; Initializations/after makes
  1493.     (canonicalize-component-name component)
  1494.  
  1495.     ;; Inherit package from parent if not specified.
  1496.     (setf (component-package component)
  1497.       (or (component-package component)
  1498.           (when parent (component-package parent))))
  1499.  
  1500.     ;; Type specific setup:
  1501.     (when (or (eq type :defsystem) (eq type :system) (eq type :subsystem))
  1502.       (setf (get-system name) component))
  1503.  
  1504.     ;; Set up the component's pathname
  1505.     (create-component-pathnames component parent)
  1506.  
  1507.     ;; If there are any components of the component, expand them too.
  1508.     (expand-component-components component (+ indent 2))
  1509.  
  1510.     ;; Make depends-on refer to structs instead of names.
  1511.     (link-component-depends-on (component-components component))
  1512.  
  1513.     ;; Design Decision: Topologically sort the dependency graph at
  1514.     ;; time of definition instead of at time of use. Probably saves a
  1515.     ;; little bit of time for the user.
  1516.  
  1517.     ;; Topological Sort the components at this level.
  1518.     (setf (component-components component)
  1519.           (topological-sort (component-components component)))
  1520.  
  1521.     ;; Return the component.
  1522.     component))
  1523.  
  1524. (defun create-component-pathnames (component parent)
  1525.   ;; Evaluate the root dir arg
  1526.   (setf (component-root-dir component :source)
  1527.     (eval (component-root-dir component :source)))
  1528.   (setf (component-root-dir component :binary)
  1529.     (eval (component-root-dir component :binary)))
  1530.   ;; Evaluate the pathname arg
  1531.   (setf (component-pathname component :source)
  1532.     (eval (component-pathname component :source)))
  1533.   (setf (component-pathname component :binary)
  1534.     (eval (component-pathname component :binary)))
  1535.   ;; Pass along the host and devices
  1536.   (setf (component-host component)
  1537.     (or (component-host component)
  1538.         (when parent (component-host parent))))
  1539.   (setf (component-device component)
  1540.     (or (component-device component)
  1541.         (when parent (component-device parent))))
  1542.   ;; Set up extension defaults
  1543.   (setf (component-extension component :source)
  1544.     (or (component-extension component :source) ; for local defaulting
  1545.         (when parent        ; parent's default
  1546.           (component-extension parent :source))
  1547.         (car *filename-extensions*))) ; system default
  1548.   (setf (component-extension component :binary)
  1549.     (or (component-extension component :binary) ; for local defaulting
  1550.         (when parent        ; parent's default
  1551.           (component-extension parent :binary))
  1552.         (cdr *filename-extensions*))) ; system default
  1553.   ;; Set up pathname defaults -- expand with parent
  1554.   ;; We must set up the source pathname before the binary pathname
  1555.   ;; to allow distribution of binaries among the sources to work.
  1556.   (generate-component-pathname component parent :source)
  1557.   (generate-component-pathname component parent :binary))
  1558.  
  1559. ;; maybe file's inheriting of pathnames should be moved elsewhere?
  1560. (defun generate-component-pathname (component parent pathname-type)
  1561.   ;; Pieces together a pathname for the component based on its component-type.
  1562.   ;; Assumes source defined first.
  1563.   ;; Null binary pathnames inherit from source instead of the component's
  1564.   ;; name. This allows binaries to be distributed among the source if
  1565.   ;; binary pathnames are not specified. Or if the root directory is
  1566.   ;; specified for binaries, but no module directories, it inherits
  1567.   ;; parallel directory structure.
  1568.   (case (component-type component)
  1569.     ((:defsystem :system)        ; Absolute Pathname
  1570.      ;; Set the root-dir to be the absolute pathname
  1571.      (setf (component-root-dir component pathname-type)
  1572.        (or (component-pathname component pathname-type)
  1573.            (when (eq pathname-type :binary)
  1574.          ;; When the binary root is nil, use source.
  1575.          (component-root-dir component :source))) )
  1576.      ;; Set the relative pathname to be nil
  1577.      (setf (component-pathname component pathname-type) 
  1578.        nil));; should this be "" instead?
  1579.     ;; If the name of the component-pathname is nil, it
  1580.     ;; defaults to the name of the component. Use "" to
  1581.     ;; avoid this defaulting.
  1582.     (:private-file                      ; Absolute Pathname
  1583.      ;; Root-dir is the directory part of the pathname
  1584.      (setf (component-root-dir component pathname-type)
  1585.        ""
  1586.        #+ignore(or (when (component-pathname component pathname-type)
  1587.              (pathname-directory 
  1588.               (component-pathname component pathname-type)))
  1589.                (when (eq pathname-type :binary)
  1590.              ;; When the binary root is nil, use source.
  1591.              (component-root-dir component :source)))
  1592.        )
  1593.      ;; The relative pathname is the name part
  1594.      (setf (component-pathname component pathname-type)
  1595.        (or (when (and (eq pathname-type :binary)
  1596.               (null (component-pathname component :binary)))
  1597.          ;; When the binary-pathname is nil use source.
  1598.          (component-pathname component :source))
  1599.            (or (when (component-pathname component pathname-type)
  1600. ;             (pathname-name )
  1601.              (component-pathname component pathname-type))
  1602.            (component-name component)))))
  1603.     ((:module :subsystem)            ; Pathname relative to parent.
  1604.      ;; Inherit root-dir from parent
  1605.      (setf (component-root-dir component pathname-type)
  1606.        (component-root-dir parent pathname-type))
  1607.      ;; Tack the relative-dir onto the pathname
  1608.      (setf (component-pathname component pathname-type)
  1609.        (or (when (and (eq pathname-type :binary)
  1610.               (null (component-pathname component :binary)))
  1611.          ;; When the binary-pathname is nil use source.
  1612.          (component-pathname component :source))
  1613.            (append-directories
  1614.         (component-pathname parent pathname-type)
  1615.         (or (component-pathname component pathname-type)
  1616.             (component-name component))))))
  1617.     (:file                ; Pathname relative to parent.
  1618.      ;; Inherit root-dir from parent
  1619.      (setf (component-root-dir component pathname-type)
  1620.        (component-root-dir parent pathname-type))
  1621.      ;; Tack the relative-dir onto the pathname
  1622.      (setf (component-pathname component pathname-type)
  1623.        (or (append-directories
  1624.         (component-pathname parent pathname-type)
  1625.         (or (component-pathname component pathname-type)
  1626.             (component-name component)
  1627.             (when (eq pathname-type :binary)
  1628.               ;; When the binary-pathname is nil use source.
  1629.               (component-pathname component :source)))))))
  1630.     ))       
  1631.  
  1632. (defun expand-component-components (component &optional (indent 0)) 
  1633.   (setf (component-components component)
  1634.     (remove-if #'null
  1635.        (mapcar #'(lambda (definition)
  1636.                (expand-component-definition definition
  1637.                             component indent))
  1638.            (component-components component)))))
  1639.  
  1640. (defun expand-component-definition (definition parent &optional (indent 0))
  1641.   ;; Should do some checking for malformed definitions here.
  1642.   (cond ((null definition) nil)
  1643.         ((stringp definition) 
  1644.          ;; Strings are assumed to be of type :file
  1645.          (create-component :file definition nil parent indent))
  1646.         ((and (listp definition)
  1647.               (not (member (car definition) 
  1648.                '(:defsystem :system :subsystem
  1649.                  :module :file :private-file))))
  1650.          ;; Lists whose first element is not a component type
  1651.          ;; are assumed to be of type :file
  1652.          (create-component :file (car definition) (cdr definition) parent indent))
  1653.         ((listp definition)
  1654.          ;; Otherwise, it is (we hope) a normal form definition
  1655.          (create-component (car definition)   ; type
  1656.                            (cadr definition)  ; name
  1657.                            (cddr definition)  ; definition body
  1658.                            parent             ; parent
  1659.                indent)            ; indent
  1660.          )))
  1661.  
  1662. (defun link-component-depends-on (components)
  1663.   (dolist (component components)
  1664.     (unless (and *system-dependencies-delayed*
  1665.                  (eq (component-type component) :defsystem))
  1666.       (setf (component-depends-on component)
  1667.             (mapcar #'(lambda (dependency)
  1668.             (let ((parent (find (string dependency) components
  1669.                         :key #'component-name 
  1670.                         :test #'string-equal)))
  1671.               (cond (parent parent)
  1672.                 ;; make it more intelligent about the following
  1673.                 (t (warn "Dependency ~S of component ~S not found."
  1674.                      dependency component)))))
  1675.                   
  1676.                     (component-depends-on component))))))
  1677.  
  1678. ;;; ********************************
  1679. ;;; Topological Sort the Graph *****
  1680. ;;; ********************************
  1681. (defun topological-sort (list &aux (time 0))
  1682.   ;; The algorithm works by calling depth-first-search to compute the
  1683.   ;; blackening times for each vertex, and then sorts the vertices into
  1684.   ;; reverse order by blackening time.
  1685.   (labels ((dfs-visit (node)
  1686.           (setf (topsort-color node) 'gray)
  1687.           (unless (and *system-dependencies-delayed*
  1688.                (eq (component-type node) :defsystem))
  1689.         (dolist (child (component-depends-on node))
  1690.           (cond ((eq (topsort-color child) 'white)
  1691.              (dfs-visit child))
  1692.             ((eq (topsort-color child) 'gray)
  1693.              (format t "~&Detected cycle containing ~A" child)))))
  1694.               (setf (topsort-color node) 'black)
  1695.               (setf (topsort-time node) time)
  1696.               (incf time)))
  1697.     (dolist (node list)
  1698.       (setf (topsort-color node) 'white))
  1699.     (dolist (node list)
  1700.       (when (eq (topsort-color node) 'white)
  1701.         (dfs-visit node)))
  1702.     (sort list #'< :key #'topsort-time)))
  1703.  
  1704. ;;; ********************************
  1705. ;;; Output to User *****************
  1706. ;;; ********************************
  1707. ;;; All output to the user is via the tell-user functions.
  1708.  
  1709. (defun split-string (string &key (item #\space) (test #'char=))
  1710.   ;; Splits the string into substrings at spaces.
  1711.   (let ((len (length string))
  1712.     (index 0) result)
  1713.     (dotimes (i len
  1714.         (progn (unless (= index len)
  1715.              (push (subseq string index) result))
  1716.                (reverse result)))
  1717.       (when (funcall test (char string i) item)
  1718.     (unless (= index i);; two spaces in a row
  1719.       (push (subseq string index i) result))
  1720.     (setf index (1+ i))))))
  1721.  
  1722. (defun prompt-string (component)
  1723.   (format nil "; ~:[~;TEST:~]~V,@T "
  1724.       *oos-test*
  1725.       (component-indent component)))
  1726.  
  1727. #|
  1728. (defun format-justified-string (prompt contents)
  1729.   (format t (concatenate 'string "~%" prompt "-~{~<~%" prompt " ~1,80:; ~A~>~^~}")
  1730.       (split-string contents))
  1731.   (finish-output *standard-output*))
  1732. |#
  1733.  
  1734. (defun format-justified-string (prompt contents &optional (width 80)
  1735.                        (stream *standard-output*))
  1736.   (let ((prompt-length (+ 2 (length prompt))))
  1737.     (cond ((< (+ prompt-length (length contents)) width)
  1738.        (format stream "~%~A- ~A" prompt contents))
  1739.       (t
  1740.        (format stream "~%~A-" prompt)
  1741.        (do* ((cursor prompt-length)
  1742.          (contents (split-string contents) (cdr contents))
  1743.          (content (car contents) (car contents))
  1744.          (content-length (1+ (length content)) (1+ (length content))))
  1745.            ((null contents))
  1746.          (cond ((< (+ cursor content-length) width)
  1747.             (incf cursor content-length)
  1748.             (format stream " ~A" content))
  1749.            (t
  1750.             (setf cursor (+ prompt-length content-length))
  1751.             (format stream "~%~A  ~A" prompt content)))))))
  1752.   (finish-output stream))
  1753.  
  1754. (defun tell-user (what component &optional type no-dots force)
  1755.   (when (or *oos-verbose* force)
  1756.     (format-justified-string (prompt-string component)
  1757.      (format nil "~A ~(~A~) ~@[\"~A\"~] ~:[~;...~]"
  1758.          ;; To have better messages, wrap the following around the
  1759.          ;; case statement:
  1760.          ;;(if (find (component-type component) 
  1761.          ;;    '(:defsystem :system :subsystem :module))
  1762.          ;;  "Checking"
  1763.          ;;  (case ...))
  1764.          ;; This gets around the problem of DEFSYSTEM reporting
  1765.          ;; that it's loading a module, when it eventually never
  1766.          ;; loads any of the files of the module.
  1767.          (case what 
  1768.            ((compile :compile) 
  1769.         (if (component-load-only component)
  1770.             ;; If it is :load-only t, we're loading.
  1771.             "Loading"
  1772.             ;; Otherwise we're compiling.
  1773.             "Compiling"))
  1774.            ((load :load) "Loading")
  1775.            (otherwise what))
  1776.          (component-type component)
  1777.          (or (when type
  1778.            (namestring-or-nil (component-full-pathname
  1779.                        component type)))
  1780.          (component-name component))
  1781.          (and *tell-user-when-done*
  1782.           (not no-dots))))))
  1783.  
  1784. (defun tell-user-done (component &optional force no-dots)
  1785.   ;; test is no longer really used, but we're leaving it in.
  1786.   (when (and *tell-user-when-done*
  1787.          (or *oos-verbose* force))
  1788.     (format t "~&~A~:[~;...~] Done."
  1789.         (prompt-string component) (not no-dots))
  1790.     (finish-output *standard-output*)))
  1791.  
  1792. (defmacro with-tell-user ((what component &optional type no-dots force) &body body)
  1793.   `(progn
  1794.      (tell-user ,what ,component ,type ,no-dots ,force)
  1795.      ,@body
  1796.      (tell-user-done ,component ,force ,no-dots)))
  1797.  
  1798. (defun tell-user-no-files (component &optional force)
  1799.   (when (or *oos-verbose* force)
  1800.     (format-justified-string (prompt-string component)
  1801.       (format nil "Source file ~A ~
  1802.              ~:[and binary file ~A ~;~]not found, not loading."
  1803.           (namestring (component-full-pathname component :source))
  1804.           (or *load-source-if-no-binary* *load-source-instead-of-binary*)
  1805.           (namestring (component-full-pathname component :binary))))))
  1806.  
  1807. (defun tell-user-require-system (name parent)
  1808.   (when *oos-verbose*
  1809.     (format t "~&; ~:[~;TEST:~] - System ~A requires ~S"
  1810.         *oos-test* (component-name parent) name)
  1811.     (finish-output *standard-output*)))
  1812.  
  1813. (defun tell-user-generic (string)
  1814.   (when *oos-verbose*
  1815.     (format t "~&; ~:[~;TEST:~] - ~A"
  1816.         *oos-test* string)
  1817.     (finish-output *standard-output*)))
  1818.  
  1819. ;;; ********************************
  1820. ;;; Y-OR-N-P-WAIT ******************
  1821. ;;; ********************************
  1822. ;;; y-or-n-p-wait is like y-or-n-p, but will timeout
  1823. ;;; after a specified number of seconds
  1824. (defun internal-real-time-in-seconds ()
  1825.   (float (/ (get-internal-real-time) 
  1826.         internal-time-units-per-second)))
  1827.  
  1828. (defun read-char-wait (&optional (timeout 20) input-stream &aux char)
  1829.   (do ((start (internal-real-time-in-seconds)))
  1830.       ((or (setq char (read-char-no-hang input-stream)) ;(listen *query-io*)
  1831.        (< (+ start timeout) (internal-real-time-in-seconds)))
  1832.        char)))
  1833.  
  1834. ;;; Lots of lisps, especially those that run on top of UNIX, do not get
  1835. ;;; their input one character at a time, but a whole line at a time because
  1836. ;;; of the buffering done by the UNIX system. This causes y-or-n-p-wait
  1837. ;;; to not always work as expected. 
  1838. ;;;
  1839. ;;; I wish lisp did all its own buffering (turning off UNIX input line
  1840. ;;; buffering by putting the UNIX into CBREAK mode). Of course, this means
  1841. ;;; that we lose input editing, but why can't the lisp implement this? 
  1842.  
  1843. (defvar *use-timeouts* t
  1844.   "If T, timeouts in Y-OR-N-P-WAIT are enabled. Otherwise it behaves
  1845.    like Y-OR-N-P. This is provided for users whose lisps don't handle
  1846.    read-char-no-hang properly.")
  1847.  
  1848. (defvar *clear-input-before-query* t
  1849.   "If T, y-or-n-p-wait will clear the input before printing the prompt
  1850.    and asking the user for input.")
  1851.  
  1852. (defun y-or-n-p-wait (&optional (default #\y) (timeout 20) 
  1853.                 format-string &rest args)
  1854.   "Y-OR-N-P-WAIT prints the message, if any, and reads characters from
  1855.    *QUERY-IO* until the user enters y, Y or space as an affirmative, or either
  1856.    n or N as a negative answer, or the timeout occurs. It asks again if
  1857.    you enter any other characters."
  1858.   (when *clear-input-before-query* (clear-input *query-io*))
  1859.   (when format-string
  1860.     (fresh-line *query-io*)
  1861.     (apply #'format *query-io* format-string args)
  1862.     ;; FINISH-OUTPUT needed for CMU and other places which don't handle
  1863.     ;; output streams nicely. This prevents it from continuing and
  1864.     ;; reading the query until the prompt has been printed.
  1865.     (finish-output *query-io*))
  1866.   (loop
  1867.    (let* ((read-char (if *use-timeouts*
  1868.              (read-char-wait timeout *query-io*)
  1869.              (read-char *query-io*)))
  1870.       (char (or read-char default)))
  1871.      ;; We need to ignore #\newline because otherwise the bugs in 
  1872.      ;; clear-input will cause y-or-n-p-wait to print the "Type ..."
  1873.      ;; message every time... *sigh*
  1874.      ;; Anyway, we might want to use this to ignore whitespace once
  1875.      ;; clear-input is fixed.
  1876.      (unless (find char '(#\tab #\newline #\return))
  1877.        (when (null read-char) 
  1878.      (format *query-io* "~@[~A~]" default)
  1879.      (finish-output *query-io*))
  1880.        (cond ((null char) (return t))
  1881.          ((find char '(#\y #\Y #\space) :test #'char=) (return t))
  1882.          ((find char '(#\n #\N) :test #'char=) (return nil))
  1883.          (t 
  1884.           (when *clear-input-before-query* (clear-input *query-io*))
  1885.           (format *query-io* "~&Type \"y\" for yes or \"n\" for no. ")
  1886.           (when format-string
  1887.         (fresh-line *query-io*)
  1888.         (apply #'format *query-io* format-string args))
  1889.           (finish-output *query-io*)))))))
  1890.  
  1891. #|
  1892. (y-or-n-p-wait #\y 20 "What? ")
  1893. (progn (format t "~&hi") (finish-output)
  1894.        (y-or-n-p-wait #\y 10 "1? ")
  1895.        (y-or-n-p-wait #\n 10 "2? "))
  1896. |#
  1897. ;;; ********************************
  1898. ;;; Operate on System **************
  1899. ;;; ********************************
  1900. ;;; Operate-on-system
  1901. ;; Operation is :compile, 'compile, :load or 'load
  1902. ;; Force is :all or :new-source or :new-source-and-dependents or a list of
  1903. ;; specific modules.
  1904. ;;    :all (or T) forces a recompilation of every file in the system
  1905. ;;    :new-source-and-dependents compiles only those files whose
  1906. ;;          sources have changed or who depend on recompiled files.
  1907. ;;    :new-source compiles only those files whose sources have changed
  1908. ;;    A list of modules means that only those modules and their dependents are recompiled.
  1909. ;; Test is T to print out what it would do without actually doing it. 
  1910. ;;      Note: it automatically sets verbose to T if test is T.
  1911. ;; Verbose is T to print out what it is doing (compiling, loading of
  1912. ;;      modules and files) as it does it.
  1913. ;; Dribble should be the pathname of the dribble file if you want to 
  1914. ;; dribble the compilation.
  1915. ;; Load-source-instead-of-binary is T to load .lisp instead of binary files.
  1916. ;; Version may be nil to signify no subdirectory,
  1917. ;; a symbol, such as alpha, beta, omega, :alpha, mark, which
  1918. ;; specifies a subdirectory of the root, or
  1919. ;; a string, which replaces the root.
  1920. ;;
  1921. (defun operate-on-system (name operation &key force
  1922.                    (version *version*)
  1923.                    (test *oos-test*) (verbose *oos-verbose*)
  1924.                                (load-source-instead-of-binary *load-source-instead-of-binary*)
  1925.                                (load-source-if-no-binary *load-source-if-no-binary*) 
  1926.                    (bother-user-if-no-binary *bother-user-if-no-binary*)
  1927.                    (compile-during-load *compile-during-load*)
  1928.                    dribble
  1929.                    (minimal-load *minimal-load*))
  1930.   (unwind-protect
  1931.       ;; Protect the undribble.
  1932.       (progn
  1933.     (when dribble (dribble dribble))
  1934.     (when test (setq verbose t))
  1935.     (when (null force);; defaults
  1936.       (case operation
  1937.         ((load :load) (setq force :all))
  1938.         ((compile :compile) (setq force :new-source-and-dependents))
  1939.         (t (setq force :all))))
  1940.     ;; Some CL implementations have a variable called *compile-verbose*
  1941.     ;; or *compile-file-verbose*.
  1942.     (multiple-value-bind (*version-dir* *version-replace*) 
  1943.         (translate-version version)
  1944.       ;; CL implementations may uniformly default this to nil
  1945.       (let ((*load-verbose* t) ; nil
  1946.         (*compile-file-verbose* t) ; nil
  1947.         (*compile-verbose* t) ; nil
  1948.         (*version* version)
  1949.         (*oos-verbose* verbose)
  1950.         (*oos-test* test)
  1951.         (*load-source-if-no-binary* load-source-if-no-binary)
  1952.         (*compile-during-load* compile-during-load)
  1953.         (*bother-user-if-no-binary* bother-user-if-no-binary)
  1954.         (*load-source-instead-of-binary* load-source-instead-of-binary)
  1955.         (*minimal-load* minimal-load)
  1956.         (system (find-system name :load)))
  1957.         (unless (component-operation operation)
  1958.           (error "Operation ~A undefined." operation))
  1959.         (operate-on-component system operation force))))
  1960.     (when dribble (dribble))))
  1961.  
  1962. (defun COMPILE-SYSTEM (name &key force
  1963.                 (version *version*)
  1964.                 (test *oos-test*) (verbose *oos-verbose*)
  1965.                 (load-source-instead-of-binary *load-source-instead-of-binary*)
  1966.                 (load-source-if-no-binary *load-source-if-no-binary*) 
  1967.                 (bother-user-if-no-binary *bother-user-if-no-binary*)
  1968.                 (compile-during-load *compile-during-load*)
  1969.                 dribble
  1970.                 (minimal-load *minimal-load*))
  1971.   ;; For users who are confused by OOS.
  1972.   (operate-on-system 
  1973.    name :compile
  1974.    :force force
  1975.    :version version
  1976.    :test test
  1977.    :verbose verbose
  1978.    :load-source-instead-of-binary load-source-instead-of-binary
  1979.    :load-source-if-no-binary load-source-if-no-binary
  1980.    :bother-user-if-no-binary bother-user-if-no-binary
  1981.    :compile-during-load compile-during-load
  1982.    :dribble dribble
  1983.    :minimal-load minimal-load))
  1984.  
  1985. (defun LOAD-SYSTEM (name &key force
  1986.              (version *version*)
  1987.              (test *oos-test*) (verbose *oos-verbose*)
  1988.              (load-source-instead-of-binary *load-source-instead-of-binary*)
  1989.              (load-source-if-no-binary *load-source-if-no-binary*) 
  1990.              (bother-user-if-no-binary *bother-user-if-no-binary*)
  1991.              (compile-during-load *compile-during-load*)
  1992.              dribble
  1993.              (minimal-load *minimal-load*))
  1994.   ;; For users who are confused by OOS.
  1995.   (operate-on-system 
  1996.    name :load
  1997.    :force force
  1998.    :version version
  1999.    :test test
  2000.    :verbose verbose
  2001.    :load-source-instead-of-binary load-source-instead-of-binary
  2002.    :load-source-if-no-binary load-source-if-no-binary
  2003.    :bother-user-if-no-binary bother-user-if-no-binary
  2004.    :compile-during-load compile-during-load
  2005.    :dribble dribble
  2006.    :minimal-load minimal-load))
  2007.  
  2008. (defun operate-on-component (component operation force &aux changed)
  2009.   ;; Returns T if something changed and had to be compiled.
  2010.   (let ((type (component-type component))
  2011.     (old-package (package-name *package*)))
  2012.  
  2013.     (unwind-protect
  2014.     ;; Protect old-package.
  2015.     (progn
  2016.       ;; Use the correct package.
  2017.       (when (component-package component)
  2018.         (tell-user-generic (format nil "Using package ~A" 
  2019.                        (component-package component)))
  2020.         (unless *oos-test*
  2021.           (unless (find-package (component-package component))
  2022.         ;; If the package name is the same as the name of the system,
  2023.         ;; and the package is not defined, this would lead to an
  2024.         ;; infinite loop, so bomb out with an error.
  2025.         (when (string-equal (string (component-package component)) 
  2026.                     (component-name component))
  2027.           (format t "~%Component ~A not loaded:~%"
  2028.               (component-name component))
  2029.           (error  "  Package ~A is not defined"
  2030.               (component-package component)))
  2031.         ;; If package not found, try using REQUIRE to load it.
  2032.         (new-require (component-package component)))
  2033.           ;; This was USE-PACKAGE, but should be IN-PACKAGE.
  2034.           ;; Actually, CLtL2 lisps define in-package as a macro,
  2035.           ;; so we'll set the package manually.
  2036.           ;; (in-package (component-package component))
  2037.           (let ((package (find-package (component-package component))))
  2038.         (when package
  2039.           (setf *package* package)))))
  2040.  
  2041.       ;; Load any required systems
  2042.       (when (eq type :defsystem)    ; maybe :system too?
  2043.         (operate-on-system-dependencies component operation force))
  2044.  
  2045.       ;; Do any initial actions
  2046.       (when (component-initially-do component)
  2047.         (tell-user-generic (format nil "Doing initializations for ~A"
  2048.                        (component-name component)))
  2049.         (or *oos-test*
  2050.         (eval (component-initially-do component))))
  2051.  
  2052.       ;; If operation is :compile and load-only is T, this would change
  2053.       ;; the operation to load. Only, this would mean that a module would
  2054.       ;; be considered to have changed if it was :load-only and had to be
  2055.       ;; loaded, and then dependents would be recompiled -- this doesn't
  2056.       ;; seem right. So instead, we propagate the :load-only attribute
  2057.       ;; to the components, and modify compile-file-operation so that
  2058.       ;; it won't compile the files (and modify tell-user to say "Loading"
  2059.       ;; instead of "Compiling" for load-only modules). 
  2060.       #|(when (and (find operation '(:compile compile))
  2061.            (component-load-only component))
  2062.       (setf operation :load))|#
  2063.  
  2064.       ;; Do operation and set changed flag if necessary.
  2065.       (setq changed 
  2066.         (case type
  2067.           ((:file :private-file)
  2068.            (funcall (component-operation operation) component force))
  2069.           ((:module :system :subsystem :defsystem)
  2070.            (operate-on-components component operation force changed))))
  2071.  
  2072.       ;; Do any final actions
  2073.       (when (component-finally-do component)
  2074.         (tell-user-generic (format nil "Doing finalizations for ~A"
  2075.                        (component-name component)))
  2076.         (or *oos-test*
  2077.         (eval (component-finally-do component)))))
  2078.  
  2079.       ;; Reset the package. (Cleanup form of unwind-protect.)
  2080.       ;;(in-package old-package)
  2081.       (setf *package* (find-package old-package)))
  2082.  
  2083.     ;; Provide the loaded system
  2084.     (when (or (eq type :defsystem) (eq type :system) (eq type :subsystem))
  2085.       (tell-user-generic (format nil "Providing system ~A"
  2086.                  (component-name component)))
  2087.       (or *oos-test*
  2088.       (provide (canonicalize-system-name (component-name component))))))
  2089.  
  2090.   ;; Return t if something changed in this component and hence had to be recompiled.
  2091.   changed)
  2092.  
  2093. (defvar *force* nil)
  2094. (defvar *providing-blocks-load-propagation* t
  2095.   "If T, if a system dependency exists on *modules*, it is not loaded.")
  2096. (defun operate-on-system-dependencies (component operation &optional force)
  2097.   (when *system-dependencies-delayed*
  2098.     (let ((*force* force))
  2099.       (dolist (system (component-depends-on component))
  2100.     ;; For each system that this system depends on, if it is a
  2101.     ;; defined system (either via defsystem or component type :system),
  2102.     ;; and propagation is turned on, propagates the operation to the
  2103.     ;; subsystem. Otherwise runs require (my version) on that system
  2104.     ;; to load it (needed since we may be depending on a lisp
  2105.     ;; dependent package).
  2106.     ;; Explores the system tree in a DFS manner.
  2107.     (cond ((and *operations-propagate-to-subsystems*
  2108.             (not (listp system))
  2109.             ;; The subsystem is a defined system.
  2110.             (find-system system :load-or-nil))
  2111.            ;; Call OOS on it. Since *system-dependencies-delayed* is
  2112.            ;; T, the :depends-on slot is filled with the names of
  2113.            ;; systems, not defstructs.
  2114.            ;; Aside from system, operation, force, for everything else
  2115.            ;; we rely on the globals.
  2116.            (unless (and *providing-blocks-load-propagation*
  2117.                 ;; If *providing-blocks-load-propagation* is T,
  2118.                 ;; the system dependency must not exist in the
  2119.                 ;; *modules* for it to be loaded. Note that
  2120.                 ;; the dependencies are implicitly systems.
  2121.                 (find operation '(load :load))    
  2122.                 ;; (or (eq force :all) (eq force t))
  2123.                 (find (canonicalize-system-name system)
  2124.                   *modules* :test #'string=))
  2125.          (operate-on-system system operation :force force)))
  2126.           ((listp system)
  2127.            (tell-user-require-system 
  2128.         (cond ((and (null (car system)) (null (cadr system)))
  2129.                (caddr system))
  2130.               (t system))
  2131.         component)
  2132.            (or *oos-test* (new-require (car system) nil
  2133.                        (eval (cadr system))
  2134.                        (caddr system) 
  2135.                        (or (car (cdddr system))
  2136.                            *version*))))
  2137.           (t
  2138.            (tell-user-require-system system component)
  2139.            (or *oos-test* (new-require system))))))))
  2140.  
  2141. (defun operate-on-components (component operation force changed)
  2142.   (with-tell-user (operation component)
  2143.     (if (component-components component)
  2144.     (dolist (module (component-components component))
  2145.       (when (operate-on-component module operation
  2146.           (cond ((and (dolist (dependent (component-depends-on module))
  2147.                 (when (member dependent changed)
  2148.                   (return t)))
  2149.                   #|(some #'(lambda (dependent)
  2150.                     (member dependent changed))
  2151.                     (component-depends-on module))|#
  2152.                   (or (non-empty-listp force)
  2153.                   (eq force :new-source-and-dependents)))
  2154.              ;; The component depends on a changed file 
  2155.              ;; and force agrees.
  2156.              (if (eq force :new-source-and-dependents)
  2157.                  :new-source-all
  2158.                :all))
  2159.             ((and (non-empty-listp force)
  2160.                   (member (component-name module) force
  2161.                       :test #'string-equal :key #'string))
  2162.              ;; Force is a list of modules 
  2163.              ;; and the component is one of them.
  2164.              :all)
  2165.             (t force)))
  2166.         (push module changed)))
  2167.     (case operation
  2168.       ((compile :compile)
  2169.        (eval (component-compile-form component)))
  2170.       ((load :load)
  2171.        (eval (component-load-form component))))))
  2172.   changed)
  2173.  
  2174. ;;; ********************************
  2175. ;;; New Require ********************
  2176. ;;; ********************************
  2177. (defvar *old-require* nil)
  2178.  
  2179. ;;; All calls to require in this file have been replaced with calls
  2180. ;;; to new-require to avoid compiler warnings and make this less of
  2181. ;;; a tangled mess.
  2182. (defun new-require (module-name &optional pathname definition-pname
  2183.                 default-action (version *version*))
  2184.   ;; If the pathname is present, this behaves like the old require.
  2185.   (unless (and module-name 
  2186.            (find #-CMU (string module-name)
  2187.              #+CMU (string-downcase (string module-name))
  2188.              *modules* :test #'string=)) 
  2189.     (cond (pathname
  2190.        (funcall *old-require* module-name pathname))
  2191.       ;; If the system is defined, load it.
  2192.       ((find-system module-name :load-or-nil definition-pname)
  2193.        (operate-on-system module-name :load
  2194.          :force *force*
  2195.          :version version
  2196.          :test *oos-test*
  2197.          :verbose *oos-verbose*
  2198.          :load-source-if-no-binary *load-source-if-no-binary*
  2199.          :bother-user-if-no-binary *bother-user-if-no-binary*
  2200.          :compile-during-load *compile-during-load*
  2201.          :load-source-instead-of-binary *load-source-instead-of-binary*
  2202.          :minimal-load *minimal-load*))
  2203.       ;; If there's a default action, do it. This could be a progn which
  2204.       ;; loads a file that does everything. 
  2205.       ((and default-action
  2206.         (eval default-action)))
  2207.       ;; If no system definition file, try regular require.
  2208.       ;; had last arg  PATHNAME, but this wasn't really necessary.
  2209.       ((funcall *old-require* module-name)) 
  2210.       ;; If no default action, print a warning or error message.
  2211.       (t
  2212.        (format t "~&Warning: System ~A doesn't seem to be defined..." 
  2213.            module-name)))))
  2214.  
  2215. ;;; Note that in some lisps, when the compiler sees a REQUIRE form at
  2216. ;;; top level it immediately executes it. This is as if an 
  2217. ;;; (eval-when (compile load eval) ...) were wrapped around the REQUIRE
  2218. ;;; form. I don't see any easy way to do this without making REQUIRE
  2219. ;;; a macro. 
  2220. ;;;
  2221. ;;; For example, in VAXLisp, if a (require 'streams) form is at the top of
  2222. ;;; a file in the system, compiling the system doesn't wind up loading the
  2223. ;;; streams module. If the (require 'streams) form is included within an
  2224. ;;; (eval-when (compile load eval) ...) then everything is OK.
  2225. ;;;
  2226. ;;; So perhaps we should replace the redefinition of lisp:require
  2227. ;;; with the following macro definition:
  2228. #|
  2229. (unless *old-require*
  2230.   (setf *old-require* 
  2231.     (symbol-function #-(and :excl :allegro-v4.0) 'lisp:require
  2232.              #+(and :excl :allegro-v4.0) 'cltl1:require))
  2233.  
  2234.   (let (#+:CCL (ccl:*warn-if-redefine-kernel* nil))
  2235.     ;; Note that lots of lisps barf if we redefine a function from
  2236.     ;; the LISP package. So what we do is define a macro with an
  2237.     ;; unused name, and use (setf macro-function) to redefine 
  2238.     ;; lisp:require without compiler warnings. If the lisp doesn't
  2239.     ;; do the right thing, try just replacing require-as-macro 
  2240.     ;; with lisp:require.
  2241.     (defmacro require-as-macro (module-name 
  2242.                 &optional pathname definition-pname
  2243.                 default-action (version '*version*))
  2244.       `(eval-when (compile load eval)
  2245.      (new-require ,module-name ,pathname ,definition-pname 
  2246.               ,default-action ,version)))
  2247.     (setf (macro-function #-(and :excl :allegro-v4.0) 'lisp:require
  2248.               #+(and :excl :allegro-v4.0) 'cltl1:require)
  2249.       (macro-function 'require-as-macro))))
  2250. |#
  2251. ;;; This will almost certainly fix the problem, but will cause problems
  2252. ;;; if anybody does a funcall on #'require.
  2253.  
  2254. ;;; Redefine old require to call the new require.
  2255. (unless *old-require*
  2256.   (setf *old-require* 
  2257.     (symbol-function #-(or (and :excl :allegro-v4.0) :mcl) 'lisp:require
  2258.              #+(and :excl :allegro-v4.0) 'cltl1:require
  2259.              #+:mcl 'ccl:require))
  2260.  
  2261.   (unless *dont-redefine-require*
  2262.     (let (#+:CCL (ccl:*warn-if-redefine-kernel* nil))
  2263.       (setf (symbol-function 
  2264.          #-(or (and :excl :allegro-v4.0) :mcl) 'lisp:require
  2265.          #+(and :excl :allegro-v4.0) 'cltl1:require
  2266.          #+:mcl 'ccl:require)
  2267.         (symbol-function 'new-require)))))
  2268.  
  2269.  
  2270. ;;; ********************************
  2271. ;;; Component Operations ***********
  2272. ;;; ********************************
  2273. ;;; Define :compile/compile and :load/load operations
  2274. (component-operation :compile  'compile-and-load-operation)
  2275. (component-operation 'compile  'compile-and-load-operation)
  2276. (component-operation :load     'load-file-operation)
  2277. (component-operation 'load     'load-file-operation)
  2278.  
  2279. (defun compile-and-load-operation (component force)
  2280.   ;; FORCE was CHANGED. this caused defsystem during compilation to only
  2281.   ;; load files that it immediately compiled.
  2282.   (let ((changed (compile-file-operation component force)))
  2283.     ;; Return T if the file had to be recompiled and reloaded.
  2284.     (if (and changed (component-compile-only component))
  2285.     ;; For files which are :compile-only T, compiling the file
  2286.     ;; satisfies the need to load. 
  2287.     changed
  2288.     ;; If the file wasn't compiled, or :compile-only is nil,
  2289.     ;; check to see if it needs to be loaded.
  2290.     (and (load-file-operation component force) ; FORCE was CHANGED ???
  2291.          changed))))
  2292.  
  2293. (defun compile-file-operation (component force)
  2294.   ;; Returns T if the file had to be compiled.
  2295.   (let ((must-compile
  2296.      ;; For files which are :load-only T, loading the file
  2297.      ;; satisfies the demand to recompile.
  2298.      (and (null (component-load-only component)) ; not load-only
  2299.           (or (find force '(:all :new-source-all t) :test #'eq) 
  2300.           (and (find force '(:new-source :new-source-and-dependents)
  2301.                  :test #'eq)
  2302.                (needs-compilation component))))))
  2303.  
  2304.     (cond ((and must-compile
  2305.         (probe-file (component-full-pathname component :source)))
  2306.        (with-tell-user ("Compiling source" component :source)
  2307.          (or *oos-test*
  2308.          (compile-file (component-full-pathname component :source)
  2309.                    :output-file (component-full-pathname component :binary)
  2310.                    #+CMU :error-file #+CMU (and *cmu-errors-to-file* 
  2311.                                 (component-full-pathname component :error))
  2312.                    #+(and CMU (not :new-compiler))
  2313.                    :errors-to-terminal
  2314.                    #+(and CMU (not :new-compiler))
  2315.                    *cmu-errors-to-terminal*
  2316.                    )))
  2317.        must-compile)
  2318.       (must-compile
  2319.        (tell-user "Source file not found. Not compiling"
  2320.               component :source :no-dots :force)
  2321.        nil)
  2322.       (t nil))))
  2323.  
  2324. (defun needs-compilation (component)
  2325.   ;; If there is no binary, or it is older than the source
  2326.   ;; file, then the component needs to be compiled.
  2327.   ;; Otherwise we only need to recompile if it depends on a file that changed.
  2328.   (and 
  2329.    ;; source must exist
  2330.    (probe-file (component-full-pathname component :source)) 
  2331.    (or
  2332.     ;; no binary
  2333.     (null (probe-file (component-full-pathname component :binary))) 
  2334.     ;; old binary
  2335.     (< (file-write-date (component-full-pathname component :binary)) 
  2336.        (file-write-date (component-full-pathname component :source))))))
  2337.  
  2338. (defun needs-loading (component &optional (check-source t) (check-binary t))
  2339.   ;; Compares the component's load-time against the file-write-date of
  2340.   ;; the files on disk. 
  2341.   (let ((load-time (component-load-time component)))
  2342.     (or 
  2343.      ;; File never loaded.
  2344.      (null load-time)
  2345.      ;; Binary is newer.
  2346.      (when (and check-binary
  2347.         (probe-file (component-full-pathname component :binary)))
  2348.        (< load-time
  2349.       (file-write-date (component-full-pathname component :binary))))
  2350.      ;; Source is newer.
  2351.      (when (and check-source
  2352.         (probe-file (component-full-pathname component :source)))
  2353.        (< load-time
  2354.       (file-write-date (component-full-pathname component :source)))))))
  2355.  
  2356. ;;; Need to completely rework this function...
  2357. (defun load-file-operation (component force)
  2358.   ;; Returns T if the file had to be loaded
  2359.   (let* ((binary-pname (component-full-pathname component :binary))
  2360.      (source-pname (component-full-pathname component :source))
  2361.      (binary-exists (probe-file binary-pname))
  2362.      (source-exists (probe-file source-pname))
  2363.      (source-needs-loading (needs-loading component t nil))
  2364.      (binary-needs-loading (needs-loading component nil t))
  2365.      ;; needs-compilation has an implicit source-exists in it.
  2366.      (needs-compilation (if (component-load-only component)
  2367.                 source-needs-loading
  2368.                 (needs-compilation component)))
  2369.      (check-for-new-source 
  2370.       ;; If force is :new-source*, we're checking for files
  2371.       ;; whose source is newer than the compiled versions.
  2372.       (find force '(:new-source :new-source-and-dependents :new-source-all)
  2373.         :test #'eq))
  2374.      (load-binary (or (find force '(:all :new-source-all t) :test #'eq)
  2375.               binary-needs-loading))
  2376.      (load-source
  2377.       (or *load-source-instead-of-binary*
  2378.           (and load-binary (component-load-only component))
  2379.           (and check-for-new-source needs-compilation)))
  2380.      (compile-and-load
  2381.       (and needs-compilation (or load-binary check-for-new-source)
  2382.            (compile-and-load-source-if-no-binary component))))
  2383.     ;; When we're trying to minimize the files loaded to only those
  2384.     ;; that need be, restrict the values of load-source and load-binary
  2385.     ;; so that we only load the component if the files are newer than
  2386.     ;; the load-time.
  2387.     (when *minimal-load*
  2388.       (when load-source (setf load-source source-needs-loading))
  2389.       (when load-binary (setf load-binary binary-needs-loading)))
  2390.  
  2391.     (when (or load-source load-binary compile-and-load)
  2392.       (cond (compile-and-load
  2393.          ;; If we're loading the binary and it is old or nonexistent,
  2394.          ;; and the user says yes, compile and load the source.
  2395.          (compile-file-operation component t)
  2396.          (with-tell-user ("Loading binary"   component :binary)
  2397.            (or *oos-test*
  2398.            (progn
  2399.              (load binary-pname)
  2400.              (setf (component-load-time component)
  2401.                (file-write-date binary-pname)))))
  2402.          T)
  2403.         ((and source-exists
  2404.           (or (and load-source    ; implicit needs-comp...
  2405.                (or *load-source-instead-of-binary*
  2406.                    (component-load-only component)
  2407.                    (not *compile-during-load*)))
  2408.               (and load-binary (not binary-exists)
  2409.                (load-source-if-no-binary component))))
  2410.          ;; Load the source if the source exists and:
  2411.          ;;   o  we're loading binary and it doesn't exist
  2412.          ;;   o  we're forcing it
  2413.          ;;   o  we're loading new source and user wasn't asked to compile
  2414.          (with-tell-user ("Loading source" component :source)
  2415.            (or *oos-test*
  2416.            (progn 
  2417.              (load source-pname)
  2418.              (setf (component-load-time component)
  2419.                (file-write-date source-pname)))))
  2420.          T)
  2421.         ((and binary-exists load-binary)
  2422.          (with-tell-user ("Loading binary"   component :binary)
  2423.            (or *oos-test*
  2424.            (progn
  2425.              (load binary-pname)
  2426.              (setf (component-load-time component)
  2427.                (file-write-date binary-pname)))))
  2428.          T)
  2429.         ((and (not binary-exists) (not source-exists))
  2430.          (tell-user-no-files component :force)
  2431.          (when *files-missing-is-an-error*
  2432.            (cerror "Continue, ignoring missing files."
  2433.                "~&Source file ~S ~:[and binary file ~S ~;~]do not exist."
  2434.                (namestring source-pname)
  2435.                (or *load-source-if-no-binary* 
  2436.                *load-source-instead-of-binary*)
  2437.                (namestring binary-pname)))
  2438.          nil)
  2439.         (t 
  2440.          nil)))))
  2441.  
  2442. (component-operation :delete-binaries     'delete-binaries-operation)
  2443. (defun delete-binaries-operation (component force)
  2444.   (when (or (eq force :all)
  2445.         (eq force t)
  2446.         (and (find force '(:new-source :new-source-and-dependents
  2447.                        :new-source-all)
  2448.                :test #'eq)
  2449.          (needs-compilation component)))
  2450.     (when (probe-file (component-full-pathname component :binary))
  2451.       (with-tell-user ("Deleting binary"   component :binary)
  2452.     (or *oos-test*
  2453.         (delete-file (component-full-pathname component :binary)))))))
  2454.  
  2455.     
  2456. ;; when the operation = :compile, we can assume the binary exists in test mode.
  2457. ;;    ((and *oos-test*
  2458. ;;          (eq operation :compile)
  2459. ;;          (probe-file (component-full-pathname component :source)))
  2460. ;;     (with-tell-user ("Loading binary"   component :binary)))
  2461.  
  2462. ;;; or old-binary
  2463. (defun compile-and-load-source-if-no-binary (component)
  2464.   (when (and (not *load-source-instead-of-binary*)
  2465.          (not *load-source-if-no-binary*))
  2466.     (cond ((component-load-only component)
  2467.        #|(let ((prompt (prompt-string component)))
  2468.          (format t "~A- File ~A is load-only, ~
  2469.                       ~&~A  not compiling."
  2470.              prompt
  2471.              (namestring (component-full-pathname component :source))
  2472.              prompt))|#
  2473.        nil)
  2474.       ((eq *compile-during-load* :query)
  2475.        (let* ((prompt (prompt-string component))
  2476.           (compile-source
  2477.            (y-or-n-p-wait 
  2478.             #\y 30
  2479.             "~A- Binary file ~A is old or does not exist. ~
  2480.                    ~&~A  Compile (and load) source file ~A instead? "
  2481.             prompt
  2482.             (namestring (component-full-pathname component :binary))
  2483.             prompt
  2484.             (namestring (component-full-pathname component :source)))))
  2485.          (unless (y-or-n-p-wait 
  2486.               #\y 30
  2487.               "~A- Should I bother you if this happens again? "
  2488.               prompt)
  2489.            (setq *compile-during-load* 
  2490.              (y-or-n-p-wait 
  2491.               #\y 30
  2492.               "~A- Should I compile and load or not? "
  2493.               prompt))) ; was compile-source, then t
  2494.          compile-source))
  2495.       (*compile-during-load*)
  2496.       (t nil))))
  2497.  
  2498. (defun load-source-if-no-binary (component)
  2499.   (and (not *load-source-instead-of-binary*)
  2500.        (or *load-source-if-no-binary*
  2501.        (component-load-only component)
  2502.        (when *bother-user-if-no-binary*
  2503.          (let* ((prompt (prompt-string component))
  2504.             (load-source
  2505.              (y-or-n-p-wait #\y 30
  2506.               "~A- Binary file ~A does not exist. ~
  2507.                        ~&~A  Load source file ~A instead? "
  2508.               prompt
  2509.               (namestring (component-full-pathname component :binary))
  2510.               prompt
  2511.               (namestring (component-full-pathname component :source)))))
  2512.            (setq *bother-user-if-no-binary*
  2513.              (y-or-n-p-wait #\n 30
  2514.               "~A- Should I bother you if this happens again? "
  2515.               prompt ))
  2516.            (unless *bother-user-if-no-binary*
  2517.          (setq *load-source-if-no-binary* load-source))
  2518.            load-source)))))
  2519.  
  2520. ;;; ********************************
  2521. ;;; Allegro Make System Fasl *******
  2522. ;;; ********************************
  2523. #+:excl
  2524. (defun allegro-make-system-fasl (system destination)
  2525.   (excl:shell
  2526.    (format nil "rm -f ~A; cat~{ ~A~} > ~A" 
  2527.        destination
  2528.        (mapcar #'namestring
  2529.            (files-in-system system :all :binary)))))
  2530.  
  2531. (defun files-which-need-compilation (system)
  2532.   (mapcar #'(lambda (comp) (namestring (component-full-pathname comp :source)))
  2533.       (remove nil
  2534.           (file-components-in-component
  2535.            (find-system system :load) :new-source))))
  2536.  
  2537. (defun files-in-system (name &optional (force :all) (type :source) version)
  2538.   ;; Returns a list of the pathnames in system in load order.
  2539.   (let ((system (find-system name :load)))
  2540.     (multiple-value-bind (*version-dir* *version-replace*) 
  2541.     (translate-version version)
  2542.       (let ((*version* version))
  2543.     (file-pathnames-in-component system type force)))))
  2544.  
  2545. (defun file-pathnames-in-component (component type &optional (force :all))
  2546.   (mapcar #'(lambda (comp) (component-full-pathname comp type))
  2547.       (file-components-in-component component force)))
  2548.  
  2549. (defun file-components-in-component (component &optional (force :all) 
  2550.                            &aux result changed)
  2551.   (case (component-type component)
  2552.     ((:file :private-file)
  2553.      (when (setq changed 
  2554.          (or (find force '(:all t) :test #'eq) 
  2555.              (and (not (non-empty-listp force))
  2556.               (needs-compilation component))))
  2557.        (setq result
  2558.          (list component))))
  2559.     ((:module :system :subsystem :defsystem)
  2560.      (dolist (module (component-components component))
  2561.        (multiple-value-bind (r c)
  2562.        (file-components-in-component 
  2563.         module 
  2564.         (cond ((and (some #'(lambda (dependent)
  2565.                   (member dependent changed))
  2566.                   (component-depends-on module))
  2567.             (or (non-empty-listp force)
  2568.                 (eq force :new-source-and-dependents)))
  2569.            ;; The component depends on a changed file and force agrees.
  2570.            :all)
  2571.           ((and (non-empty-listp force)
  2572.             (member (component-name module) force
  2573.                 :test #'string-equal :key #'string))
  2574.            ;; Force is a list of modules and the component is one of them.
  2575.            :all)
  2576.           (t force)))
  2577.      (when c
  2578.        (push module changed)
  2579.        (setq result (append result r)))))))
  2580.   (values result changed))
  2581.  
  2582. (setf (symbol-function 'oos) (symbol-function 'operate-on-system))
  2583.  
  2584. ;;; ********************************
  2585. ;;; Additional Component Operations 
  2586. ;;; ********************************
  2587.  
  2588. ;;; *** Edit Operation ***
  2589.  
  2590. #+:ccl
  2591. (defun edit-operation (component force)
  2592.   "Always returns nil, i.e. component not changed."
  2593.   (declare (ignore force))
  2594.   ;;
  2595.   (let* ((full-pathname (make::component-full-pathname component :source))
  2596.          (already-editing\? #+:mcl (dolist (w (windows :class 'fred-window))
  2597.                                     (when (equal (window-filename w)
  2598.                                                  full-pathname)
  2599.                                       (return w)))
  2600.                            #-:mcl nil))
  2601.     (if already-editing\?
  2602.       #+:mcl (window-select already-editing\?) #-:mcl nil
  2603.       (ed full-pathname)))
  2604.   nil)
  2605.  
  2606. #+:ccl
  2607. (make::component-operation :edit 'edit-operation)
  2608. #+:ccl
  2609. (make::component-operation 'edit 'edit-operation)
  2610.  
  2611. ;;; *** System Source Size ***
  2612.  
  2613. (defun system-source-size (system-name)
  2614.   "Prints a short report and returns the size in bytes of the source files in
  2615.    <system-name>."
  2616.   (let* ((file-list (files-in-system system-name :all :source))
  2617.          (total-size (file-list-size file-list)))
  2618.     (format t "~&~S (~A files) totals ~A bytes (~A K)"
  2619.             system-name (length file-list) total-size (round total-size 1024))
  2620.     total-size))
  2621.  
  2622. (defun file-list-size (file-list)
  2623.   "Returns the size in bytes of the files in <file-list>."
  2624.   ;;
  2625.   (let ((total-size 0))
  2626.     (dolist (file file-list)
  2627.       (with-open-file (stream file)
  2628.         (incf total-size (file-length stream))))
  2629.     total-size))
  2630.  
  2631.  
  2632.  
  2633. ;;; ****************************************************************
  2634. ;;; Dead Code ******************************************************
  2635. ;;; ****************************************************************
  2636.  
  2637. #|
  2638. ;;; ********************************
  2639. ;;; Alist Manipulation *************
  2640. ;;; ********************************
  2641. ;;; This is really gross. I've replaced it with hash tables.
  2642.  
  2643. (defun alist-lookup (name alist &key (test #'eql) (key #'identity))
  2644.   (cdr (assoc name alist :test test :key key)))
  2645.  
  2646. (defmacro set-alist-lookup ((name alist &key (test '#'eql) (key '#'identity)) 
  2647.                 value)
  2648.   (let ((pair (gensym)))
  2649.     `(let ((,pair (assoc ,name ,alist :test ,test :key ,key)))
  2650.        (if ,pair
  2651.        (rplacd ,pair ,value)
  2652.      (push (cons ,name ,value) ,alist)))))
  2653.  
  2654. (defun component-operation (name &optional operation)
  2655.   (if operation
  2656.       (set-alist-lookup (name *component-operations*) operation)
  2657.     (alist-lookup name *component-operations*)))
  2658.  
  2659. (defun machine-type-translation (name &optional operation)
  2660.   (if operation
  2661.       (set-alist-lookup (name *machine-type-alist* :test #'string-equal)
  2662.             operation)
  2663.     (alist-lookup name *machine-type-alist* :test #'string-equal)))
  2664.  
  2665. (defun software-type-translation (name &optional operation)
  2666.   (if operation
  2667.       (set-alist-lookup (name *software-type-alist* :test #'string-equal)
  2668.             operation)
  2669.     (alist-lookup name *software-type-alist* :test #'string-equal)))
  2670.  
  2671. |#
  2672.  
  2673. ;;; *END OF FILE*
  2674.  
  2675.  
  2676.  
  2677.  
  2678.