Ticket #440: compile-ccl.lisp

File compile-ccl.lisp, 30.0 KB (added by dbmcclain, 6 years ago)

Corrected ccl/lib/compile-ccl.lisp

Line 
1;;;-*-Mode: LISP; Package: CCL -*-
2;;;
3;;;   Copyright (C) 1994-2001 Digitool, Inc
4;;;   This file is part of OpenMCL. 
5;;;
6;;;   OpenMCL is licensed under the terms of the Lisp Lesser GNU Public
7;;;   License , known as the LLGPL and distributed with OpenMCL as the
8;;;   file "LICENSE".  The LLGPL consists of a preamble and the LGPL,
9;;;   which is distributed with OpenMCL as the file "LGPL".  Where these
10;;;   conflict, the preamble takes precedence. 
11;;;
12;;;   OpenMCL is referenced in the preamble as the "LIBRARY."
13;;;
14;;;   The LLGPL is also available online at
15;;;   http://opensource.franz.com/preamble.html
16
17(in-package "CCL")
18
19(require 'systems)
20
21(defparameter *sysdef-modules*
22  '(systems compile-ccl))
23
24(defparameter *level-1-modules*
25  '(level-1
26    l1-cl-package
27    l1-boot-1 l1-boot-2 l1-boot-3
28    l1-utils l1-init l1-symhash l1-numbers l1-aprims
29    l1-sort l1-dcode l1-clos-boot l1-clos
30    l1-unicode l1-streams l1-files l1-io
31    l1-format l1-readloop l1-reader
32    l1-sysio l1-pathnames l1-events
33    l1-boot-lds  l1-readloop-lds
34    l1-lisp-threads  l1-application l1-processes
35    l1-typesys sysutils l1-error-system
36    l1-error-signal version l1-callbacks
37    l1-sockets linux-files
38    ))
39
40(defparameter *compiler-modules*
41  '(nx optimizers dll-node arch vreg vinsn
42    reg subprims  backend nx2))
43
44
45(defparameter *ppc-compiler-modules*
46  '(ppc32-arch
47    ppc64-arch
48    ppc-arch
49    ppcenv
50    ppc-asm
51    risc-lap
52    ppc-lap
53    ppc-backend
54))
55
56(defparameter *x86-compiler-modules*
57  '(x8632-arch
58    x8664-arch
59    x86-arch
60    x8632env
61    x8664env
62    x86-asm
63    x86-lap
64    x86-backend
65))
66
67(defparameter *ppc32-compiler-backend-modules*
68  '(ppc32-backend ppc32-vinsns))
69
70(defparameter *ppc64-compiler-backend-modules*
71  '(ppc64-backend ppc64-vinsns))
72
73
74(defparameter *ppc-compiler-backend-modules*
75  '(ppc2))
76
77
78(defparameter *x8632-compiler-backend-modules*
79  '(x8632-backend x8632-vinsns))
80
81(defparameter *x8664-compiler-backend-modules*
82  '(x8664-backend x8664-vinsns))
83
84(defparameter *x86-compiler-backend-modules*
85  '(x862))
86
87
88
89
90(defparameter *ppc-xload-modules* '(xppcfasload xfasload heap-image ))
91(defparameter *x8632-xload-modules* '(xx8632fasload xfasload heap-image ))
92(defparameter *x8664-xload-modules* '(xx8664fasload xfasload heap-image ))
93
94
95;;; Not too OS-specific.
96(defparameter *ppc-xdev-modules* '(ppc-lapmacros ))
97(defparameter *x86-xdev-modules* '(x86-lapmacros ))
98
99(defun target-xdev-modules (&optional (target
100                                       (backend-target-arch-name
101                                        *host-backend*)))
102  (case target
103    ((:ppc32 :ppc64) *ppc-xdev-modules*)
104    ((:x8632 :x8664) *x86-xdev-modules*)))
105
106(defun target-xload-modules (&optional (target
107                                        (backend-target-arch-name *host-backend*)))
108  (case target
109    ((:ppc32 :ppc64) *ppc-xload-modules*)
110    (:x8632 *x8632-xload-modules*)
111    (:x8664 *x8664-xload-modules*)))
112
113
114
115
116
117
118(defparameter *env-modules*
119  '(hash backquote lispequ  level-2 macros
120    defstruct-macros lists chars setf setf-runtime
121    defstruct defstruct-lds
122    foreign-types
123    db-io
124    nfcomp
125    ))
126
127(defun target-env-modules (&optional (target
128                                      (backend-name *host-backend*)))
129  (append *env-modules*
130          (list
131           (ecase target
132             (:linuxppc32 'ffi-linuxppc32)
133             (:darwinppc32 'ffi-darwinppc32)
134             (:darwinppc64 'ffi-darwinppc64)
135             (:linuxppc64 'ffi-linuxppc64)
136             (:darwinx8632 'ffi-darwinx8632)
137             (:linuxx8664 'ffi-linuxx8664)
138             (:darwinx8664 'ffi-darwinx8664)
139             (:freebsdx8664 'ffi-freebsdx8664)
140             (:solarisx8664 'ffi-solarisx8664)
141             (:win64 'ffi-win64)
142             (:linuxx8632 'ffi-linuxx8632)
143             (:win32 'ffi-win32)
144             (:solarisx8632 'ffi-solarisx8632)
145             (:freebsdx8632 'ffi-freebsdx8632)))))
146
147
148(defun target-compiler-modules (&optional (target
149                                           (backend-target-arch-name
150                                            *host-backend*)))
151  (case target
152    (:ppc32 (append *ppc-compiler-modules*
153                    *ppc32-compiler-backend-modules*
154                    *ppc-compiler-backend-modules*))
155    (:ppc64 (append *ppc-compiler-modules*
156                    *ppc64-compiler-backend-modules*
157                    *ppc-compiler-backend-modules*))
158    (:x8632 (append *x86-compiler-modules*
159                    *x8632-compiler-backend-modules*
160                    *x86-compiler-backend-modules*))
161    (:x8664 (append *x86-compiler-modules*
162                    *x8664-compiler-backend-modules*
163                    *x86-compiler-backend-modules*))))
164
165(defparameter *other-lib-modules*
166  '(streams pathnames backtrace
167    apropos
168    numbers
169    dumplisp   source-files))
170
171(defun target-other-lib-modules (&optional (target
172                                            (backend-target-arch-name
173                                             *host-backend*)))
174  (append *other-lib-modules*
175          (case target
176            ((:ppc32 :ppc64) '(ppc-backtrace ppc-disassemble))
177            ((:x8632 :x8664) '(x86-backtrace x86-disassemble)))))
178         
179
180(defun target-lib-modules (&optional (backend-name
181                                      (backend-name *host-backend*)))
182  (let* ((backend (or (find-backend backend-name) *host-backend*))
183         (arch-name (backend-target-arch-name backend)))
184    (append (target-env-modules backend-name) (target-other-lib-modules arch-name))))
185
186
187(defparameter *code-modules*
188  '(encapsulate
189    read misc  arrays-fry
190    sequences sort
191    method-combination
192    case-error pprint
193    format time
194;        eval step
195    backtrace-lds  ccl-export-syms prepare-mcl-environment))
196
197
198
199(defparameter *aux-modules*
200  '(number-macros number-case-macro
201    loop
202    runtime
203    mcl-compat
204    arglist
205    edit-callers
206    describe
207    leaks
208    asdf
209    defsystem
210    ))
211
212
213
214
215
216
217
218(defun target-level-1-modules (&optional (target (backend-name *host-backend*)))
219  (append *level-1-modules*
220          (case target
221            ((:linuxppc32 :darwinppc32 :linuxppc64 :darwinppc64)
222             '(ppc-error-signal ppc-trap-support
223               ppc-threads-utils ppc-callback-support))
224            ((:linuxx8664 :freebsdx8664 :darwinx8664 :solarisx8664
225                          :darwinx8632 :win64  :linuxx8632 :win32 :solarisx8632
226                          :freebsdx8632)
227             '(x86-error-signal x86-trap-support
228               x86-threads-utils x86-callback-support)))))
229
230
231;;; Needed to cross-dump an image
232
233
234(unless (fboundp 'xload-level-0)
235  (%fhave 'xload-level-0
236          #'(lambda (&rest rest)
237              (in-development-mode
238               (require-modules (target-xload-modules)))
239              (apply 'xload-level-0 rest))))
240
241(defun find-module (module &optional (target (backend-name *host-backend*))  &aux data fasl sources)
242  (if (setq data (assoc module *ccl-system*))
243    (let* ((backend (or (find-backend target) *host-backend*)))
244      (setq fasl (cadr data) sources (caddr data))     
245      (setq fasl (merge-pathnames (backend-target-fasl-pathname
246                                   backend) fasl))
247      (values fasl (if (listp sources) sources (list sources))))
248    (error "Module ~S not defined" module)))
249
250;compile if needed.
251(defun target-compile-modules (modules target force-compile)
252  (if (not (listp modules)) (setq modules (list modules)))
253  (in-development-mode
254   (dolist (module modules t)
255     (multiple-value-bind (fasl sources) (find-module module target)
256      (if (needs-compile-p fasl sources force-compile)
257        (progn
258          (require'nfcomp)
259          (compile-file (car sources)
260                        :output-file fasl
261                        :verbose t
262                        :target target)))))))
263
264
265(defun needs-compile-p (fasl sources force-compile)
266  (if fasl
267    (if (eq force-compile t)
268      t
269      (if (not (probe-file fasl))
270        t
271        (let ((fasldate (file-write-date fasl)))
272          (if (if (integerp force-compile) (> force-compile fasldate))
273            t
274            (dolist (source sources nil)
275              (if (> (file-write-date source) fasldate)
276                (return t)))))))))
277
278
279
280;;;compile if needed, load if recompiled.
281
282(defun update-modules (modules &optional force-compile)
283  (if (not (listp modules)) (setq modules (list modules)))
284  (in-development-mode
285   (dolist (module modules t)
286     (multiple-value-bind (fasl sources) (find-module module)
287       (if (needs-compile-p fasl sources force-compile)
288         (progn
289           (require'nfcomp)
290           (let* ((*warn-if-redefine* nil))
291             (compile-file (car sources) :output-file fasl :verbose t :load t))
292           (provide module)))))))
293
294(defun compile-modules (modules &optional force-compile)
295  (target-compile-modules modules (backend-name *host-backend*) force-compile)
296)
297
298(defun compile-ccl (&optional force-compile)
299  (with-compilation-unit ()
300    (update-modules *sysdef-modules* force-compile)
301    (update-modules 'nxenv force-compile)
302    (update-modules *compiler-modules* force-compile)
303    (update-modules (target-compiler-modules) force-compile)
304    (update-modules (target-xdev-modules) force-compile)
305    (update-modules (target-xload-modules)  force-compile)
306    (let* ((env-modules (target-env-modules))
307           (other-lib (target-other-lib-modules)))
308      (require-modules env-modules)
309      (update-modules env-modules force-compile)
310      (compile-modules (target-level-1-modules)  force-compile)
311      (update-modules other-lib force-compile)
312      (require-modules other-lib)
313      (require-update-modules *code-modules* force-compile))
314    (compile-modules *aux-modules* force-compile)))
315
316
317
318;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
319
320(defun require-env (&optional force-load)
321  (require-modules  (target-env-modules)
322                   force-load))
323
324(defun compile-level-1 (&optional force-compile)
325  (require-env)
326  (compile-modules (target-level-1-modules (backend-name *host-backend*))
327                   force-compile))
328
329
330
331
332
333(defun compile-lib (&optional force-compile)
334  (compile-modules (target-lib-modules)
335                   force-compile))
336
337(defun compile-code (&optional force-compile)
338  (compile-modules *code-modules* force-compile))
339
340
341;Compile but don't load
342
343(defun xcompile-ccl (&optional force)
344  (with-compilation-unit ()
345    (compile-modules *sysdef-modules* force)
346    (compile-modules 'nxenv force)
347    (compile-modules *compiler-modules* force)
348    (compile-modules (target-compiler-modules) force)
349    (compile-modules (target-xdev-modules) force)
350    (compile-modules (target-xload-modules)  force)
351    (compile-modules (target-env-modules) force)
352    (compile-modules (target-level-1-modules) force)
353    (compile-modules (target-other-lib-modules) force)
354    (compile-modules *code-modules* force)
355    (compile-modules *aux-modules* force)))
356
357(defun require-update-modules (modules &optional force-compile)
358  (if (not (listp modules)) (setq modules (list modules)))
359  (in-development-mode
360    (dolist (module modules)
361    (require-modules module)
362    (update-modules module force-compile))))
363
364
365(defun target-xcompile-ccl (target &optional force)
366  (require-update-modules *sysdef-modules* force) ;in the host
367  (let* ((backend (or (find-backend target) *target-backend*))
368         (arch (backend-target-arch-name backend))
369         (*defstruct-share-accessor-functions* nil))
370    (target-compile-modules 'nxenv target force)
371    (target-compile-modules *compiler-modules* target force)
372    (target-compile-modules (target-compiler-modules arch) target force)
373    (target-compile-modules (target-level-1-modules target) target force)
374    (target-compile-modules (target-lib-modules target) target force)
375    (target-compile-modules *sysdef-modules* target force)
376    (target-compile-modules *aux-modules* target force)
377    (target-compile-modules *code-modules* target force)
378    (target-compile-modules (target-xdev-modules arch) target force)))
379
380(defun cross-compile-ccl (target &optional force)
381  (with-cross-compilation-target (target)
382    (let* ((*target-backend* (find-backend target)))
383      (target-xcompile-ccl target force))))
384
385
386(defun require-module (module force-load)
387  (multiple-value-bind (fasl source) (find-module module)
388      (setq source (car source))
389      (if (if fasl (probe-file fasl))
390        (if force-load
391          (progn
392            (load fasl)
393            (provide module))
394          (require module fasl))
395        (if (probe-file source)
396          (progn
397            (if fasl (format t "~&Can't find ~S so requiring ~S instead"
398                             fasl source))
399            (if force-load
400              (progn
401                (load source)
402                (provide module))
403              (require module source)))
404          (error "Can't find ~S or ~S" fasl source)))))
405
406(defun require-modules (modules &optional force-load)
407  (if (not (listp modules)) (setq modules (list modules)))
408  (let ((*package* (find-package :ccl)))
409    (dolist (m modules t)
410      (require-module m force-load))))
411
412
413(defun target-xcompile-level-1 (target &optional force)
414  (target-compile-modules (target-level-1-modules target) target force))
415
416(defun standard-boot-image-name (&optional (target (backend-name *host-backend*)))
417  (ecase target
418    (:darwinppc32 "ppc-boot.image")
419    (:linuxppc32 "ppc-boot")
420    (:darwinppc64 "ppc-boot64.image")
421    (:linuxppc64 "ppc-boot64")
422    (:darwinx8632 "x86-boot32.image")
423    (:linuxx8664 "x86-boot64")
424    (:freebsdx8664 "fx86-boot64")
425    (:darwinx8664 "x86-boot64.image")
426    (:solarisx8664 "sx86-boot64")
427    (:win64 "wx86-boot64.image")
428    (:linuxx8632 "x86-boot32")
429    (:win32 "wx86-boot32.image")
430    (:solarisx8632 "sx86-boot32")
431    (:freebsdx8632 "fx86-boot32")))
432
433(defun standard-kernel-name (&optional (target (backend-name *host-backend*)))
434  (ecase target
435    (:darwinppc32 "dppccl")
436    (:linuxppc32 "ppccl")
437    (:darwinppc64 "dppccl64")
438    (:darwinx8632 "dx86cl")
439    (:linuxppc64 "ppccl64")
440    (:linuxx8664 "lx86cl64")
441    (:freebsdx8664 "fx86cl64")
442    (:darwinx8664 "dx86cl64")
443    (:solarisx8664 "sx86cl64")
444    (:win64 "wx86cl64.exe")
445    (:linuxx8632 "lx86cl")
446    (:win32 "wx86cl.exe")
447    (:solarisx8632 "sx86cl")
448    (:freebsdx8632 "fx86cl")))
449
450(defun standard-image-name (&optional (target (backend-name *host-backend*)))
451  (concatenate 'string (pathname-name (standard-kernel-name target)) ".image"))
452
453(defun kernel-build-directory (&optional (target (backend-name *host-backend*)))
454  (ecase target
455    (:darwinppc32 "darwinppc")
456    (:linuxppc32 "linuxppc")
457    (:darwinppc64 "darwinppc64")
458    (:linuxppc64 "linuxppc64")
459    (:darwinx8632 "darwinx8632")
460    (:linuxx8664 "linuxx8664")
461    (:freebsdx8664 "freebsdx8664")
462    (:darwinx8664 "darwinx8664")
463    (:solarisx8664 "solarisx64")
464    (:win64 "win64")
465    (:linuxx8632 "linuxx8632")
466    (:win32 "win32")
467    (:solarisx8632 "solarisx86")
468    (:freebsdx8632 "freebsdx8632")))
469
470;;; If we distribute (e.g.) 32- and 64-bit versions for the same
471;;; machine and OS in the same svn directory, return the name of the
472;;; peer backend, or NIL. For example., the peer of :linuxppc64 is
473;;; :linuxppc32.  Note that this may change over time.
474;;; Return NIL if the concept doesn't apply.
475(defun peer-platform (&optional (target (backend-name *host-backend*)))
476  (let* ((pairs '((:darwinppc32 . :darwinppc64)
477                  (:linuxppc32 . :linuxppc64)
478                  (:darwinx8632 . :darwinx8664)
479                  (:linuxx8632 . :linuxx8664)
480                  (:win32 . :win64)
481                  (:solarisx8632 . :solarisx8664)
482                  (:freebsdx8632 . :freebsdx8664))))
483    (or (cdr (assoc target pairs))
484        (car (rassoc target pairs)))))
485
486(defun make-program (&optional (target (backend-name *host-backend*)))
487  ;; The Solaris "make" program is too clever to understand -C, so
488  ;; use GNU make (installed as "gmake").
489  (case target
490    ((:solarisx8664 :solarisx8632) "gmake")
491    (t "make")))
492
493(defparameter *known-optional-features* '(:count-gf-calls :monitor-futex-wait :unique-dcode))
494(defvar *build-time-optional-features* nil)
495
496
497(defun rebuild-ccl (&key update full clean kernel force (reload t) exit reload-arguments verbose optional-features)
498  (let* ((*build-time-optional-features* (intersection *known-optional-features* optional-features))
499         (*features* (append *build-time-optional-features* *features*)))
500    (when *build-time-optional-features*
501      (setq full t))
502    (when full
503      (setq clean t kernel t reload t))
504    (when update (update-ccl :verbose (not (eq update :quiet))))
505    (when (or clean force)
506      ;; for better bug reports...
507      (format t "~&Rebuilding ~a using ~a"
508              (lisp-implementation-type)
509              (lisp-implementation-version)))
510    (let* ((cd (current-directory)))
511      (unwind-protect
512           (progn
513             (setf (current-directory) (translate-logical-pathname "ccl:"))
514             (when clean
515               (dolist (f (directory
516                           (translate-logical-pathname
517                            (merge-pathnames
518                             (make-pathname :name :wild
519                                            :type (pathname-type *.fasl-pathname*))
520                             "ccl:**;"))))
521                 (delete-file f)))
522             (when kernel
523               (when (or clean force)
524                 ;; Do a "make -k clean".
525                 (run-program "make"
526                              (list "-k"
527                                    "-C"
528                                    (format nil "lisp-kernel/~a"
529                                            (kernel-build-directory))
530                                    "clean")))
531               (format t "~&;Building lisp-kernel ...")
532               (with-output-to-string (s)
533                                      (multiple-value-bind
534                                          (status exit-code)
535                                          (external-process-status
536                                           (run-program (make-program)
537                                                        (list "-k" "-C"
538                                                              (format nil "lisp-kernel/~a"
539                                                                      (kernel-build-directory))
540                                                              "-j"
541                                                           
542                                                              (format nil "~d" (1+ (cpu-count))))
543                                                        :output s
544                                                        :error :output))
545                                        (if (and (eq :exited status) (zerop exit-code))
546                                          (progn
547                                            (format t "~&;Kernel built successfully.")
548                                            (when verbose
549                                              (format t "~&;kernel build output:~%~a"
550                                                      (get-output-stream-string s)))
551                                            (sleep 1))
552                                          (error "Error(s) during kernel compilation.~%~a"
553                                                 (get-output-stream-string s))))))
554             (compile-ccl (not (null force)))
555             (if force (xload-level-0 :force) (xload-level-0))
556             (when reload
557               (with-input-from-string (cmd (format nil
558                                                    "(save-application ~s)"
559                                                    (standard-image-name)))
560                 (with-output-to-string (output)
561                                        (multiple-value-bind (status exit-code)
562                                            (external-process-status
563                                             (run-program
564                                              (format nil "./~a" (standard-kernel-name))
565                                              (list* "--image-name" (standard-boot-image-name)
566                                                     reload-arguments)
567                                              :input cmd
568                                              :output output
569                                              :error output))
570                                          (if (and (eq status :exited)
571                                                   (eql exit-code 0))
572                                            (progn
573                                              (format t "~&;Wrote heap image: ~s"
574                                                      (truename (format nil "ccl:~a"
575                                                                        (standard-image-name))))
576                                              (when verbose
577                                                (format t "~&;Reload heap image output:~%~a"
578                                                        (get-output-stream-string output))))
579                                            (error "Errors (~s ~s) reloading boot image:~&~a"
580                                                   status exit-code
581                                                   (get-output-stream-string output)))))))
582             (when exit
583               (quit)))
584        (setf (current-directory) cd)))))
585                                                 
586               
587(defun create-interfaces (dirname &key target populate-arg)
588  (let* ((backend (if target (find-backend target) *target-backend*))
589         (*default-pathname-defaults* nil)
590         (ftd (backend-target-foreign-type-data backend))
591         (d (use-interface-dir dirname ftd))
592         (populate (merge-pathnames "C/populate.sh"
593                                    (merge-pathnames
594                                     (interface-dir-subdir d)
595                                     (ftd-interface-db-directory ftd))))
596         (cdir (make-pathname :directory (pathname-directory (translate-logical-pathname populate))))
597         (args (list "-c"
598                     (format nil "cd ~a && /bin/sh ~a ~@[~a~]"
599                             (native-translated-namestring cdir)
600                             (native-translated-namestring populate)
601                             populate-arg))))
602    (format t "~&;[Running interface translator via ~s to produce .ffi file(s) from headers]~&" populate)
603    (force-output t)
604    (multiple-value-bind (status exit-code)
605        (external-process-status
606         (run-program "/bin/sh" args :output t))
607      (if (and (eq status :exited)
608               (eql exit-code 0))
609        (let* ((f 'parse-standard-ffi-files))
610          (require "PARSE-FFI")
611          (format t "~%~%;[Parsing .ffi files; may create new .cdb files for ~s]" dirname)
612          (funcall f dirname target)
613          (format t "~%~%;[Parsing .ffi files again to resolve forward-referenced constants]")
614          (funcall f dirname target))))))
615
616(defun update-ccl (&key (verbose t))
617  (let* ((changed ())
618         (conflicts ()))
619    (with-output-to-string (out)
620      (with-preserved-working-directory ((translate-logical-pathname "ccl:"))
621        (when verbose (format t "~&;Running 'svn update'."))
622        (multiple-value-bind (status exit-code)
623            (external-process-status
624             (run-program "svn" '("update" "--non-interactive") :output out :error t))
625          (when verbose (format t "~&;'svn update' complete."))
626          (if (not (and (eq status :exited)
627                        (eql exit-code 0)))
628            (error "Running \"svn update\" produced exit status ~s, code ~s." status exit-code)
629            (let* ((sout (get-output-stream-string out))
630                   (added ())
631                   (deleted ())
632                   (updated ())
633                   (merged ())
634                   (binaries (list (standard-kernel-name) (standard-image-name )))
635                   (peer (peer-platform)))
636              (when peer
637                (push (standard-kernel-name peer) binaries)
638                (push (standard-image-name peer) binaries))
639              (flet ((svn-revert (string)
640                       (multiple-value-bind (status exit-code)
641                           (external-process-status (run-program "svn" `("revert" ,string)))
642                         (when (and (eq status :exited) (eql exit-code 0))
643                           (setq conflicts (delete string conflicts :test #'string=))
644                           (push string updated)))))
645                (with-input-from-string (in sout)
646                  (do* ((line (read-line in nil nil) (read-line in nil nil)))
647                       ((null line))
648                    (when (and (> (length line) 2)
649                               (eql #\space (schar line 1)))
650                      (let* ((path (string-trim " " (subseq line 2))))
651                        (case (schar line 0)
652                          (#\A (push path added))
653                          (#\D (push path deleted))
654                          (#\U (push path updated))
655                          (#\G (push path merged))
656                          (#\C (push path conflicts)))))))
657                ;; If the kernel and/or image conflict, use "svn revert"
658                ;; to replace the working copies with the (just updated)
659                ;; repository versions.
660                (setq changed (if (or added deleted updated merged conflicts) t))
661             
662                (dolist (f binaries)
663                  (when (member f conflicts :test #'string=)
664                    (svn-revert f)))
665                ;; If there are any remaining conflicts, offer
666                ;; to revert them.
667                (when conflicts
668                  (with-preserved-working-directory ()
669                    (cerror "Discard local changes to these files (using 'svn revert'."
670                            "'svn update' was unable to merge local changes to the following file~p with the updated versions:~{~&~s~~}" (length conflicts) conflicts)
671                    (dolist (c (copy-list conflicts))
672                      (svn-revert c))))
673                ;; Report other changes, if verbose.
674                (when (and verbose
675                           (or added deleted updated merged conflicts))
676                  (format t "~&;Changes from svn update:")
677                  (flet ((show-changes (herald files)
678                           (when files
679                             (format t "~&; ~a:~{~&;  ~a~}"
680                                     herald files))))
681                    (show-changes "Conflicting files" conflicts)
682                    (show-changes "New files/directories" added)
683                    (show-changes "Deleted files/directories" deleted)
684                    (show-changes "Updated files" updated)
685                    (show-changes "Files with local changes, successfully merged" merged)))))))))
686    (values changed conflicts)))
687
688(defmacro with-preserved-working-directory ((&optional dir) &body body)
689  (let ((wd (gensym)))
690    `(let ((,wd (mac-default-directory)))
691       (unwind-protect
692            (progn
693              ,@(when dir `((cwd ,dir)))
694              ,@body)
695         (cwd ,wd)))))
696
697(defun ensure-tests-loaded (&key force update ansi ccl)
698  (unless (and (find-package "REGRESSION-TEST") (not force))
699    (if (probe-file (translate-logical-pathname "ccl:tests;ansi-tests;"))
700      (when update
701        (cwd (translate-logical-pathname "ccl:tests;"))
702        (run-program "svn" '("update")))
703      (let* ((svn (probe-file (translate-logical-pathname "ccl:.svn;entries")))
704             (repo (and svn (svn-repository)))
705             (s (make-string-output-stream)))
706        (when repo
707          (format t "~&Checking out test suite into ccl:tests;~%")
708          (cwd (translate-logical-pathname "ccl:"))
709          (multiple-value-bind (status exit-code)
710              (external-process-status
711               (run-program "svn" (list "checkout" (format nil "~a/trunk/tests" repo) "tests")
712                            :output s
713                            :error s))
714            (unless (and (eq status :exited)
715                         (eql exit-code 0))
716              (error "Failed to check out test suite: ~%~a" (get-output-stream-string s)))))))
717    (cwd (translate-logical-pathname "ccl:tests;ansi-tests;"))
718    (run-program "make" '("-k" "clean"))
719    (map nil 'delete-file (directory "*.*fsl"))
720    ;; Muffle the typecase "clause ignored" warnings, since there is really nothing we can do about
721    ;; it without making the test suite non-portable across platforms...
722    (handler-bind ((warning (lambda (c)
723                              (when (let ((w (or (and (typep c 'compiler-warning)
724                                                      (eq (compiler-warning-warning-type c) :program-error)
725                                                      (car (compiler-warning-args c)))
726                                                 c)))
727                                      (and (typep w 'simple-warning)
728                                           (or
729                                            (string-equal
730                                             (simple-condition-format-control w)
731                                             "Clause ~S ignored in ~S form - shadowed by ~S .")
732                                            ;; Might as well ignore these as well, they're intentional.
733                                            (string-equal
734                                             (simple-condition-format-control w)
735                                             "Duplicate keyform ~s in ~s statement."))))
736                                (muffle-warning c)))))
737      ;; This loads the infrastructure
738      (load (translate-logical-pathname "ccl:tests;ansi-tests;gclload1.lsp"))
739      ;; This loads the actual tests
740      (let ((redef-var (find-symbol "*WARN-IF-REDEFINE-TEST*" :REGRESSION-TEST)))
741        (progv (list redef-var) (list (if force nil (symbol-value redef-var)))
742          (when ansi
743            (load (translate-logical-pathname "ccl:tests;ansi-tests;gclload2.lsp")))
744          ;; And our own tests
745          (when ccl
746            (load (translate-logical-pathname "ccl:tests;ansi-tests;ccl.lsp"))))))))
747
748(defun test-ccl (&key force (update t) verbose (catch-errors t) (ansi t) (ccl t)
749                      optimization-settings)
750  (with-preserved-working-directory ()
751    (let* ((*package* (find-package "CL-USER")))
752      (ensure-tests-loaded :force force :update update :ansi ansi :ccl ccl)
753      (cwd (translate-logical-pathname "ccl:tests;ansi-tests;"))
754      (let ((do-tests (find-symbol "DO-TESTS" "REGRESSION-TEST"))
755            (*print-catch-errors* nil))
756        (prog1
757            (time (funcall do-tests :verbose verbose :compile t
758                           :catch-errors catch-errors
759                           :optimization-settings (or optimization-settings '((safety 2)))))
760          ;; Clean up a little
761          (map nil #'delete-file
762               (directory (translate-logical-pathname
763                           (merge-pathnames *.fasl-pathname* "ccl:tests;ansi-tests;temp*")))))))))