improved cm

svn: r11301

original commit: dd870c3d3020d7711371eafa7f6bb9c37b6f7fc9
This commit is contained in:
Eli Barzilay 2008-08-18 21:46:16 +00:00
parent 4aa143396b
commit fe4b75e598

View File

@ -1,4 +1,4 @@
(module cm scheme/base #lang scheme/base
(require syntax/modcode (require syntax/modcode
syntax/modresolve syntax/modresolve
setup/main-collects setup/main-collects
@ -18,68 +18,58 @@
(define trust-existing-zos (make-parameter #f)) (define trust-existing-zos (make-parameter #f))
(define (trace-printf fmt . args) (define (trace-printf fmt . args)
((trace) (string-append (indent) (apply format fmt args)))) (let ([t (trace)])
(unless (eq? t void)
(define my-max (t (string-append (indent) (apply format fmt args))))))
(case-lambda
(() 0)
(x (apply max x))))
(define (get-deps code path) (define (get-deps code path)
(let-values ([(imports) (apply append (map cdr (module-compiled-imports code)))]) (filter-map (lambda (x)
(map path->bytes (let ([r (resolve-module-path-index x path)])
(let ([l (map (lambda (x) (and (path? x) (path->bytes x))))
(resolve-module-path-index x path)) (append-map cdr (module-compiled-imports code))))
imports)])
;; Filter symbols:
(let loop ([l l])
(cond
[(null? l) null]
[(symbol? (car l)) (loop (cdr l))]
[else (cons (car l) (loop (cdr l)))]))))))
(define (get-compilation-dir+name mode path) (define (get-compilation-dir+name mode path)
(let-values (((base name must-be-dir?) (split-path path))) (let-values ([(base name must-be-dir?) (split-path path)])
(values (values (if (eq? 'relative base) mode (build-path base mode))
(cond
((eq? 'relative base) mode)
(else (build-path base mode)))
name))) name)))
(define (get-compilation-path mode path) (define (get-compilation-path mode path)
(let-values ([(dir name) (get-compilation-dir+name mode path)]) (let-values ([(dir name) (get-compilation-dir+name mode path)])
(build-path dir name))) (build-path dir name)))
(define (get-code-dir mode path) (define (get-compilation-dir mode path)
(let-values (((base name-suffix must-be-dir?) (split-path path))) (let-values ([(base name-suffix must-be-dir?) (split-path path)])
(cond (if (eq? 'relative base) mode (build-path base mode))))
((eq? 'relative base) mode)
(else (build-path base mode))))) (define (touch path)
(close-output-port (open-output-file path #:exists 'append)))
(define (try-file-time path)
;; might be better to use a `with-handlers'
(and (file-exists? path) (file-or-directory-modify-seconds path)))
(define (try-delete-file path) (define (try-delete-file path)
;; Attempt to delete, but give up if it ;; Attempt to delete, but give up if it doesn't work:
;; doesn't work:
(with-handlers ([exn:fail:filesystem? void]) (with-handlers ([exn:fail:filesystem? void])
(trace-printf "deleting: ~a" path) (trace-printf "deleting: ~a" path)
(delete-file path))) (delete-file path)))
(define (compilation-failure mode path zo-name date-path reason)
(try-delete-file zo-name)
(trace-printf "failure"))
;; with-compile-output : path (output-port -> alpha) -> alpha ;; with-compile-output : path (output-port -> alpha) -> alpha
;; Open path for writing, and arranges to delete path if there's ;; Open path for writing, and arranges to delete path if there's
;; an exception. Breaks are managed so that the port is reliably ;; an exception. Breaks are managed so that the port is reliably
;; closed and the file is reliably deleted if there's a break ;; closed and the file is reliably deleted if there's a break
(define (with-compile-output path proc) (define (with-compile-output path proc)
(let ([bp (current-break-parameterization)]) (let ([bp (current-break-parameterization)])
(with-handlers ([void (lambda (exn) (with-handlers ([void (lambda (exn) (try-delete-file path) (raise exn))])
(try-delete-file path)
(raise exn))])
(let ([out (open-output-file path #:exists 'truncate/replace)]) (let ([out (open-output-file path #:exists 'truncate/replace)])
(dynamic-wind (dynamic-wind
void void
(lambda () (lambda ()
(call-with-break-parameterization (call-with-break-parameterization bp (lambda () (proc out))))
bp
(lambda ()
(proc out))))
(lambda () (lambda ()
(close-output-port out))))))) (close-output-port out)))))))
@ -87,49 +77,50 @@
(let ([dep-path (path-add-suffix (get-compilation-path mode path) #".dep")] (let ([dep-path (path-add-suffix (get-compilation-path mode path) #".dep")]
[deps (remove-duplicates (get-deps code path))] [deps (remove-duplicates (get-deps code path))]
[external-deps (remove-duplicates external-deps)]) [external-deps (remove-duplicates external-deps)])
(with-compile-output (with-compile-output dep-path
dep-path
(lambda (op) (lambda (op)
(write (cons (version) (write `(,(version)
(append (map path->main-collects-relative deps) ,@(map path->main-collects-relative deps)
(map (lambda (x) (cons 'ext (path->main-collects-relative x))) ,@(map (lambda (x)
external-deps))) (cons 'ext (path->main-collects-relative x)))
external-deps))
op) op)
(newline op))))) (newline op)))))
(define (touch path) (define (format-time sec)
(close-output-port (open-output-file path #:exists 'append))) (let ([d (seconds->date sec)])
(format "~a-~a-~a ~a:~a:~a"
(date-year d) (date-month d) (date-day d)
(date-hour d) (date-minute d) (date-second d))))
(define (compilation-failure mode path zo-name date-path reason) (define (verify-times ss-name zo-name)
(with-handlers ((exn:fail:filesystem? void)) (define ss-sec (try-file-time ss-name)) ; should exist
(delete-file zo-name)) (define zo-sec (try-file-time zo-name))
(trace-printf "failure")) (cond [(not ss-sec) (error 'compile-zo "internal error")]
[(not zo-sec) (error 'compile-zo "failed to create .zo file (~a) for ~a"
zo-name ss-name)]
[(< zo-sec ss-sec) (error 'compile-zo
"date for newly created .zo file (~a @ ~a) ~
is before source-file date (~a @ ~a)~a"
zo-name
(format-time (seconds->date zo-sec))
ss-name
(format-time (seconds->date ss-sec))
(if (> ss-sec (current-seconds))
", which appears to be in the future"
""))]))
(define (compile-zo mode path read-src-syntax) (define (compile-zo* mode path read-src-syntax zo-name)
((manager-compile-notify-handler) path) (define param
(trace-printf "compiling: ~a" path)
(parameterize ([indent (string-append " " (indent))])
(let ([zo-name (path-add-suffix (get-compilation-path mode path) #".zo")])
(cond
[(and (file-exists? zo-name) (trust-existing-zos)) (touch zo-name)]
[else
(when (file-exists? zo-name) (delete-file zo-name))
(with-handlers ([exn:get-module-code?
(lambda (ex)
(compilation-failure
mode path zo-name (exn:get-module-code-path ex)
(exn-message ex))
(raise ex))])
(let* ([param
;; Avoid using cm while loading cm-ctime: ;; Avoid using cm while loading cm-ctime:
(parameterize ([use-compiled-file-paths null]) (parameterize ([use-compiled-file-paths null])
(dynamic-require 'mzlib/private/cm-ctime (dynamic-require 'mzlib/private/cm-ctime
'current-external-file-registrar))] 'current-external-file-registrar)))
[external-deps null] (define external-deps null)
[code (parameterize ([param (lambda (ext-file) (define (external-dep! p)
(set! external-deps (set! external-deps (cons (path->bytes p) external-deps)))
(cons (path->bytes ext-file) (define code
external-deps)))] (parameterize ([param external-dep!]
[current-reader-guard [current-reader-guard
(let ([rg (current-reader-guard)]) (let ([rg (current-reader-guard)])
(lambda (d) (lambda (d)
@ -138,27 +129,22 @@
(let ([p (resolved-module-path-name (let ([p (resolved-module-path-name
(module-path-index-resolve (module-path-index-resolve
(module-path-index-join d #f)))]) (module-path-index-join d #f)))])
(when (path? p) (when (path? p) (external-dep! p))))
(set! external-deps
(cons (path->bytes p)
external-deps)))))
d)))]) d)))])
(get-module-code path mode (get-module-code path mode compile
compile
(lambda (a b) #f) ; extension handler (lambda (a b) #f) ; extension handler
#:source-reader read-src-syntax))] #:source-reader read-src-syntax)))
[code-dir (get-code-dir mode path)]) (define code-dir (get-compilation-dir mode path))
(when code (when code
(when (not (directory-exists? code-dir)) (make-directory* code-dir)
(make-directory* code-dir)) (with-compile-output zo-name
(with-compile-output
zo-name
(lambda (out) (lambda (out)
(with-handlers ((exn:fail? (with-handlers ([exn:fail?
(lambda (ex) (lambda (ex)
(close-output-port out) (close-output-port out)
(compilation-failure mode path zo-name #f (exn-message ex)) (compilation-failure mode path zo-name #f
(raise ex)))) (exn-message ex))
(raise ex))])
(parameterize ([current-write-relative-directory (parameterize ([current-write-relative-directory
(let-values ([(base name dir?) (split-path path)]) (let-values ([(base name dir?) (split-path path)])
(if (eq? base 'relative) (if (eq? base 'relative)
@ -167,114 +153,86 @@
(write code out))) (write code out)))
;; redundant, but close as early as possible: ;; redundant, but close as early as possible:
(close-output-port out) (close-output-port out)
;; Note that we check time and write .deps before returning from with-compile-output... ;; Note that we check time and write .deps before returning from
(let ([ss-sec (file-or-directory-modify-seconds path)] ;; with-compile-output...
[zo-sec (if (file-exists? zo-name) (verify-times path zo-name)
(file-or-directory-modify-seconds zo-name) (write-deps code mode path external-deps)))))
+inf.0)])
(when (< zo-sec ss-sec) (define (compile-zo mode path read-src-syntax)
(error 'compile-zo ((manager-compile-notify-handler) path)
"date for newly created .zo file (~a @ ~a) is before source-file date (~a @ ~a)~a" (trace-printf "compiling: ~a" path)
zo-name (parameterize ([indent (string-append " " (indent))])
(format-date (seconds->date zo-sec)) (let* ([zo-name (path-add-suffix (get-compilation-path mode path) #".zo")]
path [zo-exists? (file-exists? zo-name)])
(format-date (seconds->date ss-sec)) (if (and zo-exists? (trust-existing-zos))
(if (> ss-sec (current-seconds)) (touch zo-name)
", which appears to be in the future" (begin (when zo-exists? (delete-file zo-name))
"")))) (with-handlers
(write-deps code mode path external-deps))))))]))) ([exn:get-module-code?
(lambda (ex)
(compilation-failure mode path zo-name
(exn:get-module-code-path ex)
(exn-message ex))
(raise ex))])
(compile-zo* mode path read-src-syntax zo-name))))))
(trace-printf "end compile: ~a" path)) (trace-printf "end compile: ~a" path))
(define (format-date date)
(format "~a:~a:~a:~a:~a:~a"
(date-year date)
(date-month date)
(date-day date)
(date-hour date)
(date-minute date)
(date-second date)))
(define (append-object-suffix f)
(path-add-suffix f (system-type 'so-suffix)))
(define (get-compiled-time mode path) (define (get-compiled-time mode path)
(let*-values ([(dir name) (get-compilation-dir+name mode path)]) (define-values (dir name) (get-compilation-dir+name mode path))
(first-date (or (try-file-time (build-path dir "native" (system-library-subpath)
(lambda () (build-path dir "native" (system-library-subpath) (append-object-suffix name))) (path-add-suffix name (system-type
(lambda () (build-path dir (path-add-suffix name #".zo")))))) 'so-suffix))))
(try-file-time (build-path dir (path-add-suffix name #".zo")))
-inf.0))
(define first-date (define (compile-root mode path0 up-to-date read-src-syntax)
(case-lambda (define path (simplify-path (cleanse-path path0)))
[() -inf.0] (define (read-deps)
[(f . l) (with-handlers ([exn:fail:filesystem? (lambda (ex) (list (version)))])
(if f (call-with-input-file
(with-handlers ([exn:fail:filesystem? (path-add-suffix (get-compilation-path mode path) #".dep")
(lambda (ex) read)))
(apply first-date l))]) (define (do-check)
(let ([name (f)]) (define path-zo-time (get-compiled-time mode path))
(file-or-directory-modify-seconds name))) (define path-time (try-file-time path))
(apply first-date l))]))
(define (compile-root mode path up-to-date read-src-syntax)
(let ([path (simplify-path (cleanse-path path))])
(let ((stamp (and up-to-date
(hash-ref up-to-date path #f))))
(cond (cond
(stamp stamp) [(not path-time)
(else
(trace-printf "checking: ~a" path)
(let ((path-zo-time (get-compiled-time mode path))
(path-time
(with-handlers ((exn:fail:filesystem?
(lambda (ex)
(trace-printf "~a does not exist" path) (trace-printf "~a does not exist" path)
#f))) path-zo-time]
(file-or-directory-modify-seconds path)))) [else
(cond (cond
((not path-time) path-zo-time) [(> path-time path-zo-time)
(else
(cond
((> path-time path-zo-time)
(trace-printf "newer src...") (trace-printf "newer src...")
(compile-zo mode path read-src-syntax)) (compile-zo mode path read-src-syntax)]
(else [else
(let ((deps (with-handlers ((exn:fail:filesystem? (lambda (ex) (list (version))))) (let ([deps (read-deps)])
(call-with-input-file (path-add-suffix (get-compilation-path mode path) #".dep")
read))))
(cond (cond
((or (not (pair? deps)) [(not (and (pair? deps) (equal? (version) (car deps))))
(not (equal? (version) (car deps))))
(trace-printf "newer version...") (trace-printf "newer version...")
(compile-zo mode path read-src-syntax)) (compile-zo mode path read-src-syntax)]
((ormap (lambda (d) [(ormap
;; str => str is a module file name (check transitive dates) (lambda (p)
;; (cons 'ext str) => str is an non-module file (check date) ;; (cons 'ext rel-path) => a non-module file (check date)
(let ([t (cond ;; rel-path => a module file name (check transitive dates)
[(bytes? d) (compile-root mode (bytes->path d) up-to-date read-src-syntax)] (define ext? (and (pair? p) (eq? 'ext (car p))))
[(path? d) (compile-root mode d up-to-date read-src-syntax)] (define d (main-collects-relative->path (if ext? (cdr p) p)))
[(and (pair? d) (define t
(eq? (car d) 'ext) (cond [(not (path? d)) #f] ;; (can this happen?)
(or (bytes? (cdr d)) [ext? (try-file-time d)]
(path? (cdr d)))) [else (compile-root mode d up-to-date
(with-handlers ((exn:fail:filesystem? read-src-syntax)]))
(lambda (ex) +inf.0))) (and t (> t path-zo-time)
(file-or-directory-modify-seconds (if (bytes? (cdr d)) (begin (trace-printf "newer: ~a (~a > ~a)..."
(bytes->path (cdr d)) d t path-zo-time)
(cdr d))))] #t)))
[else +inf.0])]) (cdr deps))
(when (> t path-zo-time) (compile-zo mode path read-src-syntax)]))])
(trace-printf "newer: ~a (~a > ~a)..." d t path-zo-time)) (let ([stamp (get-compiled-time mode path)])
(> t path-zo-time)))
(map (lambda (p)
(if (and (pair? p)
(eq? 'ext (car p)))
(cons 'ext (main-collects-relative->path (cdr p)))
(main-collects-relative->path p)))
(cdr deps)))
(compile-zo mode path read-src-syntax))))))
(let ((stamp (get-compiled-time mode path)))
(hash-set! up-to-date path stamp) (hash-set! up-to-date path stamp)
stamp))))))))) stamp)]))
(or (and up-to-date (hash-ref up-to-date path #f))
(begin (trace-printf "checking: ~a" path)
(do-check))))
(define (managed-compile-zo zo [read-src-syntax read-syntax]) (define (managed-compile-zo zo [read-src-syntax read-syntax])
((make-caching-managed-compile-zo read-src-syntax) zo)) ((make-caching-managed-compile-zo read-src-syntax) zo))
@ -282,8 +240,12 @@
(define (make-caching-managed-compile-zo [read-src-syntax read-syntax]) (define (make-caching-managed-compile-zo [read-src-syntax read-syntax])
(let ([cache (make-hash)]) (let ([cache (make-hash)])
(lambda (zo) (lambda (zo)
(parameterize ([current-load/use-compiled (make-compilation-manager-load/use-compiled-handler/table cache)]) (parameterize ([current-load/use-compiled
(compile-root (car (use-compiled-file-paths)) (path->complete-path zo) cache read-src-syntax) (make-compilation-manager-load/use-compiled-handler/table
cache)])
(compile-root (car (use-compiled-file-paths))
(path->complete-path zo)
cache read-src-syntax)
(void))))) (void)))))
(define (make-compilation-manager-load/use-compiled-handler) (define (make-compilation-manager-load/use-compiled-handler)
@ -295,44 +257,34 @@
[orig-registry (namespace-module-registry (current-namespace))] [orig-registry (namespace-module-registry (current-namespace))]
[default-handler (current-load/use-compiled)] [default-handler (current-load/use-compiled)]
[modes (use-compiled-file-paths)]) [modes (use-compiled-file-paths)])
(define (compilation-manager-load-handler path mod-name)
(cond [(not mod-name)
(trace-printf "skipping: ~a mod-name ~s" path mod-name)]
[(not (member (car modes) (use-compiled-file-paths)))
(trace-printf "skipping: ~a compiled-paths ~s"
path (use-compiled-file-paths))]
[(not (eq? compilation-manager-load-handler
(current-load/use-compiled)))
(trace-printf "skipping: ~a current-load/use-compiled changed ~s"
path (current-load/use-compiled))]
[(not (eq? orig-eval (current-eval)))
(trace-printf "skipping: ~a orig-eval ~s current-eval ~s"
path orig-eval (current-eval))]
[(not (eq? orig-load (current-load)))
(trace-printf "skipping: ~a orig-load ~s current-load ~s"
path orig-load (current-load))]
[(not (eq? orig-registry
(namespace-module-registry (current-namespace))))
(trace-printf "skipping: ~a orig-registry ~s current-registry ~s"
path orig-registry
(namespace-module-registry (current-namespace)))]
[else
(trace-printf "processing: ~a" path)
(compile-root (car modes) path cache read-syntax)
(trace-printf "done: ~a" path)])
(default-handler path mod-name))
(when (null? modes) (when (null? modes)
(raise-mismatch-error 'make-compilation-manager-... (raise-mismatch-error 'make-compilation-manager-...
"empty use-compiled-file-paths list: " "empty use-compiled-file-paths list: "
modes)) modes))
(letrec ([compilation-manager-load-handler compilation-manager-load-handler))
(lambda (path mod-name)
(cond
[(not mod-name)
(trace-printf "skipping: ~a mod-name ~s" path mod-name)
(default-handler path mod-name)]
[(not (member (car modes) (use-compiled-file-paths)))
(trace-printf "skipping: ~a compiled-paths ~s" path (use-compiled-file-paths))
(default-handler path mod-name)]
[(not (eq? compilation-manager-load-handler (current-load/use-compiled)))
(trace-printf "skipping: ~a current-load/use-compiled changed ~s"
path
(current-load/use-compiled))
(default-handler path mod-name)]
[(not (eq? orig-eval (current-eval)))
(trace-printf "skipping: ~a orig-eval ~s current-eval ~s"
path orig-eval
(current-eval))
(default-handler path mod-name)]
[(not (eq? orig-load (current-load)))
(trace-printf "skipping: ~a orig-load ~s current-load ~s"
path
orig-load
(current-load))
(default-handler path mod-name)]
[(not (eq? orig-registry (namespace-module-registry (current-namespace))))
(trace-printf "skipping: ~a orig-rgistry ~s current-registry ~s"
path
orig-registry
(namespace-module-registry (current-namespace)))
(default-handler path mod-name)]
[else
(trace-printf "processing: ~a" path)
(compile-root (car modes) path cache read-syntax)
(trace-printf "done: ~a" path)
(default-handler path mod-name)]))])
compilation-manager-load-handler))))