1 | ;;; compile-file.lisp |
---|
2 | ;;; |
---|
3 | ;;; Copyright (C) 2004-2006 Peter Graves |
---|
4 | ;;; $Id: compile-file.lisp 15583 2022-05-23 06:23:42Z mevenson $ |
---|
5 | ;;; |
---|
6 | ;;; This program is free software; you can redistribute it and/or |
---|
7 | ;;; modify it under the terms of the GNU General Public License |
---|
8 | ;;; as published by the Free Software Foundation; either version 2 |
---|
9 | ;;; of the License, or (at your option) any later version. |
---|
10 | ;;; |
---|
11 | ;;; This program is distributed in the hope that it will be useful, |
---|
12 | ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
14 | ;;; GNU General Public License for more details. |
---|
15 | ;;; |
---|
16 | ;;; You should have received a copy of the GNU General Public License |
---|
17 | ;;; along with this program; if not, write to the Free Software |
---|
18 | ;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
---|
19 | ;;; |
---|
20 | ;;; As a special exception, the copyright holders of this library give you |
---|
21 | ;;; permission to link this library with independent modules to produce an |
---|
22 | ;;; executable, regardless of the license terms of these independent |
---|
23 | ;;; modules, and to copy and distribute the resulting executable under |
---|
24 | ;;; terms of your choice, provided that you also meet, for each linked |
---|
25 | ;;; independent module, the terms and conditions of the license of that |
---|
26 | ;;; module. An independent module is a module which is not derived from |
---|
27 | ;;; or based on this library. If you modify this library, you may extend |
---|
28 | ;;; this exception to your version of the library, but you are not |
---|
29 | ;;; obligated to do so. If you do not wish to do so, delete this |
---|
30 | ;;; exception statement from your version. |
---|
31 | |
---|
32 | (in-package #:system) |
---|
33 | |
---|
34 | (require "COMPILER-PASS2") |
---|
35 | |
---|
36 | (export 'compile-file-if-needed) |
---|
37 | |
---|
38 | (defvar *fbound-names*) |
---|
39 | |
---|
40 | (defvar *class-number*) |
---|
41 | |
---|
42 | (defvar *output-file-pathname*) |
---|
43 | |
---|
44 | (defvar *toplevel-functions*) |
---|
45 | (defvar *toplevel-macros*) |
---|
46 | (defvar *toplevel-exports*) |
---|
47 | (defvar *toplevel-setf-expanders*) |
---|
48 | (defvar *toplevel-setf-functions*) |
---|
49 | |
---|
50 | |
---|
51 | (defun base-classname (&optional (output-file-pathname *output-file-pathname*)) |
---|
52 | (sanitize-class-name (pathname-name output-file-pathname))) |
---|
53 | |
---|
54 | (defun fasl-loader-classname (&optional (output-file-pathname *output-file-pathname*)) |
---|
55 | (%format nil "~A_0" (base-classname output-file-pathname))) |
---|
56 | |
---|
57 | (declaim (ftype (function (t) t) compute-classfile)) |
---|
58 | (defun compute-classfile (n &optional (output-file-pathname |
---|
59 | *output-file-pathname*)) |
---|
60 | "Computes the pathname of the class file associated with number `n'." |
---|
61 | (let ((name |
---|
62 | (sanitize-class-name |
---|
63 | (%format nil "~A_~D" (pathname-name output-file-pathname) n)))) |
---|
64 | (merge-pathnames (make-pathname :name name :type *compile-file-class-extension*) |
---|
65 | output-file-pathname))) |
---|
66 | |
---|
67 | (defun sanitize-class-name (name) |
---|
68 | (let ((name (copy-seq name))) |
---|
69 | (dotimes (i (length name)) |
---|
70 | (declare (type fixnum i)) |
---|
71 | (when (or (char= (char name i) #\-) |
---|
72 | (char= (char name i) #\.) |
---|
73 | (char= (char name i) #\Space)) |
---|
74 | (setf (char name i) #\_))) |
---|
75 | name)) |
---|
76 | |
---|
77 | |
---|
78 | (declaim (ftype (function () t) next-classfile)) |
---|
79 | (defun next-classfile () |
---|
80 | (compute-classfile (incf *class-number*))) |
---|
81 | |
---|
82 | (defmacro report-error (&rest forms) |
---|
83 | `(handler-case (progn ,@forms) |
---|
84 | (compiler-unsupported-feature-error (condition) |
---|
85 | (fresh-line) |
---|
86 | (%format t "; UNSUPPORTED-FEATURE: ~A~%" condition) |
---|
87 | (values nil condition)))) |
---|
88 | |
---|
89 | ;; Dummy function. Should never be called. |
---|
90 | (defun dummy (&rest ignored) |
---|
91 | (declare (ignore ignored)) |
---|
92 | (assert nil)) |
---|
93 | |
---|
94 | ;;; ??? rename to something shorter? |
---|
95 | (defparameter *compiler-diagnostic* nil |
---|
96 | "The stream to emit compiler diagnostic messages to, or nil to muffle output.") |
---|
97 | (export '*compiler-diagnostic*) |
---|
98 | (defun diag (format &rest args) |
---|
99 | (apply #'cl:format |
---|
100 | *compiler-diagnostic* |
---|
101 | (cl:concatenate 'string "~&SYSTEM::*COMPILER-DIAGNOSTIC* " format "~&") |
---|
102 | (when args |
---|
103 | args))) |
---|
104 | |
---|
105 | |
---|
106 | (declaim (ftype (function (t) t) verify-load)) |
---|
107 | (defun verify-load (classfile &key (force nil)) |
---|
108 | "Return whether the file at the path denoted by CLASSFILE is a loadable JVM artifact." |
---|
109 | (declare (ignore force)) |
---|
110 | (unless classfile |
---|
111 | (diag "Nil classfile argument passed to verify-load.") |
---|
112 | (return-from verify-load nil)) |
---|
113 | (with-open-file (cf classfile :direction :input) |
---|
114 | (when |
---|
115 | (= 0 (file-length cf)) |
---|
116 | ;;; TODO hook into a real ABCL compiler condition hierarchy |
---|
117 | (diag "Internal compiler error detected: Fasl contains ~ |
---|
118 | zero-length jvm classfile corresponding to ~A." classfile) |
---|
119 | (return-from verify-load nil))) |
---|
120 | ;; ### FIXME |
---|
121 | ;; The section below can't work, because we have |
---|
122 | ;; circular references between classes of outer- and innerscoped |
---|
123 | ;; functions. We need the class loader to resolve these circular |
---|
124 | ;; references for us. Our FASL class loader does exactly that, |
---|
125 | ;; so we need a class loader here which knows how to find |
---|
126 | ;; all the .cls files related to the current scope being loaded. |
---|
127 | #+nil |
---|
128 | (when (or force (> *safety* *speed*)) |
---|
129 | (diag "Testing compiled bytecode by loading classfile into JVM.") |
---|
130 | (let ((*load-truename* *output-file-pathname*)) |
---|
131 | ;; load-compiled-function used to be wrapped via report-error |
---|
132 | (return-from verify-load (load-compiled-function classfile)))) |
---|
133 | t) |
---|
134 | |
---|
135 | (declaim (ftype (function (t) t) note-toplevel-form)) |
---|
136 | (defun note-toplevel-form (form) |
---|
137 | (when *compile-print* |
---|
138 | (fresh-line) |
---|
139 | (princ "; ") |
---|
140 | (let ((*print-length* 2) |
---|
141 | (*print-level* 2) |
---|
142 | (*print-pretty* nil)) |
---|
143 | (prin1 form)) |
---|
144 | (terpri))) |
---|
145 | |
---|
146 | (defun output-form (form) |
---|
147 | (if *binary-fasls* |
---|
148 | (push form *forms-for-output*) |
---|
149 | (progn |
---|
150 | (dump-form form *fasl-stream*) |
---|
151 | (%stream-terpri *fasl-stream*)))) |
---|
152 | |
---|
153 | (defun finalize-fasl-output () |
---|
154 | (when *binary-fasls* |
---|
155 | (let ((*package* (find-package :keyword)) |
---|
156 | (*double-colon-package-separators* T)) |
---|
157 | (dump-form (convert-toplevel-form (list* 'PROGN |
---|
158 | (nreverse *forms-for-output*)) |
---|
159 | t) |
---|
160 | *fasl-stream*)) |
---|
161 | (%stream-terpri *fasl-stream*))) |
---|
162 | |
---|
163 | |
---|
164 | (declaim (ftype (function (t) t) simple-toplevel-form-p)) |
---|
165 | (defun simple-toplevel-form-p (form) |
---|
166 | "Returns NIL if the form is too complex to become an |
---|
167 | interpreted toplevel form, non-NIL if it is 'simple enough'." |
---|
168 | (and (consp form) |
---|
169 | (every #'(lambda (arg) |
---|
170 | (or (and (atom arg) |
---|
171 | (not (and (symbolp arg) |
---|
172 | (symbol-macro-p arg)))) |
---|
173 | (and (consp arg) |
---|
174 | (eq 'QUOTE (car arg))))) |
---|
175 | (cdr form)))) |
---|
176 | |
---|
177 | (declaim (ftype (function (t t) t) convert-toplevel-form)) |
---|
178 | (defun convert-toplevel-form (form declare-inline) |
---|
179 | (when (or (simple-toplevel-form-p form) |
---|
180 | (and (eq (car form) 'SETQ) |
---|
181 | ;; for SETQ, look at the evaluated part |
---|
182 | (simple-toplevel-form-p (third form)))) |
---|
183 | ;; single form with simple or constant arguments |
---|
184 | ;; Without this exception, toplevel function calls |
---|
185 | ;; will be compiled into lambdas which get compiled to |
---|
186 | ;; compiled-functions. Those need to be loaded. |
---|
187 | ;; Conclusion: Top level interpreting the function call |
---|
188 | ;; and its arguments may be (and should be) more efficient. |
---|
189 | (return-from convert-toplevel-form |
---|
190 | (precompiler:precompile-form form nil *compile-file-environment*))) |
---|
191 | (let* ((toplevel-form (third form)) |
---|
192 | (expr `(lambda () ,form)) |
---|
193 | (saved-class-number *class-number*) |
---|
194 | (classfile (next-classfile)) |
---|
195 | (result |
---|
196 | (with-open-file |
---|
197 | (f classfile |
---|
198 | :direction :output |
---|
199 | :element-type '(unsigned-byte 8) |
---|
200 | :if-exists :supersede) |
---|
201 | (report-error (jvm:compile-defun nil |
---|
202 | expr *compile-file-environment* |
---|
203 | classfile f |
---|
204 | declare-inline)))) |
---|
205 | (compiled-function (verify-load classfile))) |
---|
206 | (declare (ignore toplevel-form result)) |
---|
207 | (progn |
---|
208 | #+nil |
---|
209 | (when (> *debug* 0) |
---|
210 | ;; TODO (annotate form toplevel-form classfile compiled-function fasl-class-number) |
---|
211 | ;;; ??? define an API by perhaps exporting these symbols? |
---|
212 | (setf (getf form 'form-source) |
---|
213 | toplevel-form |
---|
214 | |
---|
215 | (getf form 'classfile) |
---|
216 | classfile |
---|
217 | |
---|
218 | (getf form 'compiled-function) |
---|
219 | compiled-function |
---|
220 | |
---|
221 | (getf form 'class-number) |
---|
222 | saved-class-number)) |
---|
223 | (setf form |
---|
224 | (if compiled-function |
---|
225 | `(funcall (sys::get-fasl-function *fasl-loader* |
---|
226 | ,saved-class-number)) |
---|
227 | (precompiler:precompile-form form nil |
---|
228 | *compile-file-environment*)))))) |
---|
229 | |
---|
230 | (declaim (ftype (function (t stream t) t) process-progn)) |
---|
231 | (defun process-progn (forms stream compile-time-too) |
---|
232 | (dolist (form forms) |
---|
233 | (process-toplevel-form form stream compile-time-too)) |
---|
234 | nil) |
---|
235 | |
---|
236 | (declaim (ftype (function (t t t) t) process-toplevel-form)) |
---|
237 | (defun precompile-toplevel-form (form stream compile-time-too) |
---|
238 | (declare (ignore stream)) |
---|
239 | (let ((form (precompiler:precompile-form form nil |
---|
240 | *compile-file-environment*))) |
---|
241 | (when compile-time-too |
---|
242 | (eval form)) |
---|
243 | form)) |
---|
244 | |
---|
245 | (defun process-toplevel-macrolet (form stream compile-time-too) |
---|
246 | (let ((*compile-file-environment* |
---|
247 | (make-environment *compile-file-environment*))) |
---|
248 | (dolist (definition (cadr form)) |
---|
249 | (environment-add-macro-definition *compile-file-environment* |
---|
250 | (car definition) |
---|
251 | (make-macro (car definition) |
---|
252 | (make-macro-expander definition)))) |
---|
253 | (dolist (body-form (cddr form)) |
---|
254 | (process-toplevel-form body-form stream compile-time-too))) |
---|
255 | nil) |
---|
256 | |
---|
257 | (declaim (ftype (function (t t t) t) process-toplevel-defconstant)) |
---|
258 | (defun process-toplevel-defconstant (form stream compile-time-too) |
---|
259 | (declare (ignore stream compile-time-too)) |
---|
260 | ;; "If a DEFCONSTANT form appears as a top level form, the compiler |
---|
261 | ;; must recognize that [the] name names a constant variable. An |
---|
262 | ;; implementation may choose to evaluate the value-form at compile |
---|
263 | ;; time, load time, or both. Therefore, users must ensure that the |
---|
264 | ;; initial-value can be evaluated at compile time (regardless of |
---|
265 | ;; whether or not references to name appear in the file) and that |
---|
266 | ;; it always evaluates to the same value." |
---|
267 | (note-toplevel-form form) |
---|
268 | (eval form) |
---|
269 | ;;; emit make-array when initial-value is a specialized vector |
---|
270 | (let ((initial-value (third form))) |
---|
271 | (when (and (atom initial-value) |
---|
272 | (arrayp initial-value) |
---|
273 | (= (length (array-dimensions initial-value)) 1) |
---|
274 | (not (eq (array-element-type initial-value) t))) |
---|
275 | (setf (third form) |
---|
276 | `(common-lisp:make-array |
---|
277 | ',(array-dimensions initial-value) |
---|
278 | :element-type ',(array-element-type initial-value) |
---|
279 | :initial-contents ',(coerce initial-value 'list))))) |
---|
280 | `(progn |
---|
281 | (sys:put ',(second form) 'sys::source |
---|
282 | (cl:cons '(,(second form) ,(namestring *source*) ,*source-position*) |
---|
283 | (cl:get ',(second form) 'sys::source nil))) |
---|
284 | ,form)) |
---|
285 | |
---|
286 | (declaim (ftype (function (t t t) t) process-toplevel-quote)) |
---|
287 | (defun process-toplevel-quote (form stream compile-time-too) |
---|
288 | (declare (ignore stream)) |
---|
289 | (when compile-time-too |
---|
290 | (eval form)) |
---|
291 | nil) |
---|
292 | |
---|
293 | |
---|
294 | (declaim (ftype (function (t t t) t) process-toplevel-import)) |
---|
295 | (defun process-toplevel-import (form stream compile-time-too) |
---|
296 | (declare (ignore stream)) |
---|
297 | (let ((form (precompiler:precompile-form form nil |
---|
298 | *compile-file-environment*))) |
---|
299 | (let ((*package* +keyword-package+)) |
---|
300 | (output-form form)) |
---|
301 | (when compile-time-too |
---|
302 | (eval form))) |
---|
303 | nil) |
---|
304 | |
---|
305 | (declaim (ftype (function (t t t) t) process-toplevel-export)) |
---|
306 | (defun process-toplevel-export (form stream compile-time-too) |
---|
307 | (when (and (listp (second form)) |
---|
308 | (eq (car (second form)) 'QUOTE)) ;; constant export list |
---|
309 | (let ((sym-or-syms (second (second form)))) |
---|
310 | (setf *toplevel-exports* |
---|
311 | (append *toplevel-exports* (if (listp sym-or-syms) |
---|
312 | sym-or-syms |
---|
313 | (list sym-or-syms)))))) |
---|
314 | (precompile-toplevel-form form stream compile-time-too)) |
---|
315 | |
---|
316 | |
---|
317 | (declaim (ftype (function (t t t) t) process-record-source-information)) |
---|
318 | |
---|
319 | (defun process-record-source-information (form stream compile-time-too) |
---|
320 | (declare (ignore stream compile-time-too)) |
---|
321 | (let* ((name (second form)) |
---|
322 | (type (third form))) |
---|
323 | (when (quoted-form-p name) (setq name (second name))) |
---|
324 | (when (quoted-form-p type) (setq type (second type))) |
---|
325 | (let ((sym (if (consp name) (second name) name))) |
---|
326 | `(sys:put ',sym 'sys::source |
---|
327 | (cl:cons '(,type ,(namestring *source*) ,*source-position*) |
---|
328 | (cl:get ',sym 'sys::source nil)))))) |
---|
329 | |
---|
330 | |
---|
331 | (declaim (ftype (function (t t t) t) process-toplevel-mop.ensure-method)) |
---|
332 | (defun process-toplevel-mop.ensure-method (form stream compile-time-too) |
---|
333 | (declare (ignore stream)) |
---|
334 | (flet ((convert-ensure-method (form key) |
---|
335 | (let* ((tail (cddr form)) |
---|
336 | (function-form (getf tail key))) |
---|
337 | (when (and function-form (consp function-form) |
---|
338 | (eq (%car function-form) 'FUNCTION)) |
---|
339 | (let ((lambda-expression (cadr function-form))) |
---|
340 | (jvm::with-saved-compiler-policy |
---|
341 | (let* ((saved-class-number *class-number*) |
---|
342 | (classfile (next-classfile)) |
---|
343 | (result |
---|
344 | (with-open-file |
---|
345 | (f classfile |
---|
346 | :direction :output |
---|
347 | :element-type '(unsigned-byte 8) |
---|
348 | :if-exists :supersede) |
---|
349 | (report-error |
---|
350 | (jvm:compile-defun nil lambda-expression |
---|
351 | *compile-file-environment* |
---|
352 | classfile f nil)))) |
---|
353 | (compiled-function (verify-load classfile))) |
---|
354 | (declare (ignore result)) |
---|
355 | (cond |
---|
356 | (compiled-function |
---|
357 | (setf (getf tail key) |
---|
358 | `(sys::get-fasl-function *fasl-loader* |
---|
359 | ,saved-class-number))) |
---|
360 | (t |
---|
361 | ;; FIXME This should be a warning or error of some sort... |
---|
362 | (format *error-output* "; Unable to compile method~%")))))))))) |
---|
363 | (when compile-time-too |
---|
364 | (let* ((copy-form (copy-tree form)) |
---|
365 | ;; ### Ideally, the precompiler would leave the forms alone |
---|
366 | ;; and copy them where required, instead of forcing us to |
---|
367 | ;; do a deep copy in advance |
---|
368 | (precompiled-form (precompiler:precompile-form copy-form nil |
---|
369 | *compile-file-environment*))) |
---|
370 | (eval precompiled-form))) |
---|
371 | (convert-ensure-method form :function) |
---|
372 | (convert-ensure-method form :fast-function)) |
---|
373 | (precompiler:precompile-form form nil *compile-file-environment*)) |
---|
374 | |
---|
375 | (declaim (ftype (function (t t t) t) process-toplevel-defvar/defparameter)) |
---|
376 | (defun process-toplevel-defvar/defparameter (form stream compile-time-too) |
---|
377 | (declare (ignore stream)) |
---|
378 | (note-toplevel-form form) |
---|
379 | (if compile-time-too |
---|
380 | (eval form) |
---|
381 | ;; "If a DEFVAR or DEFPARAMETER form appears as a top level form, |
---|
382 | ;; the compiler must recognize that the name has been proclaimed |
---|
383 | ;; special. However, it must neither evaluate the initial-value |
---|
384 | ;; form nor assign the dynamic variable named NAME at compile |
---|
385 | ;; time." |
---|
386 | (let ((name (second form))) |
---|
387 | (%defvar name))) |
---|
388 | (let ((name (second form)) |
---|
389 | (initial-value (third form))) |
---|
390 | ;;; emit make-array when initial-value is a specialized vector |
---|
391 | (when (and (atom initial-value) |
---|
392 | (arrayp initial-value) |
---|
393 | (= (length (array-dimensions initial-value)) 1) |
---|
394 | (not (eq (array-element-type initial-value) t))) |
---|
395 | (setf (third form) |
---|
396 | `(common-lisp:make-array |
---|
397 | ',(array-dimensions initial-value) |
---|
398 | :element-type ',(array-element-type initial-value) |
---|
399 | :initial-contents ',(coerce initial-value 'list)))) |
---|
400 | `(progn |
---|
401 | (sys:put ',name 'sys::source |
---|
402 | (cl:cons |
---|
403 | (list :variable ,(namestring *source*) ,*source-position*) |
---|
404 | (cl:get ',name 'sys::source nil))) |
---|
405 | ,form))) |
---|
406 | |
---|
407 | |
---|
408 | (declaim (ftype (function (t t t) t) process-toplevel-defpackage/in-package)) |
---|
409 | (defun process-toplevel-defpackage/in-package (form stream compile-time-too) |
---|
410 | (declare (ignore stream compile-time-too)) |
---|
411 | (note-toplevel-form form) |
---|
412 | (let ((defpackage-name (and (eq (car form) 'defpackage) (intern (string (second form)) :keyword))) ) |
---|
413 | (setf form |
---|
414 | (precompiler:precompile-form form nil *compile-file-environment*)) |
---|
415 | (eval form) |
---|
416 | ;; Force package prefix to be used when dumping form. |
---|
417 | (let ((*package* +keyword-package+)) |
---|
418 | (output-form form)) |
---|
419 | ;; a bit ugly here. Since we precompile, and added |
---|
420 | ;; record-source-information we need to know where it is. |
---|
421 | |
---|
422 | ;; The defpackage is at top, so we know where the name is (though |
---|
423 | ;; it is a string by now) (if it is a defpackage) |
---|
424 | (if defpackage-name |
---|
425 | `(sys:put ,defpackage-name 'sys::source |
---|
426 | (cl:cons '(:package ,(namestring *source*) ,*source-position*) |
---|
427 | (cl:get ,defpackage-name 'sys::source nil))) |
---|
428 | nil))) |
---|
429 | |
---|
430 | (declaim (ftype (function (t t t) t) process-toplevel-declare)) |
---|
431 | (defun process-toplevel-declare (form stream compile-time-too) |
---|
432 | (declare (ignore stream compile-time-too)) |
---|
433 | (compiler-style-warn "Misplaced declaration: ~S" form) |
---|
434 | nil) |
---|
435 | |
---|
436 | (declaim (ftype (function (t t t) t) process-toplevel-progn)) |
---|
437 | (defun process-toplevel-progn (form stream compile-time-too) |
---|
438 | (process-progn (cdr form) stream compile-time-too) |
---|
439 | nil) |
---|
440 | |
---|
441 | (declaim (ftype (function (t t t) t) process-toplevel-deftype)) |
---|
442 | (defun process-toplevel-deftype (form stream compile-time-too) |
---|
443 | (declare (ignore stream compile-time-too)) |
---|
444 | (note-toplevel-form form) |
---|
445 | (eval form) |
---|
446 | `(progn |
---|
447 | (sys:put ',(second form) 'sys::source |
---|
448 | (cl:cons '(,(second form) ,(namestring *source*) ,*source-position*) |
---|
449 | (cl:get ',(second form) 'sys::source nil))) |
---|
450 | ,form)) |
---|
451 | |
---|
452 | (declaim (ftype (function (t t t) t) process-toplevel-eval-when)) |
---|
453 | (defun process-toplevel-eval-when (form stream compile-time-too) |
---|
454 | (flet ((parse-eval-when-situations (situations) |
---|
455 | "Parse an EVAL-WHEN situations list, returning three flags, |
---|
456 | (VALUES COMPILE-TOPLEVEL LOAD-TOPLEVEL EXECUTE), indicating |
---|
457 | the types of situations present in the list." |
---|
458 | ; Adapted from SBCL. |
---|
459 | (when (or (not (listp situations)) |
---|
460 | (set-difference situations |
---|
461 | '(:compile-toplevel |
---|
462 | compile |
---|
463 | :load-toplevel |
---|
464 | load |
---|
465 | :execute |
---|
466 | eval))) |
---|
467 | (error "Bad EVAL-WHEN situation list: ~S." situations)) |
---|
468 | (values (intersection '(:compile-toplevel compile) situations) |
---|
469 | (intersection '(:load-toplevel load) situations) |
---|
470 | (intersection '(:execute eval) situations)))) |
---|
471 | (multiple-value-bind (ct lt e) |
---|
472 | (parse-eval-when-situations (cadr form)) |
---|
473 | (let ((new-compile-time-too (or ct (and compile-time-too e))) |
---|
474 | (body (cddr form))) |
---|
475 | (if lt |
---|
476 | (process-progn body stream new-compile-time-too) |
---|
477 | (when new-compile-time-too |
---|
478 | (eval `(progn ,@body))))))) |
---|
479 | nil) |
---|
480 | |
---|
481 | |
---|
482 | (declaim (ftype (function (t t t) t) process-toplevel-defmethod/defgeneric)) |
---|
483 | (defun process-toplevel-defmethod/defgeneric (form stream compile-time-too) |
---|
484 | (note-toplevel-form form) |
---|
485 | (note-name-defined (second form)) |
---|
486 | (push (second form) *toplevel-functions*) |
---|
487 | (when (and (consp (second form)) |
---|
488 | (eq 'setf (first (second form)))) |
---|
489 | (push (second (second form)) |
---|
490 | *toplevel-setf-functions*)) |
---|
491 | (let ((*compile-print* nil)) |
---|
492 | (process-toplevel-form (macroexpand-1 form *compile-file-environment*) |
---|
493 | stream compile-time-too)) |
---|
494 | (let* ((sym (if (consp (second form)) (second (second form)) (second form)))) |
---|
495 | (when (eq (car form) 'defgeneric) |
---|
496 | `(progn |
---|
497 | (sys:put ',sym 'sys::source |
---|
498 | (cl:cons '((:generic-function ,(second form)) |
---|
499 | ,(namestring *source*) ,*source-position*) |
---|
500 | (cl:get ',sym 'sys::source nil))) |
---|
501 | ,@(loop for method-form in (cdddr form) |
---|
502 | when (eq (car method-form) :method) |
---|
503 | collect |
---|
504 | (multiple-value-bind (function-name qualifiers lambda-list specializers documentation declarations body) |
---|
505 | (mop::parse-defmethod `(,(second form) ,@(rest method-form))) |
---|
506 | ;;; FIXME: style points for refactoring double backquote to "normal" form |
---|
507 | `(sys:put ',sym 'sys::source |
---|
508 | (cl:cons `((:method ,',sym ,',qualifiers ,',specializers) |
---|
509 | ,,(namestring *source*) ,,*source-position*) |
---|
510 | (cl:get ',sym 'sys::source nil))))))))) |
---|
511 | |
---|
512 | |
---|
513 | (declaim (ftype (function (t t t) t) process-toplevel-locally)) |
---|
514 | (defun process-toplevel-locally (form stream compile-time-too) |
---|
515 | (jvm::with-saved-compiler-policy |
---|
516 | (multiple-value-bind (forms decls) |
---|
517 | (parse-body (cdr form) nil) |
---|
518 | (process-optimization-declarations decls) |
---|
519 | (let* ((jvm::*visible-variables* jvm::*visible-variables*) |
---|
520 | (specials (jvm::process-declarations-for-vars (cdr form) |
---|
521 | nil nil))) |
---|
522 | (dolist (special specials) |
---|
523 | (push special jvm::*visible-variables*)) |
---|
524 | (process-progn forms stream compile-time-too)))) |
---|
525 | nil) |
---|
526 | |
---|
527 | (declaim (ftype (function (t t t) t) process-toplevel-defmacro)) |
---|
528 | (defun process-toplevel-defmacro (form stream compile-time-too) |
---|
529 | (declare (ignore stream compile-time-too)) |
---|
530 | (note-toplevel-form form) |
---|
531 | (let ((name (second form))) |
---|
532 | (eval form) |
---|
533 | (push name *toplevel-macros*) |
---|
534 | (let* ((expr (function-lambda-expression (macro-function name))) |
---|
535 | (saved-class-number *class-number*) |
---|
536 | (classfile (next-classfile))) |
---|
537 | (with-open-file |
---|
538 | (f classfile |
---|
539 | :direction :output |
---|
540 | :element-type '(unsigned-byte 8) |
---|
541 | :if-exists :supersede) |
---|
542 | (ignore-errors |
---|
543 | (jvm:compile-defun nil expr *compile-file-environment* |
---|
544 | classfile f nil))) |
---|
545 | (when (null (verify-load classfile)) |
---|
546 | ;; FIXME error or warning |
---|
547 | (format *error-output* "; Unable to compile macro ~A~%" name) |
---|
548 | (return-from process-toplevel-defmacro form)) |
---|
549 | |
---|
550 | (if (special-operator-p name) |
---|
551 | `(sys:put ',name 'macroexpand-macro |
---|
552 | (sys:make-macro ',name |
---|
553 | (sys::get-fasl-function *fasl-loader* |
---|
554 | ,saved-class-number))) |
---|
555 | `(progn |
---|
556 | (sys:put ',name 'sys::source |
---|
557 | (cl:cons '(:macro ,(namestring *source*) ,*source-position*) |
---|
558 | (cl:get ',name 'sys::source nil))) |
---|
559 | (sys:fset ',name |
---|
560 | (sys:make-macro ',name |
---|
561 | (sys::get-fasl-function *fasl-loader* |
---|
562 | ,saved-class-number)) |
---|
563 | ,*source-position* |
---|
564 | ',(third form) |
---|
565 | ,(%documentation name 'cl:function))))))) |
---|
566 | |
---|
567 | (declaim (ftype (function (t t t) t) process-toplevel-defun)) |
---|
568 | (defun process-toplevel-defun (form stream compile-time-too) |
---|
569 | (declare (ignore stream)) |
---|
570 | (note-toplevel-form form) |
---|
571 | (let* ((name (second form)) |
---|
572 | (block-name (fdefinition-block-name name)) |
---|
573 | (lambda-list (third form)) |
---|
574 | (body (nthcdr 3 form))) |
---|
575 | (jvm::with-saved-compiler-policy |
---|
576 | (multiple-value-bind (body decls doc) |
---|
577 | (parse-body body) |
---|
578 | (let* ((expr `(lambda ,lambda-list |
---|
579 | ,@decls (block ,block-name ,@body))) |
---|
580 | (saved-class-number *class-number*) |
---|
581 | (classfile (next-classfile)) |
---|
582 | (internal-compiler-errors nil) |
---|
583 | (result (with-open-file |
---|
584 | (f classfile |
---|
585 | :direction :output |
---|
586 | :element-type '(unsigned-byte 8) |
---|
587 | :if-exists :supersede) |
---|
588 | (handler-bind |
---|
589 | ((internal-compiler-error |
---|
590 | #'(lambda (e) |
---|
591 | (push e internal-compiler-errors) |
---|
592 | (continue)))) |
---|
593 | (report-error |
---|
594 | (jvm:compile-defun name expr *compile-file-environment* |
---|
595 | classfile f nil))))) |
---|
596 | (compiled-function (if (not internal-compiler-errors) |
---|
597 | (verify-load classfile) |
---|
598 | nil))) |
---|
599 | (declare (ignore result)) |
---|
600 | (cond |
---|
601 | ((and (not internal-compiler-errors) |
---|
602 | compiled-function) |
---|
603 | (when compile-time-too |
---|
604 | (eval form)) |
---|
605 | (let ((sym (if (consp name) (second name) name))) |
---|
606 | (setf form |
---|
607 | `(progn |
---|
608 | (sys:put ',sym 'sys::source |
---|
609 | (cl:cons '((:function ,name) |
---|
610 | ,(namestring *source*) ,*source-position*) |
---|
611 | (cl:get ',sym 'sys::source nil))) |
---|
612 | (sys:fset ',name |
---|
613 | (sys::get-fasl-function *fasl-loader* |
---|
614 | ,saved-class-number) |
---|
615 | ,*source-position* |
---|
616 | ',lambda-list |
---|
617 | ,doc))))) |
---|
618 | (t |
---|
619 | (compiler-warn "Unable to compile function ~A. Using interpreted form instead.~%" name) |
---|
620 | (when internal-compiler-errors |
---|
621 | (dolist (e internal-compiler-errors) |
---|
622 | (format *error-output* |
---|
623 | "; ~A~%" e))) |
---|
624 | (let ((precompiled-function |
---|
625 | (precompiler:precompile-form expr nil |
---|
626 | *compile-file-environment*))) |
---|
627 | (setf form |
---|
628 | `(sys:fset ',name |
---|
629 | ,precompiled-function |
---|
630 | ,*source-position* |
---|
631 | ',lambda-list |
---|
632 | ,doc))) |
---|
633 | (when compile-time-too |
---|
634 | (eval form))))) |
---|
635 | (when (and (symbolp name) (eq (get name '%inline) 'INLINE)) |
---|
636 | ;; FIXME Need to support SETF functions too! |
---|
637 | (setf (inline-expansion name) |
---|
638 | (jvm::generate-inline-expansion block-name |
---|
639 | lambda-list |
---|
640 | (append decls body))) |
---|
641 | (output-form `(cl:setf (inline-expansion ',name) |
---|
642 | ',(inline-expansion name)))))) |
---|
643 | (push name jvm::*functions-defined-in-current-file*) |
---|
644 | (note-name-defined name) |
---|
645 | (push name *toplevel-functions*) |
---|
646 | (when (and (consp name) |
---|
647 | (or |
---|
648 | (eq 'setf (first name)) |
---|
649 | (eq 'cl:setf (first name)))) |
---|
650 | (push (second name) *toplevel-setf-functions*)) |
---|
651 | ;; If NAME is not fbound, provide a dummy definition so that |
---|
652 | ;; getSymbolFunctionOrDie() will succeed when we try to verify that |
---|
653 | ;; functions defined later in the same file can be loaded correctly. |
---|
654 | (unless (fboundp name) |
---|
655 | (setf (fdefinition name) #'dummy) |
---|
656 | (push name *fbound-names*))) |
---|
657 | form) |
---|
658 | |
---|
659 | |
---|
660 | ;; toplevel handlers |
---|
661 | ;; each toplevel handler takes a form and stream as input |
---|
662 | |
---|
663 | (defun install-toplevel-handler (symbol handler) |
---|
664 | (setf (get symbol 'toplevel-handler) handler)) |
---|
665 | |
---|
666 | (dolist (pair '((COMPILER-DEFSTRUCT precompile-toplevel-form) |
---|
667 | (DECLARE process-toplevel-declare) |
---|
668 | (DEFCONSTANT process-toplevel-defconstant) |
---|
669 | (DEFGENERIC process-toplevel-defmethod/defgeneric) |
---|
670 | (DEFMACRO process-toplevel-defmacro) |
---|
671 | (DEFMETHOD process-toplevel-defmethod/defgeneric) |
---|
672 | (DEFPACKAGE process-toplevel-defpackage/in-package) |
---|
673 | (DEFPARAMETER process-toplevel-defvar/defparameter) |
---|
674 | (DEFTYPE process-toplevel-deftype) |
---|
675 | (DEFUN process-toplevel-defun) |
---|
676 | (DEFVAR process-toplevel-defvar/defparameter) |
---|
677 | (EVAL-WHEN process-toplevel-eval-when) |
---|
678 | (EXPORT process-toplevel-export) |
---|
679 | (IMPORT process-toplevel-import) |
---|
680 | (IN-PACKAGE process-toplevel-defpackage/in-package) |
---|
681 | (LOCALLY process-toplevel-locally) |
---|
682 | (MACROLET process-toplevel-macrolet) |
---|
683 | (PROCLAIM precompile-toplevel-form) |
---|
684 | (PROGN process-toplevel-progn) |
---|
685 | (PROVIDE precompile-toplevel-form) |
---|
686 | (PUT precompile-toplevel-form) |
---|
687 | (QUOTE process-toplevel-quote) |
---|
688 | (REQUIRE precompile-toplevel-form) |
---|
689 | (SHADOW precompile-toplevel-form) |
---|
690 | (%SET-FDEFINITION precompile-toplevel-form) |
---|
691 | (MOP::ENSURE-METHOD process-toplevel-mop.ensure-method) |
---|
692 | (record-source-information-for-type process-record-source-information))) |
---|
693 | (install-toplevel-handler (car pair) (cadr pair))) |
---|
694 | |
---|
695 | (declaim (ftype (function (t stream t) t) process-toplevel-form)) |
---|
696 | (defun process-toplevel-form (form stream compile-time-too) |
---|
697 | (unless (atom form) |
---|
698 | (let* ((operator (%car form)) |
---|
699 | (handler (get operator 'toplevel-handler))) |
---|
700 | (when handler |
---|
701 | (let ((out-form (funcall handler form stream compile-time-too))) |
---|
702 | (when out-form |
---|
703 | (output-form out-form))) |
---|
704 | (return-from process-toplevel-form)) |
---|
705 | (when (and (symbolp operator) |
---|
706 | (macro-function operator *compile-file-environment*)) |
---|
707 | (when (eq operator 'define-setf-expander) |
---|
708 | (push (second form) *toplevel-setf-expanders*)) |
---|
709 | (when (and (eq operator 'defsetf) |
---|
710 | (consp (third form))) ;; long form of DEFSETF |
---|
711 | (push (second form) *toplevel-setf-expanders*)) |
---|
712 | (note-toplevel-form form) |
---|
713 | ;; Note that we want MACROEXPAND-1 and not MACROEXPAND here, in |
---|
714 | ;; case the form being expanded expands into something that needs |
---|
715 | ;; special handling by PROCESS-TOPLEVEL-FORM (e.g. DEFMACRO). |
---|
716 | (let ((*compile-print* nil)) |
---|
717 | (process-toplevel-form (macroexpand-1 form *compile-file-environment*) |
---|
718 | stream compile-time-too)) |
---|
719 | (return-from process-toplevel-form)) |
---|
720 | (cond |
---|
721 | ((and (symbolp operator) |
---|
722 | (not (special-operator-p operator)) |
---|
723 | (null (cdr form))) |
---|
724 | (setf form (precompiler:precompile-form form nil |
---|
725 | *compile-file-environment*))) |
---|
726 | (t |
---|
727 | (note-toplevel-form form) |
---|
728 | (setf form (convert-toplevel-form form nil))))) |
---|
729 | (when (consp form) |
---|
730 | (output-form form))) |
---|
731 | ;; Make sure the compiled-function loader knows where |
---|
732 | ;; to load the compiled functions. Note that this trickery |
---|
733 | ;; was already used in verify-load before I used it, |
---|
734 | ;; however, binding *load-truename* isn't fully compliant, I think. |
---|
735 | (when compile-time-too |
---|
736 | (let ((*load-truename* *output-file-pathname*) |
---|
737 | (*fasl-loader* (make-fasl-class-loader |
---|
738 | (concatenate 'string |
---|
739 | "org.armedbear.lisp." (base-classname))))) |
---|
740 | (eval form)))) |
---|
741 | |
---|
742 | (defun populate-zip-fasl (output-file) |
---|
743 | (let* ((type ;; Don't use ".zip", it'll result in an extension with |
---|
744 | ;; a dot, which is rejected by NAMESTRING |
---|
745 | (%format nil "~A~A" (pathname-type output-file) "-zip")) |
---|
746 | (output-file (if (logical-pathname-p output-file) |
---|
747 | (translate-logical-pathname output-file) |
---|
748 | output-file)) |
---|
749 | (zipfile |
---|
750 | (if (find :windows *features*) |
---|
751 | (make-pathname :defaults output-file :type type) |
---|
752 | (make-pathname :defaults output-file :type type |
---|
753 | :device :unspecific))) |
---|
754 | (pathnames nil) |
---|
755 | (fasl-loader (make-pathname :defaults output-file |
---|
756 | :name (fasl-loader-classname) |
---|
757 | :type *compile-file-class-extension*))) |
---|
758 | (when (probe-file fasl-loader) |
---|
759 | (push fasl-loader pathnames)) |
---|
760 | (dotimes (i *class-number*) |
---|
761 | (let ((truename (probe-file (compute-classfile (1+ i))))) |
---|
762 | (when truename |
---|
763 | (push truename pathnames) |
---|
764 | ;;; XXX it would be better to just use the recorded number |
---|
765 | ;;; of class constants, but probing for the first at least |
---|
766 | ;;; makes this subjectively bearable. |
---|
767 | (when (probe-file |
---|
768 | (make-pathname :name (format nil "~A_0" |
---|
769 | (pathname-name truename)) |
---|
770 | :type "clc" |
---|
771 | :defaults truename)) |
---|
772 | (dolist (resource (directory |
---|
773 | (make-pathname :name (format nil "~A_*" |
---|
774 | (pathname-name truename)) |
---|
775 | :type "clc" |
---|
776 | :defaults truename))) |
---|
777 | (push resource pathnames)))))) |
---|
778 | (setf pathnames (nreverse (remove nil pathnames))) |
---|
779 | (let ((load-file (make-pathname :defaults output-file |
---|
780 | :name "__loader__" |
---|
781 | :type "_"))) |
---|
782 | (rename-file output-file load-file) |
---|
783 | (push load-file pathnames)) |
---|
784 | (zip zipfile pathnames) |
---|
785 | (dolist (pathname pathnames) |
---|
786 | (ignore-errors (delete-file pathname))) |
---|
787 | (rename-file zipfile output-file))) |
---|
788 | |
---|
789 | (defun write-fasl-prologue (stream in-package) |
---|
790 | "Write the forms that form the fasl to STREAM. |
---|
791 | |
---|
792 | The last form will use IN-PACKAGE to set the *package* to its value when |
---|
793 | COMPILE-FILE was invoked." |
---|
794 | (let ((out stream) |
---|
795 | (*package* (find-package :keyword))) |
---|
796 | ;; write header |
---|
797 | (write "; -*- Mode: Lisp -*-" :escape nil :stream out) |
---|
798 | (%stream-terpri out) |
---|
799 | (write (list 'sys:init-fasl :version *fasl-version*) :stream out) |
---|
800 | (%stream-terpri out) |
---|
801 | (write (list 'cl:setq 'sys:*source* *compile-file-truename*) :stream out) |
---|
802 | (%stream-terpri out) |
---|
803 | |
---|
804 | ;; Note: Beyond this point, you can't use DUMP-FORM, |
---|
805 | ;; because the list of uninterned symbols has been fixed now. |
---|
806 | (when *fasl-uninterned-symbols* |
---|
807 | (write (list 'cl:setq 'sys::*fasl-uninterned-symbols* |
---|
808 | (coerce (mapcar #'car (nreverse *fasl-uninterned-symbols*)) |
---|
809 | 'vector)) |
---|
810 | :stream out :length nil)) |
---|
811 | (%stream-terpri out) |
---|
812 | |
---|
813 | (when (> *class-number* 0) |
---|
814 | (write (list 'cl:setq 'sys:*fasl-loader* |
---|
815 | `(sys::make-fasl-class-loader |
---|
816 | ,(concatenate 'string "org.armedbear.lisp." |
---|
817 | (base-classname)))) |
---|
818 | :stream out)) |
---|
819 | (%stream-terpri out) |
---|
820 | |
---|
821 | (write `(in-package ,(package-name in-package)) |
---|
822 | :stream out) |
---|
823 | (%stream-terpri out))) |
---|
824 | |
---|
825 | (defvar *binary-fasls* nil) |
---|
826 | (defvar *forms-for-output* nil) |
---|
827 | (defvar *fasl-stream* nil) |
---|
828 | |
---|
829 | (defun compile-from-stream (in output-file temp-file temp-file2 |
---|
830 | extract-toplevel-funcs-and-macros |
---|
831 | functions-file macros-file exports-file |
---|
832 | setf-functions-file setf-expanders-file) |
---|
833 | (let* ((*compile-file-pathname* (make-pathname :defaults (pathname in) |
---|
834 | :version nil)) |
---|
835 | (*compile-file-truename* (make-pathname :defaults (truename in) |
---|
836 | :version nil)) |
---|
837 | (*source* *compile-file-truename*) |
---|
838 | (*class-number* 0) |
---|
839 | (namestring (namestring *compile-file-truename*)) |
---|
840 | (start (get-internal-real-time)) |
---|
841 | *fasl-uninterned-symbols* |
---|
842 | (warnings-p nil) |
---|
843 | (in-package *package*) |
---|
844 | (failure-p nil)) |
---|
845 | (when *compile-verbose* |
---|
846 | (format t "; Compiling ~A ...~%" namestring)) |
---|
847 | (with-compilation-unit () |
---|
848 | (with-open-file (out temp-file |
---|
849 | :direction :output :if-exists :supersede |
---|
850 | :external-format *fasl-external-format*) |
---|
851 | (let ((*readtable* *readtable*) |
---|
852 | (*read-default-float-format* *read-default-float-format*) |
---|
853 | (*read-base* *read-base*) |
---|
854 | (*package* *package*) |
---|
855 | (jvm::*functions-defined-in-current-file* '()) |
---|
856 | (*fbound-names* '()) |
---|
857 | (*fasl-stream* out) |
---|
858 | *forms-for-output*) |
---|
859 | (jvm::with-saved-compiler-policy |
---|
860 | (jvm::with-file-compilation |
---|
861 | (handler-bind |
---|
862 | ((style-warning |
---|
863 | #'(lambda (c) |
---|
864 | (setf warnings-p t) |
---|
865 | ;; let outer handlers do their thing |
---|
866 | (signal c) |
---|
867 | ;; prevent the next handler |
---|
868 | ;; from running: we're a |
---|
869 | ;; WARNING subclass |
---|
870 | (continue))) |
---|
871 | ((or warning compiler-error) |
---|
872 | #'(lambda (c) |
---|
873 | (declare (ignore c)) |
---|
874 | (setf warnings-p t |
---|
875 | failure-p t)))) |
---|
876 | (loop |
---|
877 | (let* ((*source-position* (file-position in)) |
---|
878 | (jvm::*source-line-number* (stream-line-number in)) |
---|
879 | (form (read in nil in)) |
---|
880 | (*compiler-error-context* form)) |
---|
881 | (when (eq form in) |
---|
882 | (return)) |
---|
883 | (cond |
---|
884 | ((>= (length (format nil "~a" form)) 65536) |
---|
885 | ;; Following the solution propose here: |
---|
886 | ;; see https://github.com/armedbear/abcl/issues/246#issuecomment-698854437 |
---|
887 | ;; just include the offending interpreted form in the loader |
---|
888 | ;; using it instead of the compiled representation |
---|
889 | (diag "Falling back to interpreted version of top-level form longer ~ |
---|
890 | than 65535 bytes") |
---|
891 | (write (ext:macroexpand-all form *compile-file-environment*) |
---|
892 | :stream out)) |
---|
893 | (t |
---|
894 | (process-toplevel-form form out nil)))))) |
---|
895 | (finalize-fasl-output) |
---|
896 | (dolist (name *fbound-names*) |
---|
897 | (fmakunbound name))))))) |
---|
898 | (when extract-toplevel-funcs-and-macros |
---|
899 | (setf *toplevel-functions* |
---|
900 | (remove-if-not (lambda (func-name) |
---|
901 | (if (symbolp func-name) |
---|
902 | (symbol-package func-name) |
---|
903 | T)) |
---|
904 | (remove-duplicates |
---|
905 | *toplevel-functions*))) |
---|
906 | (when *toplevel-functions* |
---|
907 | (with-open-file (f-out functions-file |
---|
908 | :direction :output |
---|
909 | :if-does-not-exist :create |
---|
910 | :if-exists :supersede) |
---|
911 | |
---|
912 | (let ((*package* (find-package :keyword))) |
---|
913 | (write *toplevel-functions* :stream f-out)))) |
---|
914 | (setf *toplevel-macros* |
---|
915 | (remove-if-not (lambda (mac-name) |
---|
916 | (if (symbolp mac-name) |
---|
917 | (symbol-package mac-name) |
---|
918 | T)) |
---|
919 | (remove-duplicates *toplevel-macros*))) |
---|
920 | (when *toplevel-macros* |
---|
921 | (with-open-file (m-out macros-file |
---|
922 | :direction :output |
---|
923 | :if-does-not-exist :create |
---|
924 | :if-exists :supersede) |
---|
925 | (let ((*package* (find-package :keyword))) |
---|
926 | (write *toplevel-macros* :stream m-out)))) |
---|
927 | (setf *toplevel-exports* |
---|
928 | (remove-if-not (lambda (sym) |
---|
929 | (if (symbolp sym) |
---|
930 | (symbol-package sym) |
---|
931 | T)) |
---|
932 | (remove-duplicates *toplevel-exports*))) |
---|
933 | (when *toplevel-exports* |
---|
934 | (with-open-file (e-out exports-file |
---|
935 | :direction :output |
---|
936 | :if-does-not-exist :create |
---|
937 | :if-exists :supersede) |
---|
938 | (let ((*package* (find-package :keyword))) |
---|
939 | (write *toplevel-exports* :stream e-out)))) |
---|
940 | (setf *toplevel-setf-functions* |
---|
941 | (remove-if-not (lambda (sym) |
---|
942 | (if (symbolp sym) |
---|
943 | (symbol-package sym) |
---|
944 | T)) |
---|
945 | (remove-duplicates *toplevel-setf-functions*))) |
---|
946 | (when *toplevel-setf-functions* |
---|
947 | (with-open-file (e-out setf-functions-file |
---|
948 | :direction :output |
---|
949 | :if-does-not-exist :create |
---|
950 | :if-exists :supersede) |
---|
951 | (let ((*package* (find-package :keyword))) |
---|
952 | (write *toplevel-setf-functions* :stream e-out)))) |
---|
953 | (setf *toplevel-setf-expanders* |
---|
954 | (remove-if-not (lambda (sym) |
---|
955 | (if (symbolp sym) |
---|
956 | (symbol-package sym) |
---|
957 | T)) |
---|
958 | (remove-duplicates *toplevel-setf-expanders*))) |
---|
959 | (when *toplevel-setf-expanders* |
---|
960 | (with-open-file (e-out setf-expanders-file |
---|
961 | :direction :output |
---|
962 | :if-does-not-exist :create |
---|
963 | :if-exists :supersede) |
---|
964 | (let ((*package* (find-package :keyword))) |
---|
965 | (write *toplevel-setf-expanders* :stream e-out))))) |
---|
966 | (with-open-file (in temp-file :direction :input :external-format *fasl-external-format*) |
---|
967 | (with-open-file (out temp-file2 :direction :output |
---|
968 | :if-does-not-exist :create |
---|
969 | :if-exists :supersede |
---|
970 | :external-format *fasl-external-format*) |
---|
971 | (let ((*package* (find-package :keyword)) |
---|
972 | (*print-fasl* t) |
---|
973 | (*print-array* t) |
---|
974 | (*print-base* 10) |
---|
975 | (*print-case* :upcase) |
---|
976 | (*print-circle* nil) |
---|
977 | (*print-escape* t) |
---|
978 | (*print-gensym* t) |
---|
979 | (*print-length* nil) |
---|
980 | (*print-level* nil) |
---|
981 | (*print-lines* nil) |
---|
982 | (*print-pretty* nil) |
---|
983 | (*print-radix* nil) |
---|
984 | (*print-readably* t) |
---|
985 | (*print-right-margin* nil) |
---|
986 | (*print-structure* t) |
---|
987 | |
---|
988 | ;; make sure to write all floats with their exponent marker: |
---|
989 | ;; the dump-time default may not be the same at load-time |
---|
990 | |
---|
991 | (*read-default-float-format* nil)) |
---|
992 | |
---|
993 | ;; these values are also bound by WITH-STANDARD-IO-SYNTAX, |
---|
994 | ;; but not used by our reader/printer, so don't bind them, |
---|
995 | ;; for efficiency reasons. |
---|
996 | ;; (*read-eval* t) |
---|
997 | ;; (*read-suppress* nil) |
---|
998 | ;; (*print-miser-width* nil) |
---|
999 | ;; (*print-pprint-dispatch* (copy-pprint-dispatch nil)) |
---|
1000 | ;; (*read-base* 10) |
---|
1001 | ;; (*read-default-float-format* 'single-float) |
---|
1002 | ;; (*readtable* (copy-readtable nil)) |
---|
1003 | |
---|
1004 | (write-fasl-prologue out in-package) |
---|
1005 | ;; copy remaining content |
---|
1006 | (loop for line = (read-line in nil :eof) |
---|
1007 | while (not (eq line :eof)) |
---|
1008 | do (write-line line out))))) |
---|
1009 | (delete-file temp-file) |
---|
1010 | (when (subtypep (type-of output-file) 'jar-pathname) |
---|
1011 | (remove-zip-cache-entry output-file)) |
---|
1012 | (rename-file temp-file2 output-file) |
---|
1013 | |
---|
1014 | (when *compile-file-zip* |
---|
1015 | (populate-zip-fasl output-file)) |
---|
1016 | |
---|
1017 | (when *compile-verbose* |
---|
1018 | (format t "~&; Wrote ~A (~A seconds)~%" |
---|
1019 | (namestring output-file) |
---|
1020 | (/ (- (get-internal-real-time) start) 1000.0))) |
---|
1021 | (values (truename output-file) warnings-p failure-p))) |
---|
1022 | |
---|
1023 | (defun compile-file (input-file |
---|
1024 | &key |
---|
1025 | output-file |
---|
1026 | ((:verbose *compile-verbose*) *compile-verbose*) |
---|
1027 | ((:print *compile-print*) *compile-print*) |
---|
1028 | (extract-toplevel-funcs-and-macros nil) |
---|
1029 | (external-format :utf-8)) |
---|
1030 | (flet ((pathname-with-type (pathname type &optional suffix) |
---|
1031 | (when suffix |
---|
1032 | (setq type (concatenate 'string type suffix))) |
---|
1033 | (make-pathname :type type :defaults pathname))) |
---|
1034 | (unless (or (and (probe-file input-file) |
---|
1035 | (not (file-directory-p input-file))) |
---|
1036 | (pathname-type input-file)) |
---|
1037 | (let ((pathname (pathname-with-type input-file "lisp"))) |
---|
1038 | (when (probe-file pathname) |
---|
1039 | (setf input-file pathname)))) |
---|
1040 | (setf output-file |
---|
1041 | (compile-file-pathname input-file :output-file output-file)) |
---|
1042 | (let* ((*output-file-pathname* output-file) |
---|
1043 | (type (pathname-type output-file)) |
---|
1044 | (temp-file (pathname-with-type output-file type "-tmp")) |
---|
1045 | (temp-file2 (pathname-with-type output-file type "-tmp2")) |
---|
1046 | (functions-file (pathname-with-type output-file "funcs")) |
---|
1047 | (macros-file (pathname-with-type output-file "macs")) |
---|
1048 | (exports-file (pathname-with-type output-file "exps")) |
---|
1049 | (setf-functions-file (pathname-with-type output-file "setf-functions")) |
---|
1050 | (setf-expanders-file (pathname-with-type output-file "setf-expanders")) |
---|
1051 | *toplevel-functions* |
---|
1052 | *toplevel-macros* |
---|
1053 | *toplevel-exports* |
---|
1054 | *toplevel-setf-functions* |
---|
1055 | *toplevel-setf-expanders*) |
---|
1056 | (with-open-file (in input-file :direction :input :external-format external-format) |
---|
1057 | (multiple-value-bind (output-file-truename warnings-p failure-p) |
---|
1058 | (compile-from-stream in output-file temp-file temp-file2 |
---|
1059 | extract-toplevel-funcs-and-macros |
---|
1060 | functions-file macros-file exports-file |
---|
1061 | setf-functions-file setf-expanders-file) |
---|
1062 | (values (truename output-file) warnings-p failure-p)))))) |
---|
1063 | |
---|
1064 | (defun compile-file-if-needed (input-file &rest allargs &key force-compile |
---|
1065 | &allow-other-keys) |
---|
1066 | (setf input-file (truename input-file)) |
---|
1067 | (cond (force-compile |
---|
1068 | (remf allargs :force-compile) |
---|
1069 | (apply 'compile-file input-file allargs)) |
---|
1070 | (t |
---|
1071 | (let* ((source-write-time (file-write-date input-file)) |
---|
1072 | (output-file (or (getf allargs :output-file) |
---|
1073 | (compile-file-pathname input-file))) |
---|
1074 | (target-write-time (and (probe-file output-file) |
---|
1075 | (file-write-date output-file)))) |
---|
1076 | (if (or (null target-write-time) |
---|
1077 | (<= target-write-time source-write-time)) |
---|
1078 | (apply #'compile-file input-file allargs) |
---|
1079 | output-file))))) |
---|
1080 | |
---|
1081 | (provide 'compile-file) |
---|