racket/collects/compiler/compiler-unit.rkt
2011-12-31 15:16:59 -05:00

208 lines
9.3 KiB
Racket

#lang scheme/base
;; Main compilation procedures
;; (c) 1997-2012 PLT Scheme Inc.
;; The various procedures provided by this library are implemented
;; by dynamically linking to code supplied by the MzLib, dynext, and
;; compiler collections.
(require scheme/unit
"sig.rkt"
dynext/file-sig
dynext/link-sig
dynext/compile-sig
syntax/toplevel
syntax/moddep
scheme/file
mzlib/compile ; gets compile-file
compiler/cm
setup/getinfo
setup/main-collects
setup/private/omitted-paths)
(provide compiler@)
(define-namespace-anchor anchor)
(define orig-namespace (namespace-anchor->empty-namespace anchor))
;; ;;;;;;;; ----- The main compiler unit ------ ;;;;;;;;;;
(define-unit compiler@
(import compiler:option^
dynext:compile^
dynext:link^
dynext:file^)
(export compiler^)
(define compile-notify-handler
(make-parameter void))
(define current-compiler-dynamic-require-wrapper
(make-parameter (lambda (thunk)
(parameterize ([current-namespace orig-namespace])
(thunk)))))
(define (c-dynamic-require path id)
((current-compiler-dynamic-require-wrapper)
(lambda () (dynamic-require path id))))
(define (c-get-info cp)
((current-compiler-dynamic-require-wrapper)
(lambda () (get-info cp))))
(define (c-get-info/full cp)
((current-compiler-dynamic-require-wrapper)
(lambda () (get-info/full cp))))
(define (compile-to-zo src dest namespace eval? verbose? mod?)
((if eval?
(lambda (t) (parameterize ([read-accept-reader #t])
(t)))
with-module-reading-parameterization)
(lambda ()
(parameterize ([current-namespace namespace])
(compile-file src dest
(compose
(if eval?
(lambda (expr)
(expand-syntax-top-level-with-compile-time-evals expr))
values)
(if mod?
(lambda (expr)
(check-module-form expr
(let-values ([(base name dir?) (split-path src)])
(string->symbol
(path-element->string (path-replace-suffix name #""))))
src))
values))))))
(when verbose?
(printf " [output to \"~a\"]\n" dest)))
(define (compile-zos prefix #:verbose? [verbose? #f] #:module? [mod? #f])
(define n (if prefix (make-base-namespace) (current-namespace)))
(when prefix (eval prefix n))
(lambda (source-files destination-directory)
(define file-bases
(map (lambda (file)
(if destination-directory
(let-values ([(base file dir?) (split-path file)])
(build-path
(if (eq? destination-directory 'auto)
(let ([d (build-path (if (eq? base 'relative) 'same base)
"compiled")])
(unless (directory-exists? d) (make-directory* d))
d)
destination-directory)
file))
file))
source-files))
(for ([f source-files] [b file-bases])
(let ([zo (append-zo-suffix b)])
(compile-to-zo f zo n prefix verbose? mod?)))))
(define (compile-directory-visitor dir info worker omit-root
#:verbose [verbose? #t]
#:skip-path [orig-skip-path #f]
#:skip-doc-sources? [skip-docs? #f])
(define info* (or info (lambda (key mk-default) (mk-default))))
(define omit-paths (omitted-paths dir c-get-info/full omit-root))
(define skip-path (and orig-skip-path (path->bytes
(simplify-path (if (string? orig-skip-path)
(string->path orig-skip-path)
orig-skip-path)
#f))))
(unless (eq? 'all omit-paths)
(let ([init (parameterize ([current-directory dir]
[current-load-relative-directory dir]
;; Verbose compilation manager:
[manager-trace-handler (if verbose?
(let ([op (current-output-port)])
(lambda (s) (fprintf op "~a\n" s)))
(manager-trace-handler))]
[manager-compile-notify-handler
(lambda (path) ((compile-notify-handler) path))]
[manager-skip-file-handler
(lambda (path) (and skip-path
(let ([b (path->bytes (simplify-path path #f))]
[len (bytes-length skip-path)])
(and ((bytes-length b) . > . len)
(bytes=? (subbytes b 0 len) skip-path)))
(list -inf.0 "")))])
(let* ([sses (append
;; Find all .rkt/.ss/.scm files:
(filter extract-base-filename/ss (directory-list))
;; Add specified doc sources:
(if skip-docs?
null
(map (lambda (s) (if (string? s) (string->path s) s))
(map car (info* 'scribblings (lambda () null))))))]
[sses (remove* omit-paths sses)])
(worker null sses)))])
(if (compile-subcollections)
(begin
(when (info* 'compile-subcollections (lambda () #f))
(printf "Warning: ignoring `compile-subcollections' entry in info ~a\n"
dir))
(for/fold ([init init]) ([p (directory-list dir)])
(let ([p* (build-path dir p)])
(if (and (directory-exists? p*) (not (member p omit-paths)))
(compile-directory-visitor p* (c-get-info/full p*) worker omit-root
#:verbose verbose?
#:skip-path skip-path
#:skip-doc-sources? skip-docs?)
init))))
init))))
(define (compile-directory dir info
#:verbose [verbose? #t]
#:skip-path [orig-skip-path #f]
#:skip-doc-sources? [skip-docs? #f]
#:managed-compile-zo [managed-compile-zo
(make-caching-managed-compile-zo)]
#:omit-root [omit-root dir])
(define (worker prev sses)
(for-each managed-compile-zo sses))
(compile-directory-visitor dir info worker omit-root
#:verbose verbose?
#:skip-path orig-skip-path
#:skip-doc-sources? skip-docs?))
(define (get-compile-directory-srcs dir info
#:verbose [verbose? #t]
#:skip-path [orig-skip-path #f]
#:skip-doc-sources? [skip-docs? #f]
#:managed-compile-zo [managed-compile-zo
(make-caching-managed-compile-zo)]
#:omit-root [omit-root dir])
(compile-directory-visitor dir info append omit-root
#:verbose verbose?
#:skip-path orig-skip-path
#:skip-doc-sources? skip-docs?
#:managed-compile-zo managed-compile-zo))
(define unspec (gensym))
(define (compile-collection-zos collection
#:skip-path [skip-path #f]
#:skip-doc-sources? [skip-docs? #f]
#:managed-compile-zo [managed-compile-zo
(make-caching-managed-compile-zo)]
#:omit-root [omit-root unspec]
. cp)
(define dir (apply collection-path collection cp))
(compile-directory dir
(c-get-info (cons collection cp))
#:omit-root (if (eq? omit-root unspec)
dir
omit-root)
#:verbose #f
#:skip-path skip-path
#:skip-doc-sources? skip-docs?
#:managed-compile-zo managed-compile-zo))
(define compile-directory-zos compile-directory)
(define compile-directory-srcs get-compile-directory-srcs)
)