diff --git a/collects/compiler/cm-accomplice.ss b/collects/compiler/cm-accomplice.ss new file mode 100644 index 0000000000..9cf2b293a9 --- /dev/null +++ b/collects/compiler/cm-accomplice.ss @@ -0,0 +1,5 @@ +#lang scheme/base + +(require mzlib/cm-accomplice) + +(provide (all-from-out mzlib/cm-accomplice)) diff --git a/collects/compiler/cm.ss b/collects/compiler/cm.ss new file mode 100644 index 0000000000..fb85ff0bf9 --- /dev/null +++ b/collects/compiler/cm.ss @@ -0,0 +1,5 @@ +#lang scheme/base + +(require mzlib/cm) + +(provide (all-from-out mzlib/cm)) diff --git a/collects/scheme/mpair.ss b/collects/scheme/mpair.ss index 01c0d41b4b..2051d7c4cb 100644 --- a/collects/scheme/mpair.ss +++ b/collects/scheme/mpair.ss @@ -8,6 +8,7 @@ mappend mappend! mreverse + mreverse! mlist-tail mlist-ref mmemq @@ -103,10 +104,11 @@ (case-lambda [() null] [(a) a] - [(a b) (let loop ([atail a]) - (cond [(null? atail) b] - [(null? (mcdr atail)) (set-mcdr! atail b) a] - [else (loop (mcdr atail))]))] + [(a b) (if (null? a) + b + (let loop ([atail a]) + (cond [(null? (mcdr atail)) (set-mcdr! atail b) a] + [else (loop (mcdr atail))])))] [(a . l) (mappend! a (apply mappend! l))])) (define (mreverse l) @@ -115,6 +117,14 @@ [(null? l) a] [else (loop (mcdr l) (mcons (mcar l) a))]))) +(define (mreverse! l) + (let loop ([l l][prev null]) + (cond + [(null? l) prev] + [else (let ([next (mcdr l)]) + (set-mcdr! l prev) + (loop next l))]))) + (define (mlist-tail l n) (cond [(zero? n) l] diff --git a/collects/scribblings/mzc/cc.scrbl b/collects/scribblings/mzc/cc.scrbl new file mode 100644 index 0000000000..8cf176d3c4 --- /dev/null +++ b/collects/scribblings/mzc/cc.scrbl @@ -0,0 +1,5 @@ +#lang scribble/doc +@(require scribble/manual + "common.ss") + +@title[#:tag "cc"]{Compiling and Linking C Extensions} diff --git a/collects/scribblings/mzc/common.ss b/collects/scribblings/mzc/common.ss new file mode 100644 index 0000000000..3b1bcd0a02 --- /dev/null +++ b/collects/scribblings/mzc/common.ss @@ -0,0 +1,7 @@ +#lang scheme/base +(require scribble/manual) + +(provide mzc) + +(define mzc (exec "mzc")) + diff --git a/collects/scribblings/mzc/exe.scrbl b/collects/scribblings/mzc/exe.scrbl new file mode 100644 index 0000000000..2d5c16bde6 --- /dev/null +++ b/collects/scribblings/mzc/exe.scrbl @@ -0,0 +1,5 @@ +#lang scribble/doc +@(require scribble/manual + "common.ss") + +@title[#:tag "exe"]{Creating and Packaging Stand-Alone Executables} diff --git a/collects/scribblings/mzc/ext.scrbl b/collects/scribblings/mzc/ext.scrbl new file mode 100644 index 0000000000..70f053648e --- /dev/null +++ b/collects/scribblings/mzc/ext.scrbl @@ -0,0 +1,5 @@ +#lang scribble/doc +@(require scribble/manual + "common.ss") + +@title[#:tag "ext"]{Compiling to Native Code via C} diff --git a/collects/scribblings/mzc/info.ss b/collects/scribblings/mzc/info.ss new file mode 100644 index 0000000000..53aeb9b6fc --- /dev/null +++ b/collects/scribblings/mzc/info.ss @@ -0,0 +1,4 @@ +(module info setup/infotab + (define name "Scribblings: mzc") + (define scribblings '(("mzc.scrbl" (multi-page)))) + (define doc-categories '(tool))) diff --git a/collects/scribblings/mzc/make.scrbl b/collects/scribblings/mzc/make.scrbl new file mode 100644 index 0000000000..5022883895 --- /dev/null +++ b/collects/scribblings/mzc/make.scrbl @@ -0,0 +1,251 @@ +#lang scribble/doc +@(require scribble/manual + scribble/bnf + "common.ss" + (for-label scheme/base + scheme/include + scheme/contract + compiler/cm + compiler/cm-accomplice)) + +@title[#:tag "make"]{Compiling Modified Modules to Bytecode} + +The default mode for @|mzc| is to accept filenames for Scheme modules +to be compiled to bytecode format. Modules are re-compiled only if the +source Scheme file is newer than the bytecode file, or if any imported +module is recompiled. + +@; ---------------------------------------------------------------------- + +@section{Bytecode Files} + +A file @filepath{@nonterm{name}.@nonterm{ext}} is compiled to bytecode +that is saved as @filepath{compiled/@nonterm{name}_@nonterm{ext}.zo} +relative to the file. As a result, the bytecode file is normally used +automatically when @filepath{@nonterm{name}.@nonterm{ext}} is required +as a module, since the underlying @scheme[load/use-compiled] operation +detects such a bytecode file. + +For example, in a directory that contains the following files: + +@itemize{ + + @item{@filepath{a.scm}: + +@schememod[ +scheme +(require "b.scm" "c.scm") +(+ b c) +]} + + @item{@filepath{b.scm}: + +@schememod[ +scheme +(provide b) +(define b 1) +]} + + @item{@filepath{c.scm}: + +@schememod[ +scheme +(provide c) +(define c 1) +]}} + +then + +@commandline{mzc a.scm} + +triggers the creation of @filepath{compiled/a_ss.zo}, +@filepath{compiled/b_ss.zo}, and @filepath{compiled/c_ss.zo}. +A subsequent + +@commandline{mzscheme a.scm} + +loads bytecode from the generated @filepath{.zo} files, paying attention +to the @filepath{.scm} sources only to confirm that each +@filepath{.zo} file has a later timestamp. + +In contrast, + +@commandline{mzc b.scm c.scm} + +would create only @filepath{compiled/b_scm.zo} and +@filepath{compiled/c_scm.zo}, since neither @filepath{b.scm} nor +@filepath{c.scm} imports @filepath{a.scm}. + +@; ---------------------------------------------------------------------- + +@section{Dependency Files} + +In addition to a bytecode file, @|mzc| creates a file +@filepath{compiled/@nonterm{name}_@nonterm{ext}.dep} that records +dependencies of the compiled module on other module files. Using this +dependency information, a re-compilation request via @|mzc| can +consult both the source file's timestamp and the timestamps for the +sources and bytecode of imported modules. Furthermore, imported +modules are themselves compiled as necessary, including updating the +bytecode and dependency files for the imported modules, transitively. + +Continuing the @exec{mzc a.scm} example from the previous section, the +@|mzc| creates @filepath{compiled/a_scm.dep}, +@filepath{compiled/b_scm.dep}, and @filepath{compiled/c_scm.dep} at +the same time as the @filepath{.zo} files. The +@filepath{compiled/a_scm.dep} file records the dependency of +@filepath{a.scm} on @filepath{b.scm}, @filepath{c.scm} and the +@schememodname[scheme] library. If the @filepath{b.scm} file is +modified (so that its timestamp changes), then running + +@commandline{mzc a.scm} + +again rebuilds @filepath{compiled/a_ss.zo} and +@filepath{compiled/b_ss.zo}. + +For module files that are within library collections, @exec{setup-plt} +uses the same @filepath{.zo} and @filepath{.dep} conventions and files +as @|mzc|, so the two tools can be used together. + +@; ---------------------------------------------------------------------- + +@section{Scheme Compilation Manager API} + +@defmodule[compiler/cm]{The @schememodname[compiler/cm] module +implements the compilation and dependency management used by @|mzc| +and @exec{setup-plt}.} + +@defproc[(make-compilation-manager-load/use-compiled-handler) + (path? (or/c symbol? false/c) . -> . any)]{ + +Returns a procedure suitable as a value for the +@scheme[current-load/use-compiled] parameter. The returned procedure +passes it arguments on to the @scheme[current-load/use-compiled] +procedure that is installed when +@scheme[make-compilation-manager-load/use-compiled-handler] is called, +but first it automatically compiles a source file to a @filepath{.zo} +file if + +@itemize{ + + @item{the file is expected to contain a module (i.e., the second + argument to the handler is a symbol);} + + @item{the value of each of @scheme[current-eval], + @scheme[current-load], and @scheme[current-namespace] is the same as + when @scheme[make-compilation-manager-load/use-compiled-handler] was + called;} + + @item{the value of @scheme[use-compiled-file-paths] contains the + first path that was present when + @scheme[make-compilation-manager-load/use-compiled-handler] was + called;} + + @item{the value of @scheme[current-load/use-compiled] is the result + of this procedure; and} + + @item{one of the following holds: + + @itemize{ + + @item{the source file is newer than the @filepath{.zo} file in the + first sub-directory listed in @scheme[use-compiled-file-paths] + (at the time that + @scheme[make-compilation-manager-load/use-compiled-handler] + was called)} + + @item{no @filepath{.dep} file exists next to the @filepath{.zo} + file;} + + @item{the version recorded in the @filepath{.dep} file does not + match the result of @scheme[(version)];} + + @item{one of the files listed in the @filepath{.dep} file has a + @filepath{.zo} timestamp newer than the one recorded in the + @filepath{.dep} file.} + + }} + +} + +After the handler procedure compiles a @filepath{.zo} file, it creates +a corresponding @filepath{.dep} file that lists the current version, +plus the @filepath{.zo} timestamp for every file that is +@scheme[require]d by the module in the compiled file. Additional +dependencies can be installed during compilation via +@schememodname[compiler/cm-accomplice]. + +The handler caches timestamps when it checks @filepath{.dep} files, +and the cache is maintained across calls to the same handler. The +cache is not consulted to compare the immediate source file to its +@filepath{.zo} file, which means that the caching behavior is +consistent with the caching of the default module name resolver (see +@scheme[current-module-name-resolver]). + +If @scheme[use-compiled-file-paths] contains an empty list when +@scheme[make-compilation-manager-load/use-compiled-handler] is called, +then @scheme[exn:fail:contract] exception is raised. + +@emph{Do not} install the result of +@scheme[make-compilation-manager-load/use-compiled-handler] when the +current namespace contains already-loaded versions of modules that may +need to be recompiled---unless the already-loaded modules are never +referenced by not-yet-loaded modules. References to already-loaded +modules may produce compiled files with inconsistent timestamps and/or +@filepath{.dep} files with incorrect information.} + + +@defproc[(managed-compile-zo [file path-string?]) void?]{ + +Compiles the given module source file to a @filepath{.zo}, installing +a compilation-manager handler while the file is compiled (so that +required modules are also compiled), and creating a @filepath{.dep} file +to record the timestamps of immediate files used to compile the source +(i.e., files @scheme[require]d in the source).} + + +@defboolparam[trust-existing-zos trust?]{ + +A parameter that is intended for use by @exec{setup-plt} when +installing with pre-built @filepath{.zo} files. It causes a +compilation-manager @scheme[load/use-compiled] handler to ``touch'' +out-of-date @filepath{.zo} files instead of re-compiling from source.} + + +@defproc[(make-caching-managed-compile-zo) + (path-string? . -> . void?)]{ + +Returns a procedure that behaves like @scheme[managed-compile-zo], but +a cache of timestamp information is preserved across calls to the +procedure.} + + +@defparam[manager-compile-notify-handler notify (path? . -> . any)]{ + +A parameter for a procedure of one argument that is called whenever a +compilation starts. The argument to the procedure is the file's path.} + + +@defparam[manager-compile-trace-handler notify (string? . -> . any)]{ + +A parameter for a procedure of one argument that is called to report + compilation-manager actions, such as checking a file. The argument to + the procedure is a string.} + +@; ---------------------------------------------------------------------- + +@section{Compilation Manager Hook for Syntax Transformers} + +@defmodule[compiler/cm-accomplice] + +@defproc[(register-external-file [file (and path? complete-path?)]) void?]{ + +Registers the complete path @scheme[file] with a compilation manager +implemented by @schememodname[compiler/cm], if one is active. The +compilation manager then records (in a @filepath{.dep} file) the path +as contributing to the implementation of the module currently being +compiled. Afterward, if the registered file is modified, the +compilation manager will know to recompile the module. + +The @scheme[include] macro, for example, calls this procedure with the +path of an included file as it expands an @scheme[include] form.} diff --git a/collects/scribblings/mzc/mzc.scrbl b/collects/scribblings/mzc/mzc.scrbl new file mode 100644 index 0000000000..3880a40f93 --- /dev/null +++ b/collects/scribblings/mzc/mzc.scrbl @@ -0,0 +1,53 @@ +#lang scribble/doc +@(require scribble/manual + "common.ss") + +@(define rare @emph{This mode is rarely useful.}) + +@title{@exec{mzc}: Compilation and Packaging} + +The @exec{mzc} tool is a kind of Swiss-army knife for PLT Scheme +compilation and packaging tasks. Its main action is determined through +one of the following command-line flags: + +@itemize{ + + @item{@as-index{@DFlag{make}} or @as-index{@Flag{k}} (the default) : + Compiles Scheme modules and all transitive imports to + bytecode. See @secref["make"].} + + @item{@as-index{@DFlag{cc}}, @as-index{@DFlag{ld}}, + @as-index{@DFlag{xform}} or @as-index{@Flag{x}} : Compiles, + links or transforms (for GC cooperation) C code to extend the + PLT Scheme runtime system. See @secref["cc"]. Using the + @scheme[scheme/foreign] FFI is often better; see + @other-manual['(lib "scribblings/foreign/foreign.scrbl")].} + + @item{@as-index{@DFlag{exe}}, @as-index{@DFlag{gui-exe}}, or + @as-index{@DFlag{exe-dir}} : Creates an executable to run a + Scheme module, or assembles all support libraries to move an + executable to a new filesystem. See @secref["exe"].} + + @item{@as-index{@DFlag{collection-plt}} or @as-index{@DFlag{plt}} : + packages Scheme code for installation into a different PLT + Scheme installation. See @secref["plt"]. @|PLaneT| is usually a + better alternative.} + + @item{@as-index{@DFlag{extension}}, @as-index{@Flag{e}}, + @as-index{@DFlag{c-source}}, or @as-index{@Flag{c}} : Compiles + Scheme code to a native-code extension via C. See + @secref["ext"]. @|rare|} + + @item{@as-index{@DFlag{zo}}, @as-index{@Flag{z}}, or + @as-index{@DFlag{collection-zo}} : Compiles Scheme code to + bytecode, without following transitive imports. See + @secref["zo"]. @|rare|} + +} + +@include-section["make.scrbl"] +@include-section["cc.scrbl"] +@include-section["exe.scrbl"] +@include-section["plt.scrbl"] +@include-section["ext.scrbl"] +@include-section["zo.scrbl"] diff --git a/collects/scribblings/mzc/plt.scrbl b/collects/scribblings/mzc/plt.scrbl new file mode 100644 index 0000000000..4ed848c836 --- /dev/null +++ b/collects/scribblings/mzc/plt.scrbl @@ -0,0 +1,5 @@ +#lang scribble/doc +@(require scribble/manual + "common.ss") + +@title[#:tag "plt"]{Packaging Library Collections} diff --git a/collects/scribblings/mzc/zo.scrbl b/collects/scribblings/mzc/zo.scrbl new file mode 100644 index 0000000000..f82baf0a95 --- /dev/null +++ b/collects/scribblings/mzc/zo.scrbl @@ -0,0 +1,8 @@ +#lang scribble/doc +@(require scribble/manual + "common.ss") + +@title[#:tag "zo"]{Compiling to Bytecode} + +The @DFlag{zo}/@Flag{z} mode for @|mzc| is an improverished form of +the default @DFlag{make}/@Flag{k} mode described in @secref["make"]. diff --git a/collects/scribblings/reference/mpairs.scrbl b/collects/scribblings/reference/mpairs.scrbl index 952f231c7f..0676fa0f71 100644 --- a/collects/scribblings/reference/mpairs.scrbl +++ b/collects/scribblings/reference/mpairs.scrbl @@ -95,14 +95,16 @@ Like @scheme[list-tail], but for @tech{mutable lists}.} Like @scheme[append], but for @tech{mutable lists}.} + @defproc*[([(mappend! [mlst mlist?] ...) mlist?] [(mappend! [mlst mlist?] ... [v any/c]) any/c])]{ -The @scheme[mappend!] procedure appends the given lists by mutating the tail of -each to refer to the next, using @scheme[set-mcdr!]. Empty lists are silently -ignored; in particular, the result of calling @scheme[mappend!] with one or -more empty lists is the same as the result of the call with the empty lists -removed from the set of arguments.} +The @scheme[mappend!] procedure appends the given lists by mutating +the tail of each to refer to the next, using @scheme[set-mcdr!]. Empty +lists are dropped; in particular, the result of calling +@scheme[mappend!] with one or more empty lists is the same as the +result of the call with the empty lists removed from the set of +arguments.} @defproc[(mreverse [mlst mlist?]) mlist?]{ @@ -110,6 +112,13 @@ removed from the set of arguments.} Like @scheme[reverse], but for @tech{mutable lists}.} +@defproc[(mreverse! [mlst mlist?]) mlist?]{ + +Like @scheme[mreverse], but destructively reverses the list by using +all of the mutable pairs in @scheme[mlst] and changing them with +@scheme[set-mcdr!].} + + @defproc[(mmap [proc procedure?] [mlst mlist?] ...+) mlist?]{ diff --git a/collects/scribblings/start/manuals.ss b/collects/scribblings/start/manuals.ss index d1c8862bfe..710c710724 100644 --- a/collects/scribblings/start/manuals.ss +++ b/collects/scribblings/start/manuals.ss @@ -79,7 +79,7 @@ the-cat] [else (fprintf (current-error-port) - "WARNING: base category: ~e from: ~e" + "WARNING: bad base category: ~e from: ~e\n" cat dir)])) ;; Priority diff --git a/collects/tests/mzscheme/mpair.ss b/collects/tests/mzscheme/mpair.ss new file mode 100644 index 0000000000..81b044e468 --- /dev/null +++ b/collects/tests/mzscheme/mpair.ss @@ -0,0 +1,55 @@ + +(load-relative "loadtest.ss") + +(Section 'mpair) + +(require scheme/mpair) + + +;; ---------------------------------------- +;; mreverse! + +(test null mreverse! null) +(test (mlist 1) mreverse! (mlist 1)) +(test (mlist 3 2 1) mreverse! (mlist 1 2 3)) + +(define a (mlist 1 2 3)) +(test (mlist 3 2 1) mreverse! a) +(test (mlist 1) values a) + +;; ---------------------------------------- +;; mappend! + +;; no args +(test null mappend!) + +;; one arg +(test (mlist 3 4 5) mappend! (mlist 3 4 5)) + +;; two args +(test (mlist 3 4 5 6) mappend! (mlist 3 4) (mlist 5 6)) + +(define a (mlist 3 4)) +(test (mlist 3 4 5 6) mappend! a (mlist 5 6)) +(test (mlist 3 4 5 6) values a) + +(test (mlist 3 4 5) mappend! null (mlist 3 4 5)) + +;; three args +(test (mlist 3 4 5 6 7 8) + mappend! (mlist 3 4) (mlist 5 6) (mlist 7 8)) +(test (mlist 3 4 5 6) mappend! (mlist 3 4) null (mlist 5 6)) + +(define a2 (mlist 3 4)) +(test (mlist 3 4 5 6) mappend! null a2 null (mlist 5 6)) +(test (mlist 3 4 5 6) values a2) + +(define a3result (mcons 3 'bogus)) +(set-mcdr! a3result a3result) +(define a3 (mlist 3)) +(test a3result mappend! a3 a3) +(test a3result values a3) + +;; ---------------------------------------- + +(report-errs) diff --git a/collects/tests/mzscheme/mzlib.ss b/collects/tests/mzscheme/mzlib.ss index 8706819290..c970d920ca 100644 --- a/collects/tests/mzscheme/mzlib.ss +++ b/collects/tests/mzscheme/mzlib.ss @@ -4,6 +4,8 @@ (load-relative "loadtest.ss") +(load-in-sandbox "mpair.ss") + (load-in-sandbox "md5.ss") (load-in-sandbox "etc.ss")