#lang scheme/base ;; On error, exit with 1 status code (error-escape-handler (lambda () (exit 1))) (error-print-width 512) (require (prefix-in compiler:option: "../option.rkt") "../compiler.rkt" raco/command-name mzlib/cmdline dynext/file dynext/compile dynext/link scheme/pretty setup/pack setup/getinfo setup/dirs) (define dest-dir (make-parameter #f)) (define ld-output (make-parameter #f)) (define exe-output (make-parameter #f)) (define exe-embedded-flags (make-parameter '("-U" "--"))) (define exe-embedded-libraries (make-parameter null)) (define exe-aux (make-parameter null)) (define exe-embedded-collects-path (make-parameter #f)) (define exe-embedded-collects-dest (make-parameter #f)) (define exe-dir-add-collects-dirs (make-parameter null)) (define exe-dir-output (make-parameter #f)) (define mods-output (make-parameter #f)) (define default-plt-name "archive") (define disable-inlining (make-parameter #f)) (define plt-output (make-parameter #f)) (define plt-name (make-parameter default-plt-name)) (define plt-files-replace (make-parameter #f)) (define plt-files-plt-relative? (make-parameter #f)) (define plt-files-plt-home-relative? (make-parameter #f)) (define plt-force-install-dir? (make-parameter #f)) (define plt-setup-collections (make-parameter null)) (define plt-include-compiled (make-parameter #f)) (define stop-at-source (make-parameter #f)) (define (extract-suffix appender) (bytes->string/latin-1 (subbytes (path->bytes (appender (bytes->path #"x"))) 1))) (define ((add-to-param param) f v) (param (append (param) (list v)))) (define mzc-symbol (string->symbol (short-program+command-name))) ;; Returns (values mode files prefixes) ;; where mode is 'compile, 'make-zo, etc. (define-values (mode source-files prefix) (parse-command-line (short-program+command-name) (current-command-line-arguments) `([help-labels "-------------------------------- mode flags ---------------------------------"] [once-any [("--cc") ,(lambda (f) 'cc) (,(format "Compile arbitrary file(s) for an extension: ~a -> ~a" (extract-suffix append-c-suffix) (extract-suffix append-object-suffix)))] [("--ld") ,(lambda (f name) (ld-output name) 'ld) (,(format "Link arbitrary file(s) to create : ~a -> ~a" (extract-suffix append-object-suffix) (extract-suffix append-extension-suffix)) "extension")] [("-x" "--xform") ,(lambda (f) 'xform) ((,(format "Convert for 3m compilation: ~a -> ~a" (extract-suffix append-c-suffix) (extract-suffix append-c-suffix)) ""))] [("--c-mods") ,(lambda (f name) (mods-output name) 'c-mods) ((,(format "Write C-embeddable module bytecode to ") "") "file")]] [help-labels ""] [once-any [("--3m") ,(lambda (f) (compiler:option:3m #t)) (,(format "Compile/link for 3m~a" (if (eq? '3m (system-type 'gc)) " [current default]" "")))] [("--cgc") ,(lambda (f) (compiler:option:3m #f)) (,(format "Compile/link for CGC~a" (if (eq? 'cgc (system-type 'gc)) " [current default]" "")))]] [once-each [("-n" "--name") ,(lambda (f name) (compiler:option:setup-prefix name)) ("Use as extra part of public low-level names" "name")]] [once-any [("-d" "--destination") ,(lambda (f d) (unless (directory-exists? d) (error mzc-symbol "the destination directory does not exist: ~s" d)) (dest-dir d)) ("Output --cc/--ld/-x file(s) to " "dir")]] [help-labels "------------------- compiler/linker configuration flags ---------------------"] [once-each [("--tool") ,(lambda (f v) (let ([v (string->symbol v)]) (use-standard-compiler v) (use-standard-linker v))) (,(format "Use pre-defined as C compiler/linker:~a" (apply string-append (apply append (map (lambda (t) (list " " (symbol->string t))) (get-standard-compilers))))) "tool")] [("--compiler") ,(lambda (f v) (current-extension-compiler v)) ("Use as C compiler" "compiler-path")]] [multi [("++ccf") ,(add-to-param current-extension-compiler-flags) ("Add C compiler flag" "flag")] [("--ccf") ,(lambda (f v) (current-extension-compiler-flags (remove v (current-extension-compiler-flags)))) ("Remove C compiler flag" "flag")] [("--ccf-clear") ,(lambda (f) (current-extension-compiler-flags null)) ("Clear C compiler flags")] [("--ccf-show") ,(lambda (f) (printf "C compiler flags: ~s\n" (expand-for-link-variant (current-extension-compiler-flags)))) ("Show C compiler flags")]] [once-each [("--linker") ,(lambda (f v) (current-extension-linker v)) ("Use as C linker" "linker-path")]] [multi [("++ldf") ,(add-to-param current-extension-linker-flags) ("Add C linker flag" "flag")] [("--ldf") ,(lambda (f v) (current-extension-linker-flags (remove v (current-extension-linker-flags)))) ("Remove C linker flag" "flag")] [("--ldf-clear") ,(lambda (f) (current-extension-linker-flags null)) ("Clear C linker flags")] [("--ldf-show") ,(lambda (f) (printf "C linker flags: ~s\n" (expand-for-link-variant (current-extension-linker-flags)))) ("Show C linker flags")] [("++ldl") ,(add-to-param current-standard-link-libraries) ("Add C linker library" "lib")] [("--ldl-show") ,(lambda (f) (printf "C linker libraries: ~s\n" (expand-for-link-variant (current-standard-link-libraries)))) ("Show C linker libraries")]] [multi [("++cppf") ,(add-to-param current-extension-preprocess-flags) ("Add C preprocess (xform) flag" "flag")] [("--cppf") ,(lambda (f v) (current-extension-preprocess-flags (remove v (current-extension-preprocess-flags)))) ("Remove C preprocess (xform) flag" "flag")] [("--cppf-clear") ,(lambda (f) (current-extension-preprocess-flags null)) ("Clear C preprocess (xform) flags")] [("--cppf-show") ,(lambda (f) (printf "C compiler flags: ~s\n" (expand-for-link-variant (current-extension-preprocess-flags)))) ("Show C preprocess (xform) flags")]] [help-labels "----------------------- C-embeddable module flags ---------------------------"] [multi [("++lib") ,(lambda (f l) (exe-embedded-libraries (append (exe-embedded-libraries) (list l)))) ("Embed in --c-mods output" "lib")]] [help-labels "-------------------------- miscellaneous flags ------------------------------"] [once-each [("-v") ,(lambda (f) (compiler:option:somewhat-verbose #t)) ("Slightly verbose mode, including version banner and output files")] [("--vv") ,(lambda (f) (compiler:option:somewhat-verbose #t) (compiler:option:verbose #t)) ("Very verbose mode")]]) (lambda (accum . files) (let ([mode (let ([l (filter symbol? accum)]) (if (null? l) (error mzc-symbol "no mode flag specified") (car l)))]) (values mode files #f))) (list "file"))) (when (compiler:option:somewhat-verbose) (printf "~a v~a [~a], Copyright (c) 2004-2013 PLT Design Inc.\n" (short-program+command-name) (version) (system-type 'gc))) (if (compiler:option:3m) (begin (link-variant '3m) (compile-variant '3m)) (begin (link-variant 'cgc) (compile-variant 'cgc))) (define (compiler-warning) (eprintf "Warning: ~a\n ~a\n" "compilation to C is usually less effective for performance" "than relying on the bytecode just-in-time compiler.")) (case mode [(cc) (for ([file source-files]) (let* ([base (extract-base-filename/c file mzc-symbol)] [dest (append-object-suffix (let-values ([(base name dir?) (split-path base)]) (build-path (or (dest-dir) 'same) name)))]) (when (compiler:option:somewhat-verbose) (printf "\"~a\":\n" file)) (compile-extension (not (compiler:option:verbose)) file dest null) (when (compiler:option:somewhat-verbose) (printf " [output to \"~a\"]\n" dest))))] [(ld) (extract-base-filename/ext (ld-output) mzc-symbol) ;; (for ([file source-files]) (extract-base-filename/o file mzc-symbol)) (let ([dest (if (dest-dir) (build-path (dest-dir) (ld-output)) (ld-output))]) (when (compiler:option:somewhat-verbose) (printf "~a:\n" (let ([s (apply string-append (map (lambda (n) (format " \"~a\"" n)) source-files))]) (substring s 1 (string-length s))))) (link-extension (not (compiler:option:verbose)) source-files dest) (when (compiler:option:somewhat-verbose) (printf " [output to \"~a\"]\n" dest)))] [(xform) (for ([file source-files]) (let* ([out-file (path-replace-suffix file ".3m.c")] [out-file (if (dest-dir) (build-path (dest-dir) out-file) out-file)]) ((dynamic-require 'compiler/xform 'xform) (not (compiler:option:verbose)) file out-file (list (find-include-dir))) (when (compiler:option:somewhat-verbose) (printf " [output to \"~a\"]\n" out-file))))] [(c-mods) (let ([dest (mods-output)]) (let-values ([(in out) (make-pipe)]) (parameterize ([current-output-port out]) ((dynamic-require 'compiler/embed 'write-module-bundle) #:modules (append (map (lambda (l) `(#f (file ,l))) source-files) (map (lambda (l) `(#t (lib ,l))) (exe-embedded-libraries))))) (close-output-port out) (let ([out (open-output-file dest #:exists 'truncate/replace)]) (fprintf out "#ifdef MZ_XFORM\n") (fprintf out "XFORM_START_SKIP;\n") (fprintf out "#endif\n") (fprintf out "static void declare_modules(Scheme_Env *env) {\n") (fprintf out " static unsigned char data[] = {") (let loop ([pos 0]) (let ([b (read-byte in)]) (when (zero? (modulo pos 20)) (fprintf out "\n ")) (unless (eof-object? b) (fprintf out "~a," b) (loop (add1 pos))))) (fprintf out "0\n };\n") (fprintf out " scheme_register_embedded_load(~a, (const char *)data);\n" (file-position in)) (fprintf out " scheme_embedded_load(~a, (const char *)data, 1);\n" (file-position in)) (fprintf out "}\n") (fprintf out "#ifdef MZ_XFORM\n") (fprintf out "XFORM_END_SKIP;\n") (fprintf out "#endif\n") (close-output-port out))) (when (compiler:option:somewhat-verbose) (printf " [output to \"~a\"]\n" dest)))] [else (printf "bad mode: ~a\n" mode)])