diff mbox series

[bug#53878,08/11] gnu: Add chez-scheme-for-racket.

Message ID 20220213215127.218952-9-philip@philipmcgrath.com
State Accepted
Headers show
Series Update Racket to 8.4. Adjust Chez Scheme packages. | expand

Checks

Context Check Description
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch success View Laminar job
cbaines/issue success View issue
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch success View Laminar job
cbaines/issue success View issue

Commit Message

Philip McGrath Feb. 13, 2022, 9:51 p.m. UTC
The Racket variant of Chez Scheme can be used to support platforms that
are not yet supported by upstream Chez Scheme.

In the process, we also add packages for 'racket-vm-cgc',
'racket-vm-bc', and 'racket-vm-cs'. A future commit will change
'racket-minimal' to use the Racket VM implementation that best supports
the target system.

* gnu/packages/patches/racket-enable-scheme-backport.patch: New patch.
* gnu/local.mk (dist_patch_DATA): Add it.
* gnu/packages/chez-and-racket-bootstrap.scm (racket-vm-cgc):
(racket-vm-bc):
(racket-vm-cs):
(chez-scheme-for-racket-bootstrap-bootfiles):
(chez-scheme-for-racket): New variables.
---
 gnu/local.mk                                  |   1 +
 gnu/packages/chez-and-racket-bootstrap.scm    | 489 +++++++++++++++++-
 .../racket-enable-scheme-backport.patch       | 465 +++++++++++++++++
 3 files changed, 948 insertions(+), 7 deletions(-)
 create mode 100644 gnu/packages/patches/racket-enable-scheme-backport.patch

Comments

Liliana Marie Prikler Feb. 14, 2022, 3:18 p.m. UTC | #1
Hi,

Am Sonntag, dem 13.02.2022 um 16:51 -0500 schrieb Philip McGrath:
> [...]
> * gnu/packages/chez-and-racket-bootstrap.scm (racket-vm-cgc):
> (racket-vm-bc):
> (racket-vm-cs):
> (chez-scheme-for-racket-bootstrap-bootfiles):
> (chez-scheme-for-racket): New variables.
One patch per package is probably better.

> [...] One way of thinking about the
> +;; bounary between the Racket VM and Racket programs is that the VM
> implements
boundary.

> +;; the primitives accessed by the 'ffi/unsafe/vm' library. Another
> perspective
> +;; is that DrRacket's ``Open defining file''/``Jump to definition''
> features
> +;; can navigate into Racket programs, including into the
> implementation of
> +;; 'racket/base', but can not jump into the implementation of the
> Racket VM
> +;; itself. A third, related perspective is that Racket code is
> usually
> +;; installed with source files alongside compiled code (though this
> is not
> +;; mandatory), whereas the Racket VM is installed only in compiled
> form.
> [...]
> +;; output. The function 'racket-vm-for-system' returns the
> recomended Racket
> +;; VM package for a given system.
This is a very long comment.  Consider how much of it is actually
necessary and how much of it is not (do I really need to know about the
capabilities of DrRacket for instance?)

> +;; Bootstrapping Racket:
> +;; ---------------------
> +;;
> +;; Here's how bootstrapping Racket works:
> +;;
> +;;   - Racket BC [CGC] can be built with only a C compiler (except
> for
> +;;     one caveat discussed below).
> +;;   - Racket BC [3M] needs an existing Racket to run "xform",
> +;;     which transforms its own C source code to add additional
> annotations
> +;;     for the precise garbage collector.
> +;;   - Racket CS needs (bootfiles for) Racket's fork of Chez Scheme.
> +;;     It also needs an existing Racket to compile Racket-
> implemented
> +;;     parts of the runtime system to R6RS libraries.
> +;;   - Chez Scheme also needs bootfiles for itself, but Racket can
> simulate
> +;;     enough of Chez Scheme to load Racket's fork of the Chez
> Scheme compiler
> +;;     purely from source into Racket and apply the compiler to
> itself,
> +;;     producing the needed bootfiles (albeit very slowly).
> +;;     Any variant of Racket since version 7.1 can run the
> simulation.
> +;;
> +;; So, we build CGC to build 3M to build bootfiles and CS.
This block I'd consider necessary, but again slightly on the verbose
end.

> +;; (Note: since the CGC variant is basically only for bootstrapping,
> we
> +;; often use "BC" to mean "3M", consistent with `(banner)` and the
> +;; suffixes used on executables when more than one variant co-
> exists.)
> +;;
> +;; One remaining bootstrapping limitation is that Racket's reader,
> module
> +;; system, and macro expander are implemented in Racket. For Racket
> CS,
> +;; they are compiled to R6RS libraries as discussed above. This note
> from the
> +;; README file applies to all such subsystems:
> +;;
> +;;     The Racket version must be practically the same as the
> current Racket
> +;;     verson, although it can be the Racket BC implementation
> (instead of
> +;;     the Racket CS implementation).
> +;;
> +;;     Unlike Chez Scheme boot files, the files generated in
> "schemified"
> +;;     are human-readable and -editable Scheme code. That provides a
> way
> +;;     out of bootstrapping black holes, even without BC.
> +;;
> +;; However, other Racket subsystems implemented in Racket for Racket
> CS
> +;; use older C implementations for Racket BC, whereas the reader,
> expander,
> +;; and module system were completely replaced with the Racket
> implementation
> +;;
> +;; For Racket BC, the compiled "linklet" s-expressions (primitive
> modules)
> +;; are embeded in C as a static string constant. Eventually, they
> are further
> +;; compiled by the C-implemented Racket BC bytecode and JIT
> compilers.
> +;; (On platforms where Racket BC's JIT is not supported, yet another
> compiler
> +;; instead compiles the linklets to C code, but this is not a
> bootstrapping
> +;; issue.)
> +;;
Again, you want to be brief and understandable.  What does this mean in
practise?  Do we have racket bootstrapped yet or is there still some
magic hidden within?

>  ;; Code:
>  
>  (define (chez-machine->unthreaded mach)
> @@ -189,19 +330,19 @@ (define* (nix-system->chez-machine #:optional
> (system (%current-system))
>                  (chez-machine->threaded mach)))))))
>  
>  ;;
> -;; Chez Scheme:
> +;; Chez auxiliary G-expressions:
>  ;;
>  
>  (define unbundle-chez-submodules
>    #~(begin
>        (use-modules (guix build utils))
>        (for-each (lambda (dir)
> -                (when (directory-exists? dir)
> -                  (delete-file-recursively dir)))
> -              '("stex"
> -                "nanopass"
> -                "lz4"
> -                "zlib"))))
> +                  (when (directory-exists? dir)
> +                    (delete-file-recursively dir)))
> +                '("stex"
> +                  "nanopass"
> +                  "lz4"
> +                  "zlib"))))
As in one of your previous patches, you're mixing cosmetic changes with
non-cosmetic ones.  This one could be prevented by correctly indenting
it in the patch that introduces it.

>  (define unpack-nanopass+stex
>    #~(begin
> @@ -216,6 +357,234 @@ (define unpack-nanopass+stex
>            ;; otherwise, it will try to download submodules
>            (display "# to placate ../configure")))))
>  
> +;;
> +;; Racket VM:
> +;;
> +
> +(define (racket-vm-common-configure-flags)
> +  ;; under a lambda extraction to avoid evaluating bash-minimal too
> early
> +  #~`(,@(cond
> +         ((false-if-exception
> +           (search-input-file %build-inputs "/bin/libtool"))
> +          => (lambda (libtool)
> +               (list (string-append "--enable-lt=" libtool))))
> +         (else
> +          '()))
> +      ,@(cond
> +         ((false-if-exception
> +           (search-input-file %build-inputs "/opt/racket-
> vm/bin/racket"))
Did we have /opt/racket... before?  We should probably avoid such
paths.
> +          => (lambda (racket)
> +               (list (string-append "--enable-racket=" racket))))
> +         (else
> +          '()))
> +      ,(string-append "CPPFLAGS=-DGUIX_RKTIO_PATCH_BIN_SH="
> +                      #$(file-append bash-minimal "/bin/sh"))
> +      "--disable-strip"
> +      "--enable-origtree")
For the record, why do you need double quoting here?  Would ungexp-
splicing extract this too soon?

> +(define-public racket-vm-cgc
> +  ;; Eventually, it may make sense for some vm packages to not be
> hidden,
> +  ;; but this one is especially likely to remain hidden.
> +  (hidden-package
> +   (package
> +     (name "racket-vm-cgc")
> +     (version "8.4")
> +     ;; ^ Remember to also update the version of
> +     ;;   chez-scheme-for-racket-bootstrap-bootfiles
> +     (source
> +      (origin
> +        (method git-fetch)
> +        (uri (git-reference
> +              (url "https://github.com/racket/racket")
> +              (commit (string-append "v" version))))
> +        (sha256
> +         (base32
> "1vpl66gdgc8rnldmn8rmb7ar9l057jqjvgpfn29k57i3c5skr8s6"))
> +        (file-name (git-file-name "racket" version))
> +        (patches (search-patches "racket-minimal-sh-via-rktio.patch"
> +                                 ;; Remove by Racket 8.5:
> +                                 "racket-enable-scheme-
> backport.patch"))
> +        (modules '((guix build utils)))
> +        (snippet
> +         #~(begin
> +             ;; Unbundle Chez submodules.
> +             (with-directory-excursion "racket/src/ChezScheme"
> +               #$unbundle-chez-submodules)
> +             ;; Unbundle libffi.
> +             (delete-file-recursively
> "racket/src/bc/foreign/libffi")))))
> +     (inputs (list ncurses ;; <- common to all variants (for
> #%terminal)
> +                   bash-minimal ;; <- common to all variants (for
> `system`)
> +                   libffi)) ;; <- only for BC variants
> +     (native-inputs (list libtool)) ;; <- only for BC variants
> +     (outputs '("out" "debug"))
> +     (build-system gnu-build-system)
> +     (arguments
> +      (list
> +       #:configure-flags
> +       #~(cons "--enable-cgcdefault"
> +               #$(racket-vm-common-configure-flags))
> +       ;; Tests are in packages like racket-test-core and
> +       ;; main-distribution-test that aren't part of the main
> +       ;; distribution.
> +       #:tests? #f
> +       ;; Upstream recommends #:out-of-source?, and it does
> +       ;; help with debugging, but it confuses `install-license-
> files`.
> +       #:modules '((ice-9 match)
> +                   (ice-9 regex)
> +                   (guix build gnu-build-system)
> +                   (guix build utils))
> +       #:strip-directories #~'("opt/racket-vm/bin"
> +                               "opt/racket-vm/lib")
> +       #:phases
> +       #~(let ()
> +           (define* ((wrap-racket-vm-outputs phase) . args)
> +             (apply
> +              phase
> +              (let loop ((args args))
> +                (match args
> +                  ((#:outputs outputs . args)
> +                   `(#:outputs
> +                     ,(let loop ((outputs outputs))
> +                        (match outputs
> +                          ((("out" . out) . outputs)
> +                           `(("out" . ,(string-append out
> "/opt/racket-vm/"))
> +                             ,@outputs))
> +                          ((other . outputs)
> +                           (cons other (loop outputs)))))
> +                     ,@args))
> +                  ((arg . args)
> +                   (cons arg (loop args)))))))
Why?


Cheers
Philip McGrath Feb. 16, 2022, 7:58 p.m. UTC | #2
Hi,

On 2/14/22 10:18, Liliana Marie Prikler wrote:
> Hi,
> 
> Am Sonntag, dem 13.02.2022 um 16:51 -0500 schrieb Philip McGrath:
>> [...]
>> * gnu/packages/chez-and-racket-bootstrap.scm (racket-vm-cgc):
>> (racket-vm-bc):
>> (racket-vm-cs):
>> (chez-scheme-for-racket-bootstrap-bootfiles):
>> (chez-scheme-for-racket): New variables.
> One patch per package is probably better.

That's fine; I'll change it. (I thought that's what I'd suggested in 
<https://issues.guix.gnu.org/53878#11>.)

> 
>> [...] One way of thinking about the
>> +;; bounary between the Racket VM and Racket programs is that the VM
>> implements
> boundary.

Thanks, I'll fix it.

> 
>> +;; the primitives accessed by the 'ffi/unsafe/vm' library. Another
>> perspective
>> +;; is that DrRacket's ``Open defining file''/``Jump to definition''
>> features
>> +;; can navigate into Racket programs, including into the
>> implementation of
>> +;; 'racket/base', but can not jump into the implementation of the
>> Racket VM
>> +;; itself. A third, related perspective is that Racket code is
>> usually
>> +;; installed with source files alongside compiled code (though this
>> is not
>> +;; mandatory), whereas the Racket VM is installed only in compiled
>> form.
>> [...]
>> +;; output. The function 'racket-vm-for-system' returns the
>> recomended Racket
>> +;; VM package for a given system.
> This is a very long comment.  Consider how much of it is actually
> necessary and how much of it is not (do I really need to know about the
> capabilities of DrRacket for instance?)


I guess it would be ok to cut the explanation of the distinction between 
VM primitives and the ``built in'' collections, since the bottom line is 
that the truly primitive primitives aren't useful without the main 
collections. I'm not sure what else to cut that wouldn't leave room for 
confusion.

>> +;; (Note: since the CGC variant is basically only for bootstrapping,
>> we
>> +;; often use "BC" to mean "3M", consistent with `(banner)` and the
>> +;; suffixes used on executables when more than one variant co-
>> exists.)
>> +;;
>> +;; One remaining bootstrapping limitation is that Racket's reader,
>> module
>> +;; system, and macro expander are implemented in Racket. For Racket
>> CS,
>> +;; they are compiled to R6RS libraries as discussed above. This note
>> from the
>> +;; README file applies to all such subsystems:
>> +;;
>> +;;     The Racket version must be practically the same as the
>> current Racket
>> +;;     verson, although it can be the Racket BC implementation
>> (instead of
>> +;;     the Racket CS implementation).
>> +;;
>> +;;     Unlike Chez Scheme boot files, the files generated in
>> "schemified"
>> +;;     are human-readable and -editable Scheme code. That provides a
>> way
>> +;;     out of bootstrapping black holes, even without BC.
>> +;;
>> +;; However, other Racket subsystems implemented in Racket for Racket
>> CS
>> +;; use older C implementations for Racket BC, whereas the reader,
>> expander,
>> +;; and module system were completely replaced with the Racket
>> implementation
>> +;;
>> +;; For Racket BC, the compiled "linklet" s-expressions (primitive
>> modules)
>> +;; are embeded in C as a static string constant. Eventually, they
>> are further
>> +;; compiled by the C-implemented Racket BC bytecode and JIT
>> compilers.
>> +;; (On platforms where Racket BC's JIT is not supported, yet another
>> compiler
>> +;; instead compiles the linklets to C code, but this is not a
>> bootstrapping
>> +;; issue.)
>> +;;
> Again, you want to be brief and understandable.  What does this mean in
> practise?  Do we have racket bootstrapped yet or is there still some
> magic hidden within?

This is just the comment that is currently at the top of 
"gnu/packages/racket.scm", but moved to this file because this is now 
going to be where the bootstrapping happens. Are there specific thing 
you want to cut?

On the current state of bootstrapping, almost everything is bootstrapped 
from C, but the "expander" subsystem (which includes the reader and the 
module system) is not currently bootstrappable, though it is readily 
auditable. I made another attempt at an explanation in this email: 
https://lists.gnu.org/archive/html/guix-devel/2021-08/msg00103.html I'd 
welcome suggestions to improve the explanation!


>>   (define unbundle-chez-submodules
>>     #~(begin
>>         (use-modules (guix build utils))
>>         (for-each (lambda (dir)
>> -                (when (directory-exists? dir)
>> -                  (delete-file-recursively dir)))
>> -              '("stex"
>> -                "nanopass"
>> -                "lz4"
>> -                "zlib"))))
>> +                  (when (directory-exists? dir)
>> +                    (delete-file-recursively dir)))
>> +                '("stex"
>> +                  "nanopass"
>> +                  "lz4"
>> +                  "zlib"))))
> As in one of your previous patches, you're mixing cosmetic changes with
> non-cosmetic ones.  This one could be prevented by correctly indenting
> it in the patch that introduces it.

Sorry, I missed this in a previous round of indentation fixing.

>> +;;
>> +;; Racket VM:
>> +;;
>> +
>> +(define (racket-vm-common-configure-flags)
>> +  ;; under a lambda extraction to avoid evaluating bash-minimal too
>> early
>> +  #~`(,@(cond
>> +         ((false-if-exception
>> +           (search-input-file %build-inputs "/bin/libtool"))
>> +          => (lambda (libtool)
>> +               (list (string-append "--enable-lt=" libtool))))
>> +         (else
>> +          '()))
>> +      ,@(cond
>> +         ((false-if-exception
>> +           (search-input-file %build-inputs "/opt/racket-
>> vm/bin/racket"))
> Did we have /opt/racket... before?  We should probably avoid such
> paths.

We did not have "opt/racket-vm/" before---adding it was sort of the 
point of this patch series.

Is the reason to avoid it a dislike for "opt", or something else?

An ``in place'' build of Racket is not meant to be unpacked directly 
into some PREFIX where it will coexist with other software. The build is 
vaguely FHS-like in that e.g. it includes a "bin" directory, but it also 
e.g. has a "collects" directory at the top level, and it puts other 
things in paths like "etc/config.rktd" rather than "etc/racket/config.rktd".

Subdirectories of "opt" often have that sort of layout, so it seemed 
like a reasonable place to put it. I considered just embracing Guix not 
being tied to FHS and putting it directly in the store output, but in 
build-side code it turned out to be useful to be able to use 
`search-input-{file,directory}` without potentially confusing the 
in-place VM with an intermediate, potentially tethered layer.

If the question is, ``why do we want an in-place build?'', I can go into 
as much depth as you want, but it makes the build-side code easier to 
reason about, it's more compatible with Racket tools e.g. for 
cross-compilation, and it should help to reduce closure sizes by letting 
us build packages with non-tethered intermediate layers.

>> +          => (lambda (racket)
>> +               (list (string-append "--enable-racket=" racket))))
>> +         (else
>> +          '()))
>> +      ,(string-append "CPPFLAGS=-DGUIX_RKTIO_PATCH_BIN_SH="
>> +                      #$(file-append bash-minimal "/bin/sh"))
>> +      "--disable-strip"
>> +      "--enable-origtree")
> For the record, why do you need double quoting here?  Would ungexp-
> splicing extract this too soon?

I'm not 100% sure I'm following your question correctly, but yes, there 
were problems with referencing `bash-minimal` too early.

(An alternative I considered was to add these arguments in a wrapper 
around gnu-build-system's configure phase, so that #:configure-flags 
would be only for arguments that variants want to override, or plausibly 
might.)

> 
>> +(define-public racket-vm-cgc
>> +  ;; Eventually, it may make sense for some vm packages to not be
>> hidden,
>> +  ;; but this one is especially likely to remain hidden.
>> +  (hidden-package
>> +   (package
>> +     (name "racket-vm-cgc")
>> +     (version "8.4")
>> +     ;; ^ Remember to also update the version of
>> +     ;;   chez-scheme-for-racket-bootstrap-bootfiles
>> +     (source
>> +      (origin
>> +        (method git-fetch)
>> +        (uri (git-reference
>> +              (url "https://github.com/racket/racket")
>> +              (commit (string-append "v" version))))
>> +        (sha256
>> +         (base32
>> "1vpl66gdgc8rnldmn8rmb7ar9l057jqjvgpfn29k57i3c5skr8s6"))
>> +        (file-name (git-file-name "racket" version))
>> +        (patches (search-patches "racket-minimal-sh-via-rktio.patch"
>> +                                 ;; Remove by Racket 8.5:
>> +                                 "racket-enable-scheme-
>> backport.patch"))
>> +        (modules '((guix build utils)))
>> +        (snippet
>> +         #~(begin
>> +             ;; Unbundle Chez submodules.
>> +             (with-directory-excursion "racket/src/ChezScheme"
>> +               #$unbundle-chez-submodules)
>> +             ;; Unbundle libffi.
>> +             (delete-file-recursively
>> "racket/src/bc/foreign/libffi")))))
>> +     (inputs (list ncurses ;; <- common to all variants (for
>> #%terminal)
>> +                   bash-minimal ;; <- common to all variants (for
>> `system`)
>> +                   libffi)) ;; <- only for BC variants
>> +     (native-inputs (list libtool)) ;; <- only for BC variants
>> +     (outputs '("out" "debug"))
>> +     (build-system gnu-build-system)
>> +     (arguments
>> +      (list
>> +       #:configure-flags
>> +       #~(cons "--enable-cgcdefault"
>> +               #$(racket-vm-common-configure-flags))
>> +       ;; Tests are in packages like racket-test-core and
>> +       ;; main-distribution-test that aren't part of the main
>> +       ;; distribution.
>> +       #:tests? #f
>> +       ;; Upstream recommends #:out-of-source?, and it does
>> +       ;; help with debugging, but it confuses `install-license-
>> files`.
>> +       #:modules '((ice-9 match)
>> +                   (ice-9 regex)
>> +                   (guix build gnu-build-system)
>> +                   (guix build utils))
>> +       #:strip-directories #~'("opt/racket-vm/bin"
>> +                               "opt/racket-vm/lib")
>> +       #:phases
>> +       #~(let ()
>> +           (define* ((wrap-racket-vm-outputs phase) . args)
>> +             (apply
>> +              phase
>> +              (let loop ((args args))
>> +                (match args
>> +                  ((#:outputs outputs . args)
>> +                   `(#:outputs
>> +                     ,(let loop ((outputs outputs))
>> +                        (match outputs
>> +                          ((("out" . out) . outputs)
>> +                           `(("out" . ,(string-append out
>> "/opt/racket-vm/"))
>> +                             ,@outputs))
>> +                          ((other . outputs)
>> +                           (cons other (loop outputs)))))
>> +                     ,@args))
>> +                  ((arg . args)
>> +                   (cons arg (loop args)))))))
> Why?
> 

Why what? Why 'wrap-racket-vm-outputs'? The wrapped phases don't have 
keywords like #:strip-directories, so adjusting their #:output argument 
is the only way to tell them where to find the files they need to 
operate on.

-Philip
diff mbox series

Patch

diff --git a/gnu/local.mk b/gnu/local.mk
index 72e086d465..8ffdd15ee2 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1787,6 +1787,7 @@  dist_patch_DATA =						\
   %D%/packages/patches/ripperx-missing-file.patch		\
   %D%/packages/patches/rpcbind-CVE-2017-8779.patch		\
   %D%/packages/patches/rtags-separate-rct.patch			\
+  %D%/packages/patches/racket-enable-scheme-backport.patch	\
   %D%/packages/patches/racket-minimal-sh-via-rktio.patch	\
   %D%/packages/patches/remake-impure-dirs.patch			\
   %D%/packages/patches/restic-0.9.6-fix-tests-for-go1.15.patch	\
diff --git a/gnu/packages/chez-and-racket-bootstrap.scm b/gnu/packages/chez-and-racket-bootstrap.scm
index 38708ab690..d2f78dfae2 100644
--- a/gnu/packages/chez-and-racket-bootstrap.scm
+++ b/gnu/packages/chez-and-racket-bootstrap.scm
@@ -34,8 +34,11 @@  (define-module (gnu packages chez-and-racket-bootstrap)
   #:use-module (guix build-system copy)
   #:use-module (guix build-system gnu)
   #:use-module (gnu packages)
+  #:use-module (gnu packages autotools)
+  #:use-module (gnu packages bash)
   #:use-module (gnu packages compression)
   #:use-module (gnu packages ghostscript)
+  #:use-module (gnu packages libffi)
   #:use-module (gnu packages linux)
   #:use-module (gnu packages ncurses)
   #:use-module (gnu packages netpbm)
@@ -62,6 +65,144 @@  (define-module (gnu packages chez-and-racket-bootstrap)
 ;; Putting the relevant definitions together in this module avoids having to
 ;; work around dependency cycles.
 ;;
+;; Anatomy of Racket:
+;; ------------------
+;;
+;; The main Racket Git repository (<https://github.com/racket/racket>) is
+;; organized broadly like this:
+;;
+;;     .
+;;     ├── Makefile
+;;     ├── pkgs/
+;;     └── racket/
+;;         ├── collects/
+;;         └── src/
+;;             ├── configure
+;;             ├── Makefile.in
+;;             ├── bc/
+;;             ├── cs/
+;;             ├── ChezScheme/
+;;             └── ...
+;;
+;; The 'racket/src/' directory contains the source of the runtime system, core
+;; compiler, and primitives for the major Racket implementations: this layer
+;; is called the ``Racket VM''. It is basically a normal autotools
+;; project. (Even when Racket VM implementations use components implemented in
+;; Racket, they are compiled in special modes to produce VM primitives.)
+;; (There are or have been experimental Racket VM implementations elsewhere,
+;; e.g. <https://github.com/pycket/pycket>.) One way of thinking about the
+;; bounary between the Racket VM and Racket programs is that the VM implements
+;; the primitives accessed by the 'ffi/unsafe/vm' library. Another perspective
+;; is that DrRacket's ``Open defining file''/``Jump to definition'' features
+;; can navigate into Racket programs, including into the implementation of
+;; 'racket/base', but can not jump into the implementation of the Racket VM
+;; itself. A third, related perspective is that Racket code is usually
+;; installed with source files alongside compiled code (though this is not
+;; mandatory), whereas the Racket VM is installed only in compiled form.
+;;
+;; The 'racket/collects/' directory contains ``built in'' Racket libraries
+;; that are not part of any package, including the implementation of
+;; 'racket/base': in particular, it must contain enough to implement `raco pkg
+;; install'. It is theoretically possible to use the Racket VM layer without
+;; the main collections, but it is not stable or useful.
+;;
+;; The 'pkgs/' directory contains Racket packages that are especially closely
+;; tied to the implementation of the Racket VM, including 'compiler-lib',
+;; 'racket-doc', and 'racket-test'. Some of these packages depend on Racket
+;; packages that are developed in other Git repositories, predominantly but
+;; not exclusively under the 'racket' GitHub organization. Conversely, not all
+;; of the packages developed in the main Git repository are part of the main
+;; Racket distribution.  (Additionally, components of the Racket VM that are
+;; implemented in Racket can be installed as packages, mostly for ease of
+;; development.)
+;;
+;; The top-level 'Makefile' is more like a directory of scripts: it has
+;; convienience targets for developing Racket, and it cooperates with the
+;; 'distro-build' package to assemble custom Racket distributions. It is not
+;; part of Racket source distributions: the root of a source distribution is
+;; basically 'racket/src' with some extra package sources and configuration
+;; added.
+;;
+;; A ''minimal Racket'' installation includes two packages: 'base', which is a
+;; sort of bridge between the current ``built-in'' collections and the package
+;; system's model of dependencies, and 'racket-lib', which, for installations
+;; that can not rely on a system package manager, pulls in the SQLite and
+;; OpenSSL shared libraries as platform-specific dependencies for use by the
+;; ``built-in'' collections.
+;;
+;; The main Racket distribution consists of installing the 'main-distribution'
+;; package and all of its dependencies.
+;;
+;; The default mode when building Racket (or installing it with the released
+;; installers) is an ``in-place build'', which produces a self-contained,
+;; relocatable, roughly FHS-like directory. (Racket also supports
+;; ``Unix-style'' installations, which rearrange the parts of an in-place
+;; build into Racket-specific subdirectories and generally tries to work for
+;; installation into an FHS-based system.) Certain tools, e.g. 'distro-build'
+;; and 'raco cross', are able to work with an in-place Racket build.
+;;
+;; This file defines the packages 'racket-vm-cgc', 'racket-vm-bc', and
+;; 'racket-vm-cs'. All three are in-place builds of 'racket/src/' and
+;; 'racket/collects/' and are installed to 'opt/racket-vm/' in the store
+;; output. The function 'racket-vm-for-system' returns the recomended Racket
+;; VM package for a given system.
+;;
+;; The file 'racket.scm' builds on these packages to define 'racket-minimal'
+;; and 'racket' packages. These use Racket's support for ``layered
+;; installations'', which allow an immutable base layer to be extended with
+;; additional packages. They use the layer configuration directly provide
+;; ready-to-install FHS-like trees, rather than relying on the built in
+;; ``Unix-style install'' mechanism.
+;;
+;; Bootstrapping Racket:
+;; ---------------------
+;;
+;; Here's how bootstrapping Racket works:
+;;
+;;   - Racket BC [CGC] can be built with only a C compiler (except for
+;;     one caveat discussed below).
+;;   - Racket BC [3M] needs an existing Racket to run "xform",
+;;     which transforms its own C source code to add additional annotations
+;;     for the precise garbage collector.
+;;   - Racket CS needs (bootfiles for) Racket's fork of Chez Scheme.
+;;     It also needs an existing Racket to compile Racket-implemented
+;;     parts of the runtime system to R6RS libraries.
+;;   - Chez Scheme also needs bootfiles for itself, but Racket can simulate
+;;     enough of Chez Scheme to load Racket's fork of the Chez Scheme compiler
+;;     purely from source into Racket and apply the compiler to itself,
+;;     producing the needed bootfiles (albeit very slowly).
+;;     Any variant of Racket since version 7.1 can run the simulation.
+;;
+;; So, we build CGC to build 3M to build bootfiles and CS.
+;;
+;; (Note: since the CGC variant is basically only for bootstrapping, we
+;; often use "BC" to mean "3M", consistent with `(banner)` and the
+;; suffixes used on executables when more than one variant co-exists.)
+;;
+;; One remaining bootstrapping limitation is that Racket's reader, module
+;; system, and macro expander are implemented in Racket. For Racket CS,
+;; they are compiled to R6RS libraries as discussed above. This note from the
+;; README file applies to all such subsystems:
+;;
+;;     The Racket version must be practically the same as the current Racket
+;;     verson, although it can be the Racket BC implementation (instead of
+;;     the Racket CS implementation).
+;;
+;;     Unlike Chez Scheme boot files, the files generated in "schemified"
+;;     are human-readable and -editable Scheme code. That provides a way
+;;     out of bootstrapping black holes, even without BC.
+;;
+;; However, other Racket subsystems implemented in Racket for Racket CS
+;; use older C implementations for Racket BC, whereas the reader, expander,
+;; and module system were completely replaced with the Racket implementation
+;;
+;; For Racket BC, the compiled "linklet" s-expressions (primitive modules)
+;; are embeded in C as a static string constant. Eventually, they are further
+;; compiled by the C-implemented Racket BC bytecode and JIT compilers.
+;; (On platforms where Racket BC's JIT is not supported, yet another compiler
+;; instead compiles the linklets to C code, but this is not a bootstrapping
+;; issue.)
+;;
 ;; Code:
 
 (define (chez-machine->unthreaded mach)
@@ -189,19 +330,19 @@  (define* (nix-system->chez-machine #:optional (system (%current-system))
                 (chez-machine->threaded mach)))))))
 
 ;;
-;; Chez Scheme:
+;; Chez auxiliary G-expressions:
 ;;
 
 (define unbundle-chez-submodules
   #~(begin
       (use-modules (guix build utils))
       (for-each (lambda (dir)
-                (when (directory-exists? dir)
-                  (delete-file-recursively dir)))
-              '("stex"
-                "nanopass"
-                "lz4"
-                "zlib"))))
+                  (when (directory-exists? dir)
+                    (delete-file-recursively dir)))
+                '("stex"
+                  "nanopass"
+                  "lz4"
+                  "zlib"))))
 
 (define unpack-nanopass+stex
   #~(begin
@@ -216,6 +357,234 @@  (define unpack-nanopass+stex
           ;; otherwise, it will try to download submodules
           (display "# to placate ../configure")))))
 
+;;
+;; Racket VM:
+;;
+
+(define (racket-vm-common-configure-flags)
+  ;; under a lambda extraction to avoid evaluating bash-minimal too early
+  #~`(,@(cond
+         ((false-if-exception
+           (search-input-file %build-inputs "/bin/libtool"))
+          => (lambda (libtool)
+               (list (string-append "--enable-lt=" libtool))))
+         (else
+          '()))
+      ,@(cond
+         ((false-if-exception
+           (search-input-file %build-inputs "/opt/racket-vm/bin/racket"))
+          => (lambda (racket)
+               (list (string-append "--enable-racket=" racket))))
+         (else
+          '()))
+      ,(string-append "CPPFLAGS=-DGUIX_RKTIO_PATCH_BIN_SH="
+                      #$(file-append bash-minimal "/bin/sh"))
+      "--disable-strip"
+      "--enable-origtree"))
+
+(define-public racket-vm-cgc
+  ;; Eventually, it may make sense for some vm packages to not be hidden,
+  ;; but this one is especially likely to remain hidden.
+  (hidden-package
+   (package
+     (name "racket-vm-cgc")
+     (version "8.4")
+     ;; ^ Remember to also update the version of
+     ;;   chez-scheme-for-racket-bootstrap-bootfiles
+     (source
+      (origin
+        (method git-fetch)
+        (uri (git-reference
+              (url "https://github.com/racket/racket")
+              (commit (string-append "v" version))))
+        (sha256
+         (base32 "1vpl66gdgc8rnldmn8rmb7ar9l057jqjvgpfn29k57i3c5skr8s6"))
+        (file-name (git-file-name "racket" version))
+        (patches (search-patches "racket-minimal-sh-via-rktio.patch"
+                                 ;; Remove by Racket 8.5:
+                                 "racket-enable-scheme-backport.patch"))
+        (modules '((guix build utils)))
+        (snippet
+         #~(begin
+             ;; Unbundle Chez submodules.
+             (with-directory-excursion "racket/src/ChezScheme"
+               #$unbundle-chez-submodules)
+             ;; Unbundle libffi.
+             (delete-file-recursively "racket/src/bc/foreign/libffi")))))
+     (inputs (list ncurses ;; <- common to all variants (for #%terminal)
+                   bash-minimal ;; <- common to all variants (for `system`)
+                   libffi)) ;; <- only for BC variants
+     (native-inputs (list libtool)) ;; <- only for BC variants
+     (outputs '("out" "debug"))
+     (build-system gnu-build-system)
+     (arguments
+      (list
+       #:configure-flags
+       #~(cons "--enable-cgcdefault"
+               #$(racket-vm-common-configure-flags))
+       ;; Tests are in packages like racket-test-core and
+       ;; main-distribution-test that aren't part of the main
+       ;; distribution.
+       #:tests? #f
+       ;; Upstream recommends #:out-of-source?, and it does
+       ;; help with debugging, but it confuses `install-license-files`.
+       #:modules '((ice-9 match)
+                   (ice-9 regex)
+                   (guix build gnu-build-system)
+                   (guix build utils))
+       #:strip-directories #~'("opt/racket-vm/bin"
+                               "opt/racket-vm/lib")
+       #:phases
+       #~(let ()
+           (define* ((wrap-racket-vm-outputs phase) . args)
+             (apply
+              phase
+              (let loop ((args args))
+                (match args
+                  ((#:outputs outputs . args)
+                   `(#:outputs
+                     ,(let loop ((outputs outputs))
+                        (match outputs
+                          ((("out" . out) . outputs)
+                           `(("out" . ,(string-append out "/opt/racket-vm/"))
+                             ,@outputs))
+                          ((other . outputs)
+                           (cons other (loop outputs)))))
+                     ,@args))
+                  ((arg . args)
+                   (cons arg (loop args)))))))
+           (modify-phases %standard-phases
+             (add-before 'configure 'initialize-config.rktd
+               (lambda* (#:key inputs #:allow-other-keys)
+                 (define (write-racket-hash alist)
+                   ;; inside must use dotted pair notation
+                   (display "#hash(")
+                   (for-each (match-lambda
+                               ((k . v)
+                                (format #t "(~s . ~s)" k v)))
+                             alist)
+                   (display ")\n"))
+                 (define maybe-release-catalog
+                   (let ((v #$(package-version this-package)))
+                     (if (string-match "^[0-9]+\\.[0-9]+($|\\.[0-8][0-9]*$)"
+                                       v)
+                         `(,(string-append
+                             "https://download.racket-lang.org/releases/"
+                             v
+                             "/catalog/"))
+                         '())))
+                 (mkdir-p "racket/etc")
+                 (with-output-to-file "racket/etc/config.rktd"
+                   (lambda ()
+                     (write-racket-hash
+                      `((build-stamp . "")
+                        (catalogs ,@maybe-release-catalog
+                                  #f)))))))
+             (add-before 'configure 'chdir
+               (lambda _
+                 (chdir "racket/src")))
+             (replace 'configure
+               (wrap-racket-vm-outputs
+                (assoc-ref %standard-phases 'configure)))
+             (replace 'patch-shebangs
+               (wrap-racket-vm-outputs
+                (assoc-ref %standard-phases 'patch-shebangs)))
+             (replace 'validate-runpath
+               (wrap-racket-vm-outputs
+                (assoc-ref %standard-phases 'validate-runpath)))
+             (replace 'make-dynamic-linker-cache
+               (wrap-racket-vm-outputs
+                (assoc-ref %standard-phases 'make-dynamic-linker-cache)))
+             (replace 'patch-dot-desktop-files
+               (wrap-racket-vm-outputs
+                (assoc-ref %standard-phases 'patch-dot-desktop-files)))))))
+     (home-page "https://racket-lang.org")
+     (synopsis "Old Racket implementation used for bootstrapping")
+     (description "This variant of the Racket BC (``before Chez'' or
+``bytecode'') implementation is not recommended for general use.  It uses
+CGC (a ``Conservative Garbage Collector''), which was succeeded as default in
+PLT Scheme version 370 (which translates to 3.7 in the current versioning
+scheme) by the 3M variant, which in turn was succeeded in version 8.0 by the
+Racket CS implementation.
+
+Racket CGC is primarily used for bootstrapping Racket BC [3M].  It may
+also be used for embedding applications without the annotations needed in C
+code to use the 3M garbage collector.")
+     ;; https://download.racket-lang.org/license.html
+     ;; The LGPL components are only used by Racket BC.
+     (license (list license:lgpl3+ license:asl2.0 license:expat)))))
+
+(define-public racket-vm-bc
+  (package
+    (inherit racket-vm-cgc)
+    (name "racket-vm-bc")
+    (native-inputs
+     (modify-inputs (package-native-inputs racket-vm-cgc)
+       (prepend racket-vm-cgc)))
+    (arguments
+     (substitute-keyword-arguments (package-arguments racket-vm-cgc)
+       ((#:configure-flags _ '())
+        #~(cons "--enable-bconly"
+                #$(racket-vm-common-configure-flags)))))
+    (synopsis "Racket BC [3M] implementation")
+    (description "The Racket BC (``before Chez'' or ``bytecode'')
+implementation was the default before Racket 8.0.  It uses a compiler written
+in C targeting architecture-independent bytecode, plus a JIT compiler on most
+platforms.  Racket BC has a different C API and supports a slightly different
+set of architectures than the current default runtime system, Racket CS (based
+on ``Chez Scheme'').  It is the recommended implementation for architectures
+that Racket CS doesn't support.
+
+This package is the normal implementation of Racket BC with a precise garbage
+collector, 3M (``Moving Memory Manager'').")))
+
+(define-public racket-vm-cs
+  (package
+    (inherit racket-vm-bc)
+    (name "racket-vm-cs")
+    (inputs
+     (modify-inputs (package-inputs racket-vm-cgc)
+       (prepend zlib lz4)
+       (delete "libffi")))
+    (native-inputs
+     (modify-inputs (package-native-inputs racket-vm-cgc)
+       (delete "libtool")
+       (prepend chez-scheme-for-racket
+                chez-nanopass-bootstrap
+                racket-vm-bc)))
+    (arguments
+     (substitute-keyword-arguments (package-arguments racket-vm-cgc)
+       ((#:phases those-phases #~%standard-phases)
+        #~(modify-phases #$those-phases
+            (add-after 'unpack 'unpack-nanopass+stex
+              (lambda args
+                (with-directory-excursion "racket/src/ChezScheme"
+                  #$unpack-nanopass+stex)))))
+       ((#:configure-flags _ '())
+        #~(cons* "--enable-csonly"
+                 "--enable-libz"
+                 "--enable-lz4"
+                 (string-append "--enable-scheme="
+                                #$(this-package-native-input
+                                   "chez-scheme-for-racket")
+                                "/bin/scheme")
+                 #$(racket-vm-common-configure-flags)))))
+    (synopsis "Racket CS implementation")
+    (description "The Racket CS implementation, which uses ``Chez Scheme'' as
+its core compiler and runtime system, has been the default Racket VM
+implemetation since Racket 8.0.  It performs better than the Racket BC
+implementation for most programs.
+
+Using the Racket VM packages directly is not recommended: instead, install the
+@code{racket-minimal} or @code{racket} packages.")
+    ;; https://download.racket-lang.org/license.html
+    ;; The LGPL components are only used by Racket BC.
+    (license (list license:asl2.0 license:expat))))
+
+;;
+;; Chez Scheme:
+;;
+
 (define-public chez-scheme-bootstrap-bootfiles
   (package
     (name "chez-scheme-bootstrap-bootfiles")
@@ -401,6 +770,112 @@  (define* (stex-make #:optional (suffix ""))
 and 32-bit PowerPC architectures.")
     (license license:asl2.0)))
 
+
+(define-public chez-scheme-for-racket-bootstrap-bootfiles
+  (package
+    (inherit chez-scheme-bootstrap-bootfiles)
+    (name "chez-scheme-for-racket-bootstrap-bootfiles")
+    (version "9.5.7.3")
+    ;; The version should match `(scheme-fork-version-number)`.
+    ;; See racket/src/ChezScheme/s/cmacros.ss c. line 360.
+    ;; It will always be different than the upstream version!
+    (source (package-source racket-vm-cgc))
+    (native-inputs (list chez-nanopass-bootstrap racket-vm-bc))
+    (arguments
+     (substitute-keyword-arguments
+         (package-arguments chez-scheme-bootstrap-bootfiles)
+       ((#:phases those-phases #~%standard-phases)
+        #~(modify-phases #$those-phases
+            (add-after 'unpack 'chdir
+              (lambda args
+                (chdir "racket/src/ChezScheme")))
+            (add-after 'chdir 'unpack-nanopass+stex
+              (lambda args
+                #$unpack-nanopass+stex))
+            (add-before 'install 'build
+              (lambda* (#:key native-inputs inputs #:allow-other-keys)
+                (invoke (search-input-file (or native-inputs inputs)
+                                           "/opt/racket-vm/bin/racket")
+                        "rktboot/main.rkt")))))))
+    (home-page "https://github.com/racket/ChezScheme")
+    ;; ^ This is downstream of https://github.com/racket/racket,
+    ;; but it's designed to be a friendly landing place for people
+    ;; who want a ChezScheme-shaped repositroy.
+    (synopsis "Chez Scheme bootfiles bootstrapped by Racket")
+    (description "Chez Scheme is a self-hosting compiler: building it
+requires ``bootfiles'' containing the Scheme-implemented portions compiled for
+the current platform.  (Chez can then cross-compile bootfiles for all other
+supported platforms.)
+
+The Racket package @code{cs-bootstrap} (part of the main Racket Git
+repository) implements enough of a Chez Scheme simulation to load the Chez
+Scheme compiler purely from source into Racket and apply the compiler to
+itself, thus bootstrapping Chez Scheme.  Bootstrapping takes about 10 times as
+long as using an existing Chez Scheme, but @code{cs-bootstrap} supports Racket
+7.1 and later, including the Racket BC variant.
+
+Note that the generated bootfiles are specific to Racket's fork of Chez
+Scheme, and @code{cs-bootstrap} does not currently support building upstream
+Chez Scheme.")
+    (properties `())
+    (license license:asl2.0)))
+
+(define-public chez-scheme-for-racket
+  (package
+    (inherit chez-scheme)
+    (name "chez-scheme-for-racket")
+    (version (package-version chez-scheme-for-racket-bootstrap-bootfiles))
+    (source (package-source racket-vm-cgc))
+    (inputs
+     (modify-inputs (package-inputs chez-scheme)
+       (delete "libx11" "util-linux:lib")))
+    (native-inputs
+     (modify-inputs (package-native-inputs chez-scheme)
+       (replace "chez-scheme-bootstrap-bootfiles"
+         chez-scheme-for-racket-bootstrap-bootfiles)))
+    (arguments
+     (substitute-keyword-arguments (package-arguments chez-scheme)
+       ((#:configure-flags cfg-flags #~'())
+        #~(cons "--disable-x11" #$cfg-flags))
+       ((#:phases those-phases #~%standard-phases)
+        #~(modify-phases #$those-phases
+            (add-after 'unpack 'chdir
+              (lambda args
+                (chdir "racket/src/ChezScheme")))))))
+    (supported-systems (filter nix-system->chez-machine
+                               %supported-systems))
+    (home-page
+     (package-home-page chez-scheme-for-racket-bootstrap-bootfiles))
+    (synopsis "Variant of Chez Scheme extended for Racket")
+    (description "This variant of Chez Scheme is extended to support the
+implementation of Racket.  It may be useful on platforms that are not yet
+supported by upstream Chez Scheme.
+
+Main additions to Chez Scheme in the Racket variant:
+@itemize @bullet
+@item
+AArch64 support
+@item
+Portable bytes (@code{pb}) support, which is mainly useful for bootstrapping
+a build on any supported platform
+@item
+Unboxed floating-point arithmetic and flvectors
+@item
+Type reconstruction during optimization (especially for safe code)
+@item
+Continuation attachments
+@item
+Parallel garbage collection, in-place garbage collection for old-generation
+objects (instead of always copying), and reachability-based memory
+accounting
+@item
+Ordered finalization, immobile (but collectable) objects, weak/ephemeron
+generic hash tables, and reference bytevectors
+@item
+Faster multiplication and division for large exact numbers
+@end itemize")
+    (license license:asl2.0)))
+
 ;;
 ;; Chez's bootstrap dependencies:
 ;;
diff --git a/gnu/packages/patches/racket-enable-scheme-backport.patch b/gnu/packages/patches/racket-enable-scheme-backport.patch
new file mode 100644
index 0000000000..3a5a4a3d82
--- /dev/null
+++ b/gnu/packages/patches/racket-enable-scheme-backport.patch
@@ -0,0 +1,465 @@ 
+From 8d7687842f099e3e7e60d3a83fed58b2c6a92863 Mon Sep 17 00:00:00 2001
+From: Matthew Flatt <mflatt@racket-lang.org>
+Date: Sun, 6 Feb 2022 10:36:09 -0700
+Subject: [PATCH 1/2] Chez Scheme: adapt bootfile build for supplied `Scheme=`
+
+(cherry picked from commit fca1e02349664060e10278ca2ce6577a949bebf5)
+
+(Fixed conflicts by dropping pbchunks and pbarch changes.)
+---
+ racket/src/ChezScheme/configure  | 15 ++++++++++++++-
+ racket/src/ChezScheme/s/Mf-base  |  4 ++--
+ racket/src/ChezScheme/s/Mf-cross |  4 +++-
+ 3 files changed, 19 insertions(+), 4 deletions(-)
+
+diff --git a/racket/src/ChezScheme/configure b/racket/src/ChezScheme/configure
+index 4515ffc105..0098829091 100755
+--- a/racket/src/ChezScheme/configure
++++ b/racket/src/ChezScheme/configure
+@@ -45,6 +45,7 @@ threads=yes
+ nothreads=no
+ temproot=""
+ help=no
++forceworkarea=no
+ gzipmanpages=yes
+ installowner=""
+ installgroup=""
+@@ -205,6 +206,9 @@ while [ $# != 0 ] ; do
+     --pb)
+       pb=yes
+       ;;
++    --force)
++      forceworkarea=yes
++      ;;
+     --installprefix=*)
+       installprefix=`echo $1 | sed -e 's/^--installprefix=//'`
+       ;;
+@@ -439,6 +443,7 @@ if [ "$help" = "yes" ]; then
+   echo "  --toolprefix=<prefix>             prefix tool (compiler, linker, ...) names"
+   echo "  --[no]gzip-man-pages              compress manual pages ($gzipmanpages)"
+   echo "  --workarea=<pathname>             build directory ($w)"
++  echo "  --force                           configure even without boot files"
+   echo "  CC=<C compiler>                   C compiler"
+   echo "  CPPFLAGS=<C preprocessor flags>   C preprocessor flags"
+   echo "  CFLAGS=<C compiler flags>         C compiler flags"
+@@ -721,8 +726,16 @@ case "${flagsmuni}" in
+         ;;
+ esac
+ 
++if [ "$w" = "$m" ] ; then
++    configuringin=""
++else
++    configuringin=" in $w"
++fi
++
+ if [ -f boot/$m/scheme.boot -o -f "$srcdir"/boot/$m/scheme.boot ] ; then
+-  echo "Configuring for $m"
++    echo "Configuring for $m$configuringin"
++elif [ "$forceworkarea" = yes ] ; then
++    echo "Configuring for $m$configuringin despite missing boot files"
+ else
+   if [ "$m" = "" ] ; then
+       maybem="<machine type>"
+diff --git a/racket/src/ChezScheme/s/Mf-base b/racket/src/ChezScheme/s/Mf-base
+index cc6178c973..1f4a967998 100644
+--- a/racket/src/ChezScheme/s/Mf-base
++++ b/racket/src/ChezScheme/s/Mf-base
+@@ -94,7 +94,7 @@ endif
+ # that Scheme and SCHEMEHEAPDIRS are set by Mf-cross to point to the host Scheme
+ # implementation
+ Scheme = ../bin/$m/scheme${ExeSuffix}
+-export SCHEMEHEAPDIRS=../boot/%m
++export SCHEMEHEAPDIRS=../boot/$m
+ export CHEZSCHEMELIBDIRS=.
+ 
+ # Define the libdirs separator character
+@@ -691,4 +691,4 @@ reset-one:
+ 
+ .PHONY: run
+ run:
+-	env SCHEMEHEAPDIRS=../boot/$m/ ../bin/$m/scheme $(ARGS)
++	env SCHEMEHEAPDIRS=${SCHEMEHEAPDIRS} ${Scheme} $(ARGS)
+diff --git a/racket/src/ChezScheme/s/Mf-cross b/racket/src/ChezScheme/s/Mf-cross
+index d796cbb459..397af59a28 100644
+--- a/racket/src/ChezScheme/s/Mf-cross
++++ b/racket/src/ChezScheme/s/Mf-cross
+@@ -43,5 +43,7 @@ x$(xm).$(m):
+ 	$(MAKE) -f Mf-cross m=$(m) xm=$(xm) i=f o=3 d=0 xpatch
+ 	mv xpatch x$(xm).$(m)
+ 
++ifneq ($(SCHEMEHEAPDIRS),:)
+ # Ensure that cross-compiling "nanopass.so" is rebuilt if the host compiler changed
+-nanopass.so: ${SCHEME} ${SCHEMEHEAPDIRS}/petite.boot ${SCHEMEHEAPDIRS}/scheme.boot
++nanopass.so: ${Scheme} ${SCHEMEHEAPDIRS}/petite.boot ${SCHEMEHEAPDIRS}/scheme.boot
++endif
+-- 
+2.32.0
+
+
+From 26c8e2c1d9b02ad85acef8bda40d92154cf0b699 Mon Sep 17 00:00:00 2001
+From: Matthew Flatt <mflatt@racket-lang.org>
+Date: Sun, 6 Feb 2022 11:03:30 -0700
+Subject: [PATCH 2/2] configure: make `--enable-scheme` work with an executable
+
+When the same Chez Scheme version as used by Racket is already
+available, then `--enable-scheme=...` can supply an executable. For
+cross builds, `--enable-scheme=...` can still supply a build
+directory, instead, as before.
+
+(cherry picked from commit 4f0e76855ce7e86107de495292a553469daf0b3f)
+---
+ racket/src/ChezScheme/makefiles/Makefile.in |  3 ++
+ racket/src/README.txt                       | 30 +++++++++++---
+ racket/src/configure                        |  8 +++-
+ racket/src/cs/README.txt                    |  6 ++-
+ racket/src/cs/c/Makefile.in                 | 44 ++++++++++++++++-----
+ racket/src/cs/c/configure                   | 24 +++++++++--
+ racket/src/cs/c/configure.ac                | 21 ++++++++--
+ 7 files changed, 112 insertions(+), 24 deletions(-)
+
+diff --git a/racket/src/ChezScheme/makefiles/Makefile.in b/racket/src/ChezScheme/makefiles/Makefile.in
+index c396efc851..3998ef9ccd 100644
+--- a/racket/src/ChezScheme/makefiles/Makefile.in
++++ b/racket/src/ChezScheme/makefiles/Makefile.in
+@@ -59,6 +59,9 @@ reset:
+ %.boot:
+ 	(cd $(workarea) && $(MAKE) $*.boot)
+ 
++auto.boot:
++	(cd $(workarea) && $(MAKE) $(defaultm).boot)
++
+ # <machine>.bootquick to build boot files for <machine>
+ # with o=3 d=0 for the cross compiler, and only after
+ # building the kernel for the configured machine
+diff --git a/racket/src/README.txt b/racket/src/README.txt
+index 98647aebce..d77310b4a4 100644
+--- a/racket/src/README.txt
++++ b/racket/src/README.txt
+@@ -354,6 +354,10 @@ variant of MinGW without "libdelayimp.a", get the implementation of
+ ========================================================================
+ 
+ Cross-compilation requires at least two flags to `configure`:
++`--host=OS` and either `--enable-racket=RACKET` or (for Racket CS)
++`--enable-scheme-SCHEME`.
++
++More information:
+ 
+  * `--host=OS`, where OS is something like `i386-gnu-linux` to
+    indicate the target platform.
+@@ -374,11 +378,27 @@ Cross-compilation requires at least two flags to `configure`:
+    run `configure` again (with no arguments) in a "local" subdirectory
+    to create a build for the current platform.
+ 
+-An additional flag is needed for building Racket CS, unless the flag
+-`--enable-racket=auto` is used:
+-
+- * `--enable-scheme=DIR`, where DIR is a path that has a "ChezScheme"
+-   directory where Chez Scheme is built for the host system.
++ * `--enable-scheme=SCHEME`, where SCHEME is a Chez Scheme executable
++   executable that runs on the build platform; the executable must be
++   the same version as used in Racket built for the target platform.
++ 
++   Supplying `--enable-scheme=DIR` is also supported in cross-build
++   mode, where DIR is a path that has a "ChezScheme" directory where
++   Chez Scheme is built for the host system.
++
++The `--enable-racket=RACKET` and `--enable-scheme=SCHEME` flags are
++allowed for non-cross builds, too:
++
++ * For Racket CS, supplying either selects a Racket or Chez Scheme
++   implementation used to create boot files to the build platform.
++   Suppling Chez Scheme is a much more direct path, but when Racket is
++   supplied, its version does not have to match the version being
++   built.
++
++ * For Racket BC, `--enable-racket=RACKET` selects a Racket for
++   prepare C sources to cooperate with garbage collection. Its version
++   needs to be close to the one being built, and potentially exactly
++   the same version.
+ 
+ Some less commonly needed `configure` flags are for Racket BC:
+ 
+diff --git a/racket/src/configure b/racket/src/configure
+index c9f3ba4419..1b53ec7ce2 100755
+--- a/racket/src/configure
++++ b/racket/src/configure
+@@ -9,6 +9,7 @@ pb_dir="$dir/ChezScheme/boot/pb"
+ use_cs=maybe
+ use_bc=maybe
+ supplied_racket=no
++supplied_scheme=no
+ enable_boothelp=
+ 
+ # We don't have to detect conflicts like `--enable-csdefault --enable-bcdefault`,
+@@ -34,6 +35,9 @@ for arg in $*; do
+         --enable-racket=*)
+             supplied_racket=yes
+             ;;
++        --enable-scheme=*)
++            supplied_scheme=yes
++            ;;
+         --help | -h)
+             echo $0:
+             echo see --help-bc or --help-cs, since the Racket CS build and the
+@@ -70,8 +74,8 @@ elif test "$use_cs" = "maybe" ; then
+ fi
+ 
+ if test "$use_cs" = "yes" ; then
+-    if test $use_bc = no  -a $supplied_racket = no -a ! -d "$pb_dir" ; then
+-        echo $0: must have $pb_dir or --enable-racket=... for --enable-csonly
++    if test $use_bc = no  -a $supplied_racket = no  -a $supplied_scheme = no  -a ! -d "$pb_dir" ; then
++        echo $0: must have $pb_dir, --enable-racket=... or --enable-scheme=... for --enable-csonly
+         exit 1
+     fi
+ 
+diff --git a/racket/src/cs/README.txt b/racket/src/cs/README.txt
+index 2ece417b78..8e6fc57b74 100644
+--- a/racket/src/cs/README.txt
++++ b/racket/src/cs/README.txt
+@@ -39,6 +39,11 @@ build:
+    installed in the "../ChezScheme/boot/pb" directory as described by
+    "../ChezScheme/BUILDING".
+ 
++   Supplying `--enable-scheme=...` is also an option if you alerady
++   have the same version of Chez Scheme built on the current platform.
++   Another build will be created, anyway, but more quickly than
++   without Chez Scheme.
++
+  * Racket is needed to generate the files in the "schemified"
+    directory from the sources in sibling directories like "../io". The
+    Racket version must be practically the same as the current Racket
+@@ -48,7 +53,6 @@ build:
+    Unlike Chez Scheme boot files, the files generated in "schemified"
+    are human-readable and -editable Scheme code. That provides a way
+    out of bootstrapping black holes, even without BC.
+-   
+ 
+ 
+ ========================================================================
+diff --git a/racket/src/cs/c/Makefile.in b/racket/src/cs/c/Makefile.in
+index 54a644a1d9..d73993f0fc 100644
+--- a/racket/src/cs/c/Makefile.in
++++ b/racket/src/cs/c/Makefile.in
+@@ -12,7 +12,9 @@ CS_HOST_WORKAREA_PREFIX = @CS_HOST_WORKAREA_PREFIX@
+ SCHEME_HOST_WORKAREA = $(CS_HOST_WORKAREA_PREFIX)$(SCHEME_WORKAREA)
+ SCHEME_BIN = $(SCHEME_HOST_WORKAREA)/$(MACH)/bin/$(MACH)/scheme
+ SCHEME_INC = $(SCHEME_HOST_WORKAREA)/$(MACH)/boot/$(MACH)
+-SCHEME = $(SCHEME_BIN) -B $(SCHEME_INC)/petite.boot -B $(SCHEME_INC)/scheme.boot
++SCHEME_built = $(SCHEME_BIN) -B $(SCHEME_INC)/petite.boot -B $(SCHEME_INC)/scheme.boot
++SCHEME_existing = @MAKE_SCHEME_SCHEME@
++SCHEME = $(SCHEME@USE_SCHEME_MODE@)
+ 
+ TARGET_MACH = @TARGET_MACH@
+ SCHEME_TARGET_INC = $(SCHEME_WORKAREA)/$(TARGET_MACH)/boot/$(TARGET_MACH)
+@@ -88,7 +90,7 @@ mainsrcdir = @srcdir@/../..
+ @INCLUDEDEP@ @srcdir@/../../version/version.mak
+ 
+ cs:
+-	$(MAKE) scheme@T_CROSS_MODE@
++	$(MAKE) scheme@MAKE_SCHEME_MODE@
+ 	$(MAKE) racket-so
+ 	cd rktio; $(MAKE)
+ 	$(MAKE) racketcs
+@@ -121,9 +123,13 @@ racket-so:
+ 
+ RACKET_SO_ENV = @CONFIGURE_RACKET_SO_COMPILE@
+ 
++TARGET_MACH_built = $(TARGET_MACH)
++TARGET_MACH_existing = xc-$(TARGET_MACH)
++XPATCH_FILE = $(SCHEME_WORKAREA)/$(TARGET_MACH@USE_SCHEME_MODE@)/s/xpatch
++
+ CS_PROGS = SCHEME="$(SCHEME)"
+ CS_OPTS = COMPRESS_COMP=@COMPRESS_COMP@ @ENABLE_OR_DISABLE_WPO@
+-CS_OPTScross = $(CS_OPTS) CSO=$(MACH) CROSS_COMP="--xpatch $(SCHEME_WORKAREA)/$(TARGET_MACH)/s/xpatch"
++CS_OPTScross = $(CS_OPTS) CSO=$(MACH) CROSS_COMP="--xpatch $(XPATCH_FILE)"
+ PASS_COMPILE_DEPS = EXTRA_COMPILE_DEPS="$(SCHEME_INC)/petite.boot $(SCHEME_INC)/scheme.boot"
+ 
+ build-racket-so:
+@@ -163,6 +169,15 @@ pb-bootquick:
+ 	cd $(SCHEME_WORKAREA) && $(MAKE) reset
+ 	$(SHELL) $(srcdir)/ready_boot.sh $(MACH) $(SCHEME_WORKAREA)
+ 
++scheme-via-scheme:
++	$(MAKE) $(SCHEME_WORKAREA)/boot/$(MACH)/scheme.boot
++	$(MAKE) mach-make
++
++$(SCHEME_WORKAREA)/boot/$(MACH)/scheme.boot:
++	mkdir -p $(SCHEME_WORKAREA)
++	$(MAKE) config-scheme CONFIG_SCHEME_MODE="$(CONFIG_SCHEME_MODE) --force"
++	cd $(SCHEME_WORKAREA) && $(MAKE) $(MACH).boot Scheme="$(SCHEME)" SCHEMEHEAPDIRS=: o=3 d=0 what=all
++
+ mach-make:
+ 	$(MAKE) config-scheme
+ 	cd $(SCHEME_WORKAREA) && $(MAKE)
+@@ -182,24 +197,33 @@ config-scheme:
+ 
+ scheme-cross:
+ 	env MAKE_BOOT_FOR_CROSS=yes SCHEME_SRC="$(SCHEME_DIR)" SCHEME_WORKAREA=$(SCHEME_WORKAREA) MACH="$(TARGET_MACH)" $(BOOTSTRAP_RACKET) "$(SCHEME_DIR)"/rktboot/make-boot.rkt
++	$(MAKE) finish-scheme-cross
++
++finish-scheme-cross:
+ 	$(SHELL) $(srcdir)/reset_boot.sh $(TARGET_MACH) $(SCHEME_WORKAREA)
+ 	cd $(SCHEME_WORKAREA) && "$(UP_SCHEME_DIR)"/configure @SCHEME_CROSS_CONFIG_ARGS@ $(SCHEME_CONFIG_VARS)
+ 	cd $(SCHEME_WORKAREA)/$(TARGET_MACH)/c && $(CHOST_HACK@T_CROSS_MODE@) $(MAKE) o=o cross=t
+-	$(MAKE) $(SCHEME_WORKAREA)/$(TARGET_MACH)/s/xpatch
++	$(MAKE) $(XPATCH_FILE)
++
++scheme-cross-via-scheme:
++	$(MAKE) $(SCHEME_WORKAREA)/boot/$(TARGET_MACH)/scheme.boot MACH=$(TARGET_MACH)
++	$(MAKE) finish-scheme-cross
+ 
+ # Rebuild patch file and cross "petite.boot" and "scheme.boot" when older
+-# than the build-host "scheme.boot" or when "make-boot.rkt" touchs dummy boot files
+-XPATCH_DEPS = $(SCHEME_HOST_WORKAREA)/$(MACH)/boot/$(MACH)/scheme.boot \
+-              $(SCHEME_WORKAREA)/boot/$(TARGET_MACH)/scheme.boot
++# than the build-<host "scheme.boot" or when "make-boot.rkt" touchs dummy boot files
++XPATCH_DEPS_built = $(SCHEME_HOST_WORKAREA)/$(MACH)/boot/$(MACH)/scheme.boot \
++                    $(SCHEME_WORKAREA)/boot/$(TARGET_MACH)/scheme.boot
++XPATCH_DEPS_existing = 
++XPATCH_DEPS = $(XPATCH_DEPS@USE_SCHEME_MODE@)
+ 
+-$(SCHEME_WORKAREA)/$(TARGET_MACH)/s/xpatch: $(XPATCH_DEPS)
++$(XPATCH_FILE): $(XPATCH_DEPS)
+ 	$(MAKE) bounce TARGET=build-xpatch-using-host
+ 
+ build-xpatch-using-host:
+ 	cd $(SCHEME_WORKAREA)/$(TARGET_MACH)/s && $(MAKE) -f Mf-cross m=$(MACH) xm=$(TARGET_MACH) Scheme="$(SCHEME_BIN)" SCHEMEHEAPDIRS="$(SCHEME_INC)"
+ 
+ XPATCH =
+-XPATCHcross = --xpatch $(SCHEME_WORKAREA)/$(TARGET_MACH)/s/xpatch
++XPATCHcross = --xpatch $(XPATCH_FILE)
+ 
+ racket.boot: racket.so
+ 	$(SCHEME) --script $(srcdir)/convert-to-boot.ss @BOOT_COMPRESS_COMP@ $(XPATCH@CROSS_MODE@) racket.so racket.boot $(TARGET_MACH)
+@@ -410,7 +434,7 @@ install-cross:
+ 	$(MAKE) compile-xpatch.$(TARGET_MACH)
+ 	$(MAKE) library-xpatch.$(TARGET_MACH)
+ 
+-SCHEME_XPATCH = $(SCHEME_WORKAREA)/$(TARGET_MACH)/s/xpatch
++SCHEME_XPATCH = $(XPATCH_FILE)
+ 
+ CROSS_SERVE_DEPS = $(srcdir)/mk-cross-serve.ss $(srcdir)/cross-serve.ss \
+                    $(srcdir)/../expander/env.ss $(srcdir)/../linklet/config.ss
+diff --git a/racket/src/cs/c/configure b/racket/src/cs/c/configure
+index 21695a431a..1eeef57753 100755
+--- a/racket/src/cs/c/configure
++++ b/racket/src/cs/c/configure
+@@ -654,6 +654,9 @@ MINGW
+ NOT_OSX
+ OSX
+ SETUP_BOOT_MODE
++USE_SCHEME_MODE
++MAKE_SCHEME_SCHEME
++MAKE_SCHEME_MODE
+ TT_CROSS_MODE
+ T_CROSS_MODE
+ CROSS_MODE
+@@ -1448,7 +1451,7 @@ Optional Features:
+   --enable-docs           build docs on install (enabled by default)
+   --enable-usersetup      setup user-specific files on install
+   --enable-racket=<path>  use <path> as Racket for build; or "auto" to create
+-  --enable-scheme=<path>  use <path> as host's build directory for cross
++  --enable-scheme=<path>  use <path> as host build for cross
+   --enable-mach=<mach>    use Chez Scheme machine type <mach>
+   --enable-target=<mach>  cross-build for Chez Scheme machine type <mach>
+   --enable-portable       prefer portable to host-specific
+@@ -2867,7 +2870,7 @@ show_explicitly_enabled "${enable_xonx}" "Unix style"
+ show_explicitly_enabled "${enable_libzo}" 'Compiled ".zo" files moved to lib'
+ 
+ show_explicitly_set "${enable_racket}" "Racket"
+-show_explicitly_set "${enable_scheme}" "Chez Scheme build directory"
++show_explicitly_set "${enable_scheme}" "Chez Scheme for build"
+ show_explicitly_set "${enable_mach}" "machine type"
+ show_explicitly_set "${enable_target}" "cross-build machine type"
+ show_explicitly_enabled "${enable_portable}" "portable"
+@@ -4745,9 +4748,21 @@ esac
+ 
+ SCHEME_DIR=${srcdir}/../../ChezScheme
+ MAKE_BUILD_SCHEME=checkout
++USE_SCHEME_MODE="_built"
++MAKE_SCHEME_MODE="${T_CROSS_MODE}"
+ 
+ if test "${enable_scheme}" != "" ; then
+-  CS_HOST_WORKAREA_PREFIX="${enable_scheme}/"
++   if test -d "${enable_scheme}" ; then
++     # Directory exists, so use it as a build directory
++     echo "Using supplied Scheme path as a build directory"
++     CS_HOST_WORKAREA_PREFIX="${enable_scheme}/"
++   else
++     # Directory does not exist, so assume it's an executable
++     echo "Using supplied Scheme path as an executable"
++     MAKE_SCHEME_MODE="${T_CROSS_MODE}-via-scheme"
++     MAKE_SCHEME_SCHEME="${enable_scheme}"
++     USE_SCHEME_MODE="_existing"
++   fi
+ fi
+ 
+ if test "${enable_racket}" != "" ; then
+@@ -6012,6 +6027,9 @@ SCHEME_CROSS_CONFIG_ARGS="--machine=${TARGET_MACH} --disable-x11 ${cs_auto_flags
+ 
+ 
+ 
++
++
++
+ 
+ 
+ 
+diff --git a/racket/src/cs/c/configure.ac b/racket/src/cs/c/configure.ac
+index 464ebe1760..aaee88156d 100644
+--- a/racket/src/cs/c/configure.ac
++++ b/racket/src/cs/c/configure.ac
+@@ -23,7 +23,7 @@ AC_ARG_ENABLE(compressmore, [  --enable-compressmore   compress compiled code ev
+ AC_ARG_ENABLE(compressboot, [  --enable-compressboot   compress boot files])
+ m4_include(../ac/path_arg.m4)
+ AC_ARG_ENABLE(racket,     [  --enable-racket=<path>  use <path> as Racket for build; or "auto" to create])
+-AC_ARG_ENABLE(scheme,     [  --enable-scheme=<path>  use <path> as host's build directory for cross])
++AC_ARG_ENABLE(scheme,     [  --enable-scheme=<path>  use <path> as host build for cross])
+ AC_ARG_ENABLE(mach,       [  --enable-mach=<mach>    use Chez Scheme machine type <mach>])
+ AC_ARG_ENABLE(target,     [  --enable-target=<mach>  cross-build for Chez Scheme machine type <mach>])
+ m4_include(../ac/portable_arg.m4)
+@@ -81,7 +81,7 @@ show_explicitly_disabled "${enable_compressboot}" "Compressed boot files"
+ show_explicitly_enabled "${enable_xonx}" "Unix style"
+ m4_include(../ac/path_show.m4)
+ show_explicitly_set "${enable_racket}" "Racket"
+-show_explicitly_set "${enable_scheme}" "Chez Scheme build directory"
++show_explicitly_set "${enable_scheme}" "Chez Scheme for build"
+ show_explicitly_set "${enable_mach}" "machine type"
+ show_explicitly_set "${enable_target}" "cross-build machine type"
+ m4_include(../ac/portable_show.m4)
+@@ -504,9 +504,21 @@ esac
+ 
+ SCHEME_DIR=${srcdir}/../../ChezScheme
+ MAKE_BUILD_SCHEME=checkout
++USE_SCHEME_MODE="_built"
++MAKE_SCHEME_MODE="${T_CROSS_MODE}"
+ 
+ if test "${enable_scheme}" != "" ; then
+-  CS_HOST_WORKAREA_PREFIX="${enable_scheme}/"
++   if test -d "${enable_scheme}" ; then
++     # Directory exists, so use it as a build directory
++     echo "Using supplied Scheme path as a build directory"
++     CS_HOST_WORKAREA_PREFIX="${enable_scheme}/"
++   else
++     # Directory does not exist, so assume it's an executable
++     echo "Using supplied Scheme path as an executable"
++     MAKE_SCHEME_MODE="${T_CROSS_MODE}-via-scheme"
++     MAKE_SCHEME_SCHEME="${enable_scheme}"
++     USE_SCHEME_MODE="_existing"
++   fi     
+ fi
+ 
+ if test "${enable_racket}" != "" ; then
+@@ -821,6 +833,9 @@ AC_SUBST(DIFF_MACH)
+ AC_SUBST(CROSS_MODE)
+ AC_SUBST(T_CROSS_MODE)
+ AC_SUBST(TT_CROSS_MODE)
++AC_SUBST(MAKE_SCHEME_MODE)
++AC_SUBST(MAKE_SCHEME_SCHEME)
++AC_SUBST(USE_SCHEME_MODE)
+ AC_SUBST(SETUP_BOOT_MODE)
+ AC_SUBST(OSX)
+ AC_SUBST(NOT_OSX)
+-- 
+2.32.0
+