(module compile-unit mzscheme (require (lib "unitsig.ss") (lib "include.ss") (lib "process.ss") (lib "sendevent.ss") "private/dirs.ss") (require "compile-sig.ss") (provide dynext:compile@) (define dynext:compile@ (unit/sig dynext:compile^ (import) (define (get-unix-compile) (or (getenv "MZSCHEME_DYNEXT_COMPILER") (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 (case (system-type) [(unix macosx) (get-unix-compile)] [(windows) (get-windows-compile)] [else #f]) (lambda (v) (when v (if (and (string? v) (or (relative-path? v) (absolute-path? 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 "pathname string or #f" v))) v))) (define win-gcc? (let ([c (current-extension-compiler)]) (and c (regexp-match "gcc.exe$" c)))) (define win-borland? (let ([c (current-extension-compiler)]) (and c (regexp-match "bcc32.exe$" c)))) (define unix-cc? (let ([c (current-extension-compiler)]) (and c (regexp-match "[^g]cc$" c)))) (define gcc-compile-flags (append '("-c" "-O2" "-fPIC") (case (string->symbol (system-library-subpath)) [(parisc-hpux) '("-D_HPUX_SOURCE")] [(ppc-macosx) '("-fno-common" "-DOS_X")] [(ppc-darwin) '("-fno-common" "-DOS_X" "-DXONX" )] [else null]))) (define unix-compile-flags (case (string->symbol (system-library-subpath)) [(parisc-hpux) '("-c" "-O2" "-Aa" "-D_HPUX_SOURCE" "+z" "+e")] [else gcc-compile-flags])) (define msvc-compile-flags '("/c" "/MT" "/O2")) (define current-extension-compiler-flags (make-parameter (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) '()]) (lambda (l) (unless (and (list? l) (andmap (lambda (s) (or (string? s) (and (procedure? s) (procedure-arity-includes? s 0)))) l)) (raise-type-error 'current-extension-compiler-flags "list of strings and thunks" l)) l))) (define compile-variant (make-parameter 'normal (lambda (s) (unless (memq s '(normal 3m)) (raise-type-error 'compile-variant "'normal or '3m" s)) s))) (define (add-variant-flags l) (append l (list (lambda () (if (eq? '3m (compile-variant)) '("-DMZ_PRECISE_GC") null))))) (define (expand-for-compile-variant l) (apply append (map (lambda (s) (if (string? s) (list s) (s))) l))) (define current-make-extra-extension-compiler-flags (make-parameter (lambda () (case (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 unix-compile-include-strings (lambda (s) (list (string-append "-I" s)))) (define msvc-compile-include-strings (lambda (s) (list (string-append "/I" 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 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" s))) (define msvc-compile-output-strings (lambda (s) (list (string-append "/Fo" 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-linker "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 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-linker "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 s))) (current-make-compile-output-strings unix-compile-output-strings)] [(borland) (let ([f (find-executable-path "bcc32.exe" #f)]) (unless f (error 'use-standard-linker "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 s))) (current-make-compile-output-strings unix-compile-output-strings)] [(msvc) (let ([f (find-executable-path "cl.exe" #f)]) (unless f (error 'use-standard-linker "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 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 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) (include (build-path "private" "stdio.ss"))]) (values p* (lambda (start-process quiet?) (do-stdio start-process quiet? (lambda (s) (error 'compile-extension "~a" s))))))) (define unix/windows-compile (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"))))) (include (build-path "private" "macinc.ss")) (define (macos-compile quiet? input-file output-file includes) (macos-make 'compile-extension "extension-project" "lib" quiet? (list input-file) output-file includes)) (define compile-extension (case (system-type) [(unix windows macosx) unix/windows-compile] [(macos) macos-compile])))))