racket/collects/dynext/compile-unit.rkt
Matthew Flatt 514706446e overhaul plot organization
by moving needed C source to src/plot and building during `make',
 but stripping out the copies of gd, png, and zlib; instead, hook
 a dc<%>-based back end into plot
2010-11-06 16:54:29 -06:00

303 lines
11 KiB
Racket

(module compile-unit mzscheme
(require mzlib/unit
mzlib/process
mzlib/sendevent
"private/dirs.ss"
"private/stdio.rkt"
"private/cmdargs.ss")
(require "compile-sig.ss")
(provide dynext:compile@)
(define-unit dynext:compile@
(import)
(export dynext:compile^)
(define (get-unix-compile)
(or (find-executable-path "gcc" #f)
(find-executable-path "cc" #f)))
(define (get-windows-compile)
(or (find-executable-path "cl.exe" #f)
(find-executable-path "gcc.exe" #f)
(find-executable-path "bcc32.exe" #f)))
(define current-extension-compiler
(make-parameter
(or (let ([p (or (getenv "MZSCHEME_DYNEXT_COMPILER")
(getenv "CC"))])
(and p
(if (absolute-path? p)
(string->path p)
(find-executable-path p #f))))
(case (system-type)
[(unix macosx) (get-unix-compile)]
[(windows) (get-windows-compile)]
[else #f]))
(lambda (v)
(when v
(if (path-string? v)
(unless (and (file-exists? v)
(memq 'execute (file-or-directory-permissions v)))
(error 'current-extension-compiler
"compiler not found or not executable: ~s" v))
(raise-type-error 'current-extension-compiler "path, valid-path string, or #f" v)))
v)))
(define win-gcc?
(let ([c (current-extension-compiler)])
(and c (regexp-match #"gcc.exe$" (path->bytes c)))))
(define win-borland?
(let ([c (current-extension-compiler)])
(and c (regexp-match #"bcc32.exe$" (path->bytes c)))))
(define unix-cc?
(let ([c (current-extension-compiler)])
(and c (regexp-match #"[^g]cc$" (path->bytes c)))))
(define (add-variant-flags l)
(append l (list (lambda ()
(if (eq? '3m (specific-compile-variant))
'("-DMZ_PRECISE_GC")
null)))))
(define gcc-cpp-flags
(add-variant-flags (case (string->symbol (path->string (system-library-subpath #f)))
[(parisc-hpux) '("-D_HPUX_SOURCE")]
[(ppc-macosx x86_64-macosx) '("-DOS_X")]
[(i386-macosx) '("-DOS_X" "-m32")]
[(ppc-darwin x86_64-darwin) '("-DOS_X" "-DXONX")]
[(i386-darwin) '("-DOS_X" "-DXONX" "-m32")]
[else null])))
(define gcc-compile-flags (append '("-c" "-O2" "-fPIC")
(case (string->symbol (path->string (system-library-subpath #f)))
[(i386-macosx i386-darwin) '("-m32" "-fno-common")]
[(ppc-macosx ppc-darwin x86_64-macosx x86_64-darwin) '("-fno-common")]
[(win32\\i386) '("-DAS_MSVC_EXTENSION")]
[else null])
gcc-cpp-flags))
(define unix-cpp-flags
(add-variant-flags (case (string->symbol (path->string (system-library-subpath #f)))
[(parisc-hpux) '("-D_HPUX_SOURCE")]
[else gcc-cpp-flags])))
(define unix-compile-flags (case (string->symbol (path->string (system-library-subpath #f)))
[(parisc-hpux) (append '("-c" "-O2" "-Aa" "+z" "+e")
unix-cpp-flags)]
[else gcc-compile-flags]))
(define msvc-compile-flags
(add-variant-flags '("/c" "/MT" "/O2")))
(define (make-flags-guard who)
(lambda (l)
(unless (and (list? l) (andmap (lambda (s) (or (path-string? s)
(and (procedure? s) (procedure-arity-includes? s 0))))
l))
(raise-type-error who "list of paths/strings and thunks" l))
l))
(define (get-env-compile-flags)
(let ([v (or (getenv "MZSCHEME_DYNEXT_COMPILER_FLAGS")
(getenv "CFLAGS"))])
(if v
(split-command-line-args v)
null)))
(define current-extension-compiler-flags
(make-parameter
(append
(get-env-compile-flags)
(case (system-type)
[(unix macosx) (if unix-cc?
unix-compile-flags
gcc-compile-flags)]
[(windows) (if (or win-gcc? win-borland?)
gcc-compile-flags
msvc-compile-flags)]
[(macos) '()]))
(make-flags-guard 'current-extension-compiler-flags)))
(define current-extension-preprocess-flags
(make-parameter
(case (system-type)
[(unix macosx) (cons "-E" (if unix-cc?
unix-cpp-flags
gcc-cpp-flags))]
[(windows) (if (or win-gcc? win-borland?)
(cons "-E" gcc-cpp-flags)
'("/E"))]
[(macos) '()])
(make-flags-guard 'current-extension-preprocess-flags)))
(define compile-variant (make-parameter
'normal
(lambda (s)
(unless (memq s '(normal cgc 3m))
(raise-type-error 'compile-variant "'normal, 'cgc, or '3m" s))
s)))
(define (specific-compile-variant)
(let ([v (compile-variant)])
(if (eq? v 'normal)
(system-type 'gc)
v)))
(define (expand-for-compile-variant l)
(apply append (map (lambda (s) (if (path-string? s) (list s) (s))) l)))
(define current-make-extra-extension-compiler-flags
(make-parameter
(lambda () (case (specific-compile-variant)
[(3m) '("-DMZ_PRECISE_GC")]
[else null]))
(lambda (p)
(unless (and (procedure? p) (procedure-arity-includes? p 0))
(raise-type-error 'current-make-extra-extension-compiler-flags "procedure (arity 0)" p))
p)))
(define (path-string->string s)
(if (string? s) s (path->string s)))
(define unix-compile-include-strings (lambda (s)
(list (string-append "-I" (path-string->string s)))))
(define msvc-compile-include-strings (lambda (s)
(list (string-append "/I" (path-string->string s)))))
(define current-make-compile-include-strings
(make-parameter
(case (system-type)
[(unix macosx) unix-compile-include-strings]
[(windows) (if (or win-gcc? win-borland?)
unix-compile-include-strings
msvc-compile-include-strings)]
[(macos) unix-compile-include-strings])
(lambda (p)
(unless (procedure-arity-includes? p 1)
(raise-type-error 'current-make-compile-include-strings "procedure of arity 1" p))
p)))
(define current-make-compile-input-strings
(make-parameter
(lambda (s) (list (path-string->string s)))
(lambda (p)
(unless (procedure-arity-includes? p 1)
(raise-type-error 'current-make-compile-input-strings "procedure of arity 1" p))
p)))
(define unix-compile-output-strings (lambda (s) (list "-o" (path-string->string s))))
(define msvc-compile-output-strings (lambda (s) (list (string-append "/Fo" (path-string->string s)))))
(define current-make-compile-output-strings
(make-parameter
(case (system-type)
[(unix macosx) unix-compile-output-strings]
[(windows) (if (or win-gcc? win-borland?)
unix-compile-output-strings
msvc-compile-output-strings)]
[(macos) unix-compile-output-strings])
(lambda (p)
(unless (procedure-arity-includes? p 1)
(raise-type-error 'current-make-compile-output-strings "procedure of arity 1" p))
p)))
(define (get-standard-compilers)
(case (system-type)
[(unix macosx) '(gcc cc)]
[(windows) '(gcc msvc borland)]
[(macos) '(cw)]))
(define (use-standard-compiler name)
(define (bad-name name)
(error 'use-standard-compiler "unknown compiler: ~a" name))
(case (system-type)
[(unix macosx)
(case name
[(cc gcc) (let* ([n (if (eq? name 'gcc) "gcc" "cc")]
[f (find-executable-path n n)])
(unless f
(error 'use-standard-compiler "cannot find ~a" n))
(current-extension-compiler f))
(current-extension-compiler-flags (add-variant-flags
(if (eq? name 'gcc)
gcc-compile-flags
unix-compile-flags)))
(current-make-compile-include-strings unix-compile-include-strings)
(current-make-compile-input-strings (lambda (s) (list (path-string->string s))))
(current-make-compile-output-strings unix-compile-output-strings)]
[else (bad-name name)])]
[(windows)
(case name
[(gcc) (let ([f (find-executable-path "gcc.exe" #f)])
(unless f
(error 'use-standard-compiler "cannot find gcc.exe"))
(current-extension-compiler f))
(current-extension-compiler-flags (add-variant-flags gcc-compile-flags))
(current-make-compile-include-strings unix-compile-include-strings)
(current-make-compile-input-strings (lambda (s) (list (path-string->string s))))
(current-make-compile-output-strings unix-compile-output-strings)]
[(borland) (let ([f (find-executable-path "bcc32.exe" #f)])
(unless f
(error 'use-standard-compiler "cannot find bcc32.exe"))
(current-extension-compiler f))
(current-extension-compiler-flags (add-variant-flags gcc-compile-flags))
(current-make-compile-include-strings unix-compile-include-strings)
(current-make-compile-input-strings (lambda (s) (list (path-string->string s))))
(current-make-compile-output-strings unix-compile-output-strings)]
[(msvc) (let ([f (find-executable-path "cl.exe" #f)])
(unless f
(error 'use-standard-compiler "cannot find MSVC's cl.exe"))
(current-extension-compiler f))
(current-extension-compiler-flags (add-variant-flags msvc-compile-flags))
(current-make-compile-include-strings msvc-compile-include-strings)
(current-make-compile-input-strings (lambda (s) (list (path-string->string s))))
(current-make-compile-output-strings msvc-compile-output-strings)]
[else (bad-name name)])]
[(macos)
(case name
[(cw) (current-extension-compiler #f)
(current-extension-compiler-flags (add-variant-flags unix-compile-flags))
(current-make-compile-include-strings unix-compile-include-strings)
(current-make-compile-input-strings (lambda (s) (list (path-string->string s))))
(current-make-compile-output-strings unix-compile-output-strings)]
[else (bad-name name)])]))
(define-values (my-process* stdio-compile)
(let-values ([(p* do-stdio) (get-stdio)])
(values
p*
(lambda (start-process quiet?)
(do-stdio start-process quiet? (lambda (s) (error 'compile-extension "~a" s)))))))
(define (make-compile-extension current-extension-compiler-flags)
(lambda (quiet? in out includes)
(let ([c (current-extension-compiler)])
(if c
(stdio-compile (lambda (quiet?)
(let ([command (append
(list c)
(expand-for-compile-variant
(current-extension-compiler-flags))
(apply append
(map
(lambda (s)
((current-make-compile-include-strings) s))
includes))
((current-make-compile-include-strings) (include-dir))
((current-make-compile-input-strings) in)
((current-make-compile-output-strings) out))])
(unless quiet?
(printf "compile-extension: ~a\n" command))
(apply my-process* command)))
quiet?)
(error 'compile-extension "can't find an installed C compiler")))))
(define compile-extension (make-compile-extension
current-extension-compiler-flags))
(define preprocess-extension (make-compile-extension
current-extension-compiler-flags))))