diff mbox series

[bug#57050,v3,07/14] gnu: Add Zuo.

Message ID 3231fd55699bd60448e5aaa3ca8ddf9fbea085c6.1661416343.git.philip@philipmcgrath.com
State Accepted
Headers show
Series gnu: Update Racket to 8.6. Add Zuo. | 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

Commit Message

Philip McGrath Aug. 25, 2022, 8:54 a.m. UTC
* gnu/packages/patches/racket-backport-8.6-zuo.patch,
gnu/packages/patches/racket-zuo-bin-sh.patch: New patches.
* gnu/local.mk (dist_patch_DATA): Add them.
* gnu/packages/racket.scm (%zuo-version): New variable.
(zuo): New variable.
---
 gnu/local.mk                                  |   2 +
 .../patches/racket-backport-8.6-zuo.patch     | 481 ++++++++++++++++++
 gnu/packages/patches/racket-zuo-bin-sh.patch  |  74 +++
 gnu/packages/racket.scm                       |  51 ++
 4 files changed, 608 insertions(+)
 create mode 100644 gnu/packages/patches/racket-backport-8.6-zuo.patch
 create mode 100644 gnu/packages/patches/racket-zuo-bin-sh.patch

Comments

Efraim Flashner Aug. 25, 2022, 10:30 a.m. UTC | #1
On Thu, Aug 25, 2022 at 04:54:09AM -0400, Philip McGrath wrote:
> * gnu/packages/patches/racket-backport-8.6-zuo.patch,
> gnu/packages/patches/racket-zuo-bin-sh.patch: New patches.
> * gnu/local.mk (dist_patch_DATA): Add them.
> * gnu/packages/racket.scm (%zuo-version): New variable.
> (zuo): New variable.
> ---
>  gnu/local.mk                                  |   2 +
>  .../patches/racket-backport-8.6-zuo.patch     | 481 ++++++++++++++++++
>  gnu/packages/patches/racket-zuo-bin-sh.patch  |  74 +++
>  gnu/packages/racket.scm                       |  51 ++
>  4 files changed, 608 insertions(+)
>  create mode 100644 gnu/packages/patches/racket-backport-8.6-zuo.patch
>  create mode 100644 gnu/packages/patches/racket-zuo-bin-sh.patch
> 
> diff --git a/gnu/local.mk b/gnu/local.mk
> index babd54c8c6..c9c3061b33 100644
> --- a/gnu/local.mk
> +++ b/gnu/local.mk
> @@ -1769,8 +1769,10 @@ 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-backport-8.6-zuo.patch		\
>    %D%/packages/patches/racket-chez-scheme-bin-sh.patch		\
>    %D%/packages/patches/racket-rktio-bin-sh.patch		\
> +  %D%/packages/patches/racket-zuo-bin-sh.patch			\
>    %D%/packages/patches/remake-impure-dirs.patch			\
>    %D%/packages/patches/restic-0.9.6-fix-tests-for-go1.15.patch	\
>    %D%/packages/patches/retroarch-LIBRETRO_DIRECTORY.patch	\
> diff --git a/gnu/packages/patches/racket-backport-8.6-zuo.patch b/gnu/packages/patches/racket-backport-8.6-zuo.patch
> new file mode 100644
> index 0000000000..b86679b7ec
> --- /dev/null
> +++ b/gnu/packages/patches/racket-backport-8.6-zuo.patch
> @@ -0,0 +1,481 @@
> +From 8761fc06b188b9ca2f4b7f2b7d1235075c44a321 Mon Sep 17 00:00:00 2001
> +From: Matthew Flatt <mflatt@racket-lang.org>
> +Date: Sat, 23 Jul 2022 17:10:58 -0600
> +Subject: [PATCH 1/4] Zuo: support cross compilation via `configure` and
> + `CC_FOR_BUILD`
> +
> +(cherry picked from commit 798a989ba6d1a30c491a3120b2c2f1570ecab911)
> +---
> + racket/src/zuo/Makefile.in  |  7 ++++++-
> + racket/src/zuo/README.md    | 10 ++++++++++
> + racket/src/zuo/configure    | 15 +++++++++++++++
> + racket/src/zuo/configure.ac | 11 +++++++++++
> + 4 files changed, 42 insertions(+), 1 deletion(-)
> +
> +diff --git a/racket/src/zuo/Makefile.in b/racket/src/zuo/Makefile.in
> +index 5d16e145bf..747b584c5c 100644
> +--- a/racket/src/zuo/Makefile.in
> ++++ b/racket/src/zuo/Makefile.in
> +@@ -17,6 +17,11 @@ CPPFLAGS = @CPPFLAGS@
> + LDFLAGS = @LDFLAGS@
> + LIBS = @LIBS@
> + 
> ++CC_FOR_BUILD = @CC_FOR_BUILD@
> ++CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
> ++LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
> ++LIBS_FOR_BUILD = @LIBS_FOR_BUILD@
> ++
> + EMBED_LIBS = @EMBED_LIBS@
> + 
> + .PHONY: zuos-to-run-and-install
> +@@ -24,7 +29,7 @@ zuos-to-run-and-install: zuo
> + 	./zuo . zuos-to-run-and-install
> + 
> + zuo: $(srcdir)/zuo.c
> +-	$(CC) $(CPPFLAGS) $(CFLAGS) -DZUO_LIB_PATH='"'"$(srcdir)/lib"'"' -o zuo $(srcdir)/zuo.c $(LDFLAGS) $(LIBS)
> ++	$(CC_FOR_BUILD) $(FLAGS_FOR_BUILD) -DZUO_LIB_PATH='"'"$(srcdir)/lib"'"' -o zuo $(srcdir)/zuo.c $(LDFLAGS_FOR_BUILD) $(LIBS_FOR_BUILD)
> + 
> + .PHONY: check
> + check: zuo
> +diff --git a/racket/src/zuo/README.md b/racket/src/zuo/README.md
> +index 17c88ee9ec..3aad504b7e 100644
> +--- a/racket/src/zuo/README.md
> ++++ b/racket/src/zuo/README.md
> +@@ -84,6 +84,16 @@ A boot image is machine-independent, whether in a stand-alone file or
> + embedded in `.c` source.
> + 
> + 
> ++Cross Compiling
> ++---------------
> ++
> ++If you use `./configure --host=...` to cross compile, then you will
> ++also need to add something like `CC_FOR_BUILD=cc` as a `./configure`
> ++argument to specify the compiler for a `zuo` to use on the build
> ++machine. If necessary, you can also specify `CFLAGS_FOR_BUILD`,
> ++`LDFLAGS_FOR_BUILD`, and/or `LIBS_FOR_BUILD`.
> ++
> ++
> + Embedding Zuo in Another Application
> + ------------------------------------
> + 
> +diff --git a/racket/src/zuo/configure b/racket/src/zuo/configure
> +index 1fa34a3fe8..575ce07d96 100755
> +--- a/racket/src/zuo/configure
> ++++ b/racket/src/zuo/configure
> +@@ -589,6 +589,10 @@ enable_embed="zuo"
> + ac_subst_vars='LTLIBOBJS
> + LIBOBJS
> + EMBED_LIBS
> ++LIBS_FOR_BUILD
> ++LDFLAGS_FOR_BUILD
> ++CFLAGS_FOR_BUILD
> ++CC_FOR_BUILD
> + OBJEXT
> + EXEEXT
> + ac_ct_CC
> +@@ -2584,6 +2588,17 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
> + ac_compiler_gnu=$ac_cv_c_compiler_gnu
> + 
> + 
> ++if test "${CC_FOR_BUILD}" = ""; then
> ++  CC_FOR_BUILD='$(CC) -O2'
> ++  CFLAGS_FOR_BUILD='$(CPPFLAGS) $(CFLAGS)'
> ++  LDFLAGS_FOR_BUILD='$(LDFLAGS)'
> ++  LIBS_FOR_BUILD='$(LIBS)'
> ++fi
> ++
> ++
> ++
> ++
> ++
> + 
> + { $as_echo "$as_me:${as_lineno-$LINENO}: zuo libraries to embed: \"${EMBED_LIBS}\"" >&5
> + $as_echo "$as_me: zuo libraries to embed: \"${EMBED_LIBS}\"" >&6;}
> +diff --git a/racket/src/zuo/configure.ac b/racket/src/zuo/configure.ac
> +index 89b3c6391d..598ff79629 100644
> +--- a/racket/src/zuo/configure.ac
> ++++ b/racket/src/zuo/configure.ac
> +@@ -25,6 +25,17 @@ AS_IF([test "x$enable_embed" = xno],
> + AC_PROG_MAKE_SET()
> + AC_PROG_CC
> + 
> ++if test "${CC_FOR_BUILD}" = ""; then
> ++  CC_FOR_BUILD='$(CC) -O2'
> ++  CFLAGS_FOR_BUILD='$(CPPFLAGS) $(CFLAGS)'
> ++  LDFLAGS_FOR_BUILD='$(LDFLAGS)'
> ++  LIBS_FOR_BUILD='$(LIBS)'
> ++fi
> ++AC_SUBST(CC_FOR_BUILD)
> ++AC_SUBST(CFLAGS_FOR_BUILD)
> ++AC_SUBST(LDFLAGS_FOR_BUILD)
> ++AC_SUBST(LIBS_FOR_BUILD)
> ++
> + AC_SUBST(EMBED_LIBS)
> + AC_MSG_NOTICE([zuo libraries to embed: "${EMBED_LIBS}"])
> + 
> +-- 
> +2.32.0
> +
> +
> +From f65194ea41eb472fbdd45d5f6c13eabe5e681704 Mon Sep 17 00:00:00 2001
> +From: Matthew Flatt <mflatt@racket-lang.org>
> +Date: Sat, 23 Jul 2022 17:47:03 -0600
> +Subject: [PATCH 2/4] Zuo: sort hash keys
> +
> +Printing in a sorted order is helpful to make things more
> +deterministic independent of symbol inputs. Making `hash-keys`
> +produce a sorted list generalizes that determinism.
> +
> +(cherry picked from commit 4e7ffd3b365d01c5d0993c0b3fd24c9623962edf)
> +---
> + racket/src/zuo/build.zuo              |  5 ++-
> + racket/src/zuo/tests/hash.zuo         |  8 ++--
> + racket/src/zuo/zuo-doc/lang-zuo.scrbl | 18 +++++++--
> + racket/src/zuo/zuo.c                  | 57 ++++++++++++++++++++++++++-
> + 4 files changed, 78 insertions(+), 10 deletions(-)
> +
> +diff --git a/racket/src/zuo/build.zuo b/racket/src/zuo/build.zuo
> +index c1b5e8ce66..129240120a 100644
> +--- a/racket/src/zuo/build.zuo
> ++++ b/racket/src/zuo/build.zuo
> +@@ -47,7 +47,10 @@
> +     (target (at-dir (add-exe name))
> +             (lambda (path token)
> +               (rule (list image_zuo.c
> +-                          (input-data-target 'config config)
> ++                          (input-data-target 'config (cons
> ++                                                      lib-path
> ++                                                      (map (lambda (key) (hash-ref config key))
> ++                                                           '(CC CPPFLAGS CFLAGS LDFLAGS LIBS))))
> +                           (quote-module-path))
> +                     (lambda ()
> +                       (define l (split-path path))
> +diff --git a/racket/src/zuo/tests/hash.zuo b/racket/src/zuo/tests/hash.zuo
> +index a35741c730..0d3d7f3af6 100644
> +--- a/racket/src/zuo/tests/hash.zuo
> ++++ b/racket/src/zuo/tests/hash.zuo
> +@@ -35,9 +35,7 @@
> + 
> + (check (hash-keys (hash)) '())
> + (check (hash-keys (hash 'a 1)) '(a))
> +-(check (let ([keys (hash-keys (hash 'a 1 'b 2))])
> +-         (or (equal? keys '(a b))
> +-             (equal? keys '(b a)))))
> ++(check (hash-keys (hash 'a 1 'b 2)) '(a b)) ; always in order
> + (check (length (hash-keys (hash 'a 1 'b 2 'c 3))) 3)
> + (check (length (hash-keys (hash 'a 1 'b 2 'a 3))) 2)
> + (check-arg-fail (hash-keys 0) "not a hash table")
> +@@ -50,3 +48,7 @@
> + (check (hash-keys-subset? (hash 'a 1 'b 2) (hash 'b 1)) #f)
> + (check-arg-fail (hash-keys-subset? 0 (hash)) "not a hash table")
> + (check-arg-fail (hash-keys-subset? (hash) 0) "not a hash table")
> ++
> ++;; print sorts keys alphabetically:
> ++(check (~a (hash 'a 1 'b 2)) "#hash((a . 1) (b . 2))")
> ++(check (~a (hash 'b 2 'a 1)) "#hash((a . 1) (b . 2))")
> +diff --git a/racket/src/zuo/zuo-doc/lang-zuo.scrbl b/racket/src/zuo/zuo-doc/lang-zuo.scrbl
> +index 94641d041e..4605e47471 100644
> +--- a/racket/src/zuo/zuo-doc/lang-zuo.scrbl
> ++++ b/racket/src/zuo/zuo-doc/lang-zuo.scrbl
> +@@ -538,10 +538,20 @@ support to convert the textual form back into a hash table value.
> + 
> + Analogous to @realracket*[hash? hash hash-ref hash-set hash-remove
> + hash-keys hash-count hash-keys-subset?] from @racketmodname[racket].
> +-Besides being constrained to symbol keys, there is one additional
> +-difference: the third argument to @racket[hash-ref], when supplied,
> +-is always used as a value to return if a key is missing, as
> +-opposed to a failure thunk.}
> ++
> ++Besides being constrained to symbol keys, there are two additional
> ++differences:
> ++
> ++@itemlist[
> ++
> ++ @item{the third argument to @racket[hash-ref], when supplied, is
> ++       always used as a value to return if a key is missing, as
> ++       opposed to a failure thunk; and}
> ++
> ++ @item{the @racket[hash-keys] function returns interned keys sorted
> ++       alphabetically.}
> ++
> ++]}
> + 
> + 
> + @section{Procedures}
> +diff --git a/racket/src/zuo/zuo.c b/racket/src/zuo/zuo.c
> +index 2957d478af..88d5747326 100644
> +--- a/racket/src/zuo/zuo.c
> ++++ b/racket/src/zuo/zuo.c
> +@@ -1298,6 +1298,59 @@ static zuo_t *zuo_trie_keys(zuo_t *trie_in, zuo_t *accum) {
> +   return accum;
> + }
> + 
> ++/*======================================================================*/
> ++/* symbol-list sorting                                                  */
> ++/*======================================================================*/
> ++
> ++/* merge sort used to make hash printing deterministic */
> ++static zuo_t *zuo_symbol_list_sort(zuo_t *l_in) {
> ++  zuo_t *l, *left, *right, *first, *last;
> ++  zuo_uint_t len = 0, i;
> ++
> ++  for (l = l_in, len = 0; l != z.o_null; l = _zuo_cdr(l))
> ++    len++;
> ++
> ++  if (len < 2)
> ++    return l_in;
> ++
> ++  left = z.o_null;
> ++  for (l = l_in, i = len >> 1; i > 0; l = _zuo_cdr(l), i--)
> ++    left = zuo_cons(_zuo_car(l), left);
> ++  right = l;
> ++
> ++  left = zuo_symbol_list_sort(left);
> ++  right = zuo_symbol_list_sort(right);
> ++
> ++  first = last = z.o_null;
> ++  while ((left != z.o_null) && (right != z.o_null)) {
> ++    zuo_t *p;
> ++
> ++    if (strcmp(ZUO_STRING_PTR(((zuo_symbol_t *)_zuo_car(left))->str),
> ++               ZUO_STRING_PTR(((zuo_symbol_t *)_zuo_car(right))->str))
> ++        < 1) {
> ++      p = zuo_cons(_zuo_car(left), z.o_null);
> ++      left = _zuo_cdr(left);
> ++    } else {
> ++      p = zuo_cons(_zuo_car(right), z.o_null);
> ++      right = _zuo_cdr(right);
> ++    }
> ++
> ++    if (first == z.o_null)
> ++      first = p;
> ++    else
> ++      ((zuo_pair_t *)last)->cdr = p;
> ++    last = p;
> ++  }
> ++
> ++  ((zuo_pair_t *)last)->cdr = ((left != z.o_null) ? left : right);
> ++
> ++  return first;
> ++}
> ++
> ++static zuo_t *zuo_trie_sorted_keys(zuo_t *trie_in, zuo_t *accum) {
> ++  return zuo_symbol_list_sort(zuo_trie_keys(trie_in, accum));
> ++}
> ++
> + /*======================================================================*/
> + /* terminal support                                                     */
> + /*======================================================================*/
> +@@ -1571,7 +1624,7 @@ static void zuo_out(zuo_out_t *out, zuo_t *obj, zuo_print_mode_t mode) {
> +         out_string(out, "opaque");
> +       out_string(out, ">");
> +     } else if (obj->tag == zuo_trie_node_tag) {
> +-      zuo_t *keys = zuo_trie_keys(obj, z.o_null);
> ++      zuo_t *keys = zuo_trie_sorted_keys(obj, z.o_null);
> +       if (mode == zuo_print_mode) {
> +         out_string(out, "(hash");
> +         if (keys != z.o_null)
> +@@ -2587,7 +2640,7 @@ static zuo_t *zuo_hash_remove(zuo_t *ht, zuo_t *sym) {
> + 
> + static zuo_t *zuo_hash_keys(zuo_t *ht) {
> +   check_hash("hash-keys", ht);
> +-  return zuo_trie_keys(ht, z.o_null);
> ++  return zuo_trie_sorted_keys(ht, z.o_null);
> + }
> + 
> + static zuo_t *zuo_hash_keys_subset_p(zuo_t *ht, zuo_t *ht2) {
> +-- 
> +2.32.0
> +
> +
> +From f2eecaa1dd875479d2cf51566223b3d0d7b9f738 Mon Sep 17 00:00:00 2001
> +From: Matthew Flatt <mflatt@racket-lang.org>
> +Date: Sat, 23 Jul 2022 18:06:41 -0600
> +Subject: [PATCH 3/4] Zuo: check for nul characters in `string->symbol`
> +
> +(cherry picked from commit e20022ccfad40d0ba2e77aa75bc4f775018c781f)
> +---
> + racket/src/zuo/tests/symbol.zuo       |  3 +++
> + racket/src/zuo/zuo-doc/lang-zuo.scrbl |  4 ++-
> + racket/src/zuo/zuo.c                  | 37 +++++++++++++++++----------
> + 3 files changed, 29 insertions(+), 15 deletions(-)
> +
> +diff --git a/racket/src/zuo/tests/symbol.zuo b/racket/src/zuo/tests/symbol.zuo
> +index 7775aeeb04..5600a89755 100644
> +--- a/racket/src/zuo/tests/symbol.zuo
> ++++ b/racket/src/zuo/tests/symbol.zuo
> +@@ -19,3 +19,6 @@
> + (check (not (equal? 'apple (string->uninterned-symbol "apple"))))
> + (check-arg-fail (string->symbol 'apple) not-string)
> + (check-arg-fail (string->uninterned-symbol 'apple) not-string)
> ++
> ++(check-arg-fail (string->symbol "apple\0spice") "without a nul character")
> ++(check (symbol? (string->uninterned-symbol "apple\0spice")))
> +diff --git a/racket/src/zuo/zuo-doc/lang-zuo.scrbl b/racket/src/zuo/zuo-doc/lang-zuo.scrbl
> +index 4605e47471..07dd5815b0 100644
> +--- a/racket/src/zuo/zuo-doc/lang-zuo.scrbl
> ++++ b/racket/src/zuo/zuo-doc/lang-zuo.scrbl
> +@@ -500,7 +500,9 @@ back into Zuo.
> + )]{
> + 
> + Analogous to @realracket*[symbol? symbol->string string->symbol
> +-string->uninterned-symbol] from @racketmodname[racket].}
> ++string->uninterned-symbol] from @racketmodname[racket], but
> ++@racket[string->symbol] accepts only strings that do not contain the
> ++null character.}
> + 
> + 
> + @section{Hash Tables (Persistent Maps)}
> +diff --git a/racket/src/zuo/zuo.c b/racket/src/zuo/zuo.c
> +index 88d5747326..17f161826d 100644
> +--- a/racket/src/zuo/zuo.c
> ++++ b/racket/src/zuo/zuo.c
> +@@ -1323,7 +1323,7 @@ static zuo_t *zuo_symbol_list_sort(zuo_t *l_in) {
> + 
> +   first = last = z.o_null;
> +   while ((left != z.o_null) && (right != z.o_null)) {
> +-    zuo_t *p;
> ++    zuo_t *p, *s_left, *s_right;
> + 
> +     if (strcmp(ZUO_STRING_PTR(((zuo_symbol_t *)_zuo_car(left))->str),
> +                ZUO_STRING_PTR(((zuo_symbol_t *)_zuo_car(right))->str))
> +@@ -2573,8 +2573,28 @@ static zuo_t *zuo_substring(zuo_t *obj, zuo_t *start_i, zuo_t *end_i) {
> +   return zuo_sized_string((const char *)&((zuo_string_t *)obj)->s[s_idx], e_idx - s_idx);
> + }
> + 
> ++static int zuo_is_string_without_nul(zuo_t *obj) {
> ++  zuo_int_t i;
> ++
> ++  if ((obj->tag != zuo_string_tag)
> ++      || ZUO_STRING_LEN(obj) == 0)
> ++    return 0;
> ++
> ++  for (i = ZUO_STRING_LEN(obj); i--; ) {
> ++    if (((zuo_string_t *)obj)->s[i] == 0)
> ++      return 0;
> ++  }
> ++
> ++  return 1;
> ++}
> ++
> + static zuo_t *zuo_string_to_symbol(zuo_t *obj) {
> +-  check_string("string->symbol", obj);
> ++  if (!zuo_is_string_without_nul(obj)) {
> ++    const char *who = "string->symbol";
> ++    check_string(who, obj);
> ++    zuo_fail_arg(who, "string without a nul character", obj);
> ++  }
> ++
> +   return zuo_symbol_from_string(ZUO_STRING_PTR(obj), obj);
> + }
> + 
> +@@ -3577,18 +3597,7 @@ static void *zuo_envvars_block(const char *who, zuo_t *envvars)
> + #endif
> + 
> + static int zuo_is_path_string(zuo_t *obj) {
> +-  zuo_int_t i;
> +-
> +-  if ((obj->tag != zuo_string_tag)
> +-      || ZUO_STRING_LEN(obj) == 0)
> +-    return 0;
> +-
> +-  for (i = ZUO_STRING_LEN(obj); i--; ) {
> +-    if (((zuo_string_t *)obj)->s[i] == 0)
> +-      return 0;
> +-  }
> +-
> +-  return 1;
> ++  return zuo_is_string_without_nul(obj);
> + }
> + 
> + static zuo_t *zuo_path_string_p(zuo_t *obj) {
> +-- 
> +2.32.0
> +
> +
> +From de6618cb3819d25580e3cd400ea09c8cf4f673a9 Mon Sep 17 00:00:00 2001
> +From: Matthew Flatt <mflatt@racket-lang.org>
> +Date: Sat, 23 Jul 2022 19:50:46 -0600
> +Subject: [PATCH 4/4] Zuo: CPPFLAGS_FOR_BUILD, too
> +
> +(cherry picked from commit cf82706c4b298f654a04c4bc8d98dff39b62a2ac)
> +---
> + racket/src/zuo/Makefile.in  | 3 ++-
> + racket/src/zuo/configure    | 5 ++++-
> + racket/src/zuo/configure.ac | 4 +++-
> + 3 files changed, 9 insertions(+), 3 deletions(-)
> +
> +diff --git a/racket/src/zuo/Makefile.in b/racket/src/zuo/Makefile.in
> +index 747b584c5c..0376c038a8 100644
> +--- a/racket/src/zuo/Makefile.in
> ++++ b/racket/src/zuo/Makefile.in
> +@@ -19,6 +19,7 @@ LIBS = @LIBS@
> + 
> + CC_FOR_BUILD = @CC_FOR_BUILD@
> + CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
> ++CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
> + LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
> + LIBS_FOR_BUILD = @LIBS_FOR_BUILD@
> + 
> +@@ -29,7 +30,7 @@ zuos-to-run-and-install: zuo
> + 	./zuo . zuos-to-run-and-install
> + 
> + zuo: $(srcdir)/zuo.c
> +-	$(CC_FOR_BUILD) $(FLAGS_FOR_BUILD) -DZUO_LIB_PATH='"'"$(srcdir)/lib"'"' -o zuo $(srcdir)/zuo.c $(LDFLAGS_FOR_BUILD) $(LIBS_FOR_BUILD)
> ++	$(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) -DZUO_LIB_PATH='"'"$(srcdir)/lib"'"' -o zuo $(srcdir)/zuo.c $(LDFLAGS_FOR_BUILD) $(LIBS_FOR_BUILD)
> + 
> + .PHONY: check
> + check: zuo
> +diff --git a/racket/src/zuo/configure b/racket/src/zuo/configure
> +index 575ce07d96..7ac453e3bc 100755
> +--- a/racket/src/zuo/configure
> ++++ b/racket/src/zuo/configure
> +@@ -591,6 +591,7 @@ LIBOBJS
> + EMBED_LIBS
> + LIBS_FOR_BUILD
> + LDFLAGS_FOR_BUILD
> ++CPPFLAGS_FOR_BUILD
> + CFLAGS_FOR_BUILD
> + CC_FOR_BUILD
> + OBJEXT
> +@@ -2590,7 +2591,8 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
> + 
> + if test "${CC_FOR_BUILD}" = ""; then
> +   CC_FOR_BUILD='$(CC) -O2'
> +-  CFLAGS_FOR_BUILD='$(CPPFLAGS) $(CFLAGS)'
> ++  CPPFLAGS_FOR_BUILD='$(CPPFLAGS)'
> ++  CFLAGS_FOR_BUILD='$(CFLAGS)'
> +   LDFLAGS_FOR_BUILD='$(LDFLAGS)'
> +   LIBS_FOR_BUILD='$(LIBS)'
> + fi
> +@@ -2600,6 +2602,7 @@ fi
> + 
> + 
> + 
> ++
> + { $as_echo "$as_me:${as_lineno-$LINENO}: zuo libraries to embed: \"${EMBED_LIBS}\"" >&5
> + $as_echo "$as_me: zuo libraries to embed: \"${EMBED_LIBS}\"" >&6;}
> + 
> +diff --git a/racket/src/zuo/configure.ac b/racket/src/zuo/configure.ac
> +index 598ff79629..051ea0beb5 100644
> +--- a/racket/src/zuo/configure.ac
> ++++ b/racket/src/zuo/configure.ac
> +@@ -27,12 +27,14 @@ AC_PROG_CC
> + 
> + if test "${CC_FOR_BUILD}" = ""; then
> +   CC_FOR_BUILD='$(CC) -O2'
> +-  CFLAGS_FOR_BUILD='$(CPPFLAGS) $(CFLAGS)'
> ++  CPPFLAGS_FOR_BUILD='$(CPPFLAGS)'
> ++  CFLAGS_FOR_BUILD='$(CFLAGS)'
> +   LDFLAGS_FOR_BUILD='$(LDFLAGS)'
> +   LIBS_FOR_BUILD='$(LIBS)'
> + fi
> + AC_SUBST(CC_FOR_BUILD)
> + AC_SUBST(CFLAGS_FOR_BUILD)
> ++AC_SUBST(CPPFLAGS_FOR_BUILD)
> + AC_SUBST(LDFLAGS_FOR_BUILD)
> + AC_SUBST(LIBS_FOR_BUILD)
> + 
> +-- 
> +2.32.0
> +
> diff --git a/gnu/packages/patches/racket-zuo-bin-sh.patch b/gnu/packages/patches/racket-zuo-bin-sh.patch
> new file mode 100644
> index 0000000000..bcdcb8e963
> --- /dev/null
> +++ b/gnu/packages/patches/racket-zuo-bin-sh.patch
> @@ -0,0 +1,74 @@
> +From 73d9b77a11b4516905caf579abb559736f715ea6 Mon Sep 17 00:00:00 2001
> +From: Philip McGrath <philip@philipmcgrath.com>
> +Date: Mon, 11 Apr 2022 20:43:18 -0400
> +Subject: [PATCH] Zuo: patch zuo_process for "/bin/sh" on Guix
> +
> +If:
> +
> +    1. The nonstandard but ubiquitous macro `_PATH_BSHELL` from
> +       <paths.h> is defined; and
> +
> +    2. `zuo_process` is called with the exact path "/bin/sh"; and
> +
> +    3. The path specified by `_PATH_BSHELL` exists;
> +
> +then `zuo_process` will execute the file specified by `_PATH_BSHELL`
> +instead of "/bin/sh".
> +
> +Checking that the path specified by `_PATH_BSHELL` exists safeguards
> +against obscure errors if attempting to use stand-alone executables
> +built by the patched Racket in non-Guix envoronments.
> +---
> + racket/src/zuo/zuo.c | 20 ++++++++++++++++++--
> + 1 file changed, 18 insertions(+), 2 deletions(-)
> +
> +diff --git a/racket/src/zuo/zuo.c b/racket/src/zuo/zuo.c
> +index 17f161826d..c4fb3929bb 100644
> +--- a/racket/src/zuo/zuo.c
> ++++ b/racket/src/zuo/zuo.c
> +@@ -15,6 +15,7 @@
> + #include <string.h>
> + #include <ctype.h>
> + #ifdef ZUO_UNIX
> ++# include <paths.h> /* PATCHED for Guix */
> + # include <fcntl.h>
> + # include <unistd.h>
> + # include <errno.h>
> +@@ -5730,7 +5731,10 @@ static void zuo_pipe(zuo_raw_handle_t *_r, zuo_raw_handle_t *_w)
> + zuo_t *zuo_process(zuo_t *command_and_args)
> + {
> +   const char *who = "process";
> +-  zuo_t *command = _zuo_car(command_and_args);
> ++  /* BEGIN PATCH for Guix */
> ++  zuo_t *_guix_orig_command = _zuo_car(command_and_args);
> ++  zuo_t *command;
> ++  /* END PATCH for Guix */
> +   zuo_t *args = _zuo_cdr(command_and_args), *rev_args = z.o_null;
> +   zuo_t *options = z.o_empty_hash, *opt;
> +   zuo_t *dir, *l, *p_handle, *result;
> +@@ -5741,7 +5745,19 @@ zuo_t *zuo_process(zuo_t *command_and_args)
> +   void *env;
> +   int as_child, exact_cmdline;
> + 
> +-  check_path_string(who, command);
> ++  /* BEGIN PATCH for Guix */
> ++  check_path_string(who, _guix_orig_command);
> ++#if defined(_PATH_BSHELL)
> ++  command =
> ++    ((z.o_false == zuo_string_eql(_guix_orig_command, zuo_string("/bin/sh")))
> ++     || (z.o_false == zuo_stat(zuo_string(_PATH_BSHELL), z.o_false, z.o_true)))
> ++    ? _guix_orig_command
> ++    : zuo_string(_PATH_BSHELL);
> ++#else
> ++  command = _guix_orig_command;
> ++#endif
> ++  /* END PATCH for Guix */
> ++
> +   for (l = args; l->tag == zuo_pair_tag; l = _zuo_cdr(l)) {
> +     zuo_t *a = _zuo_car(l);
> +     if (a == z.o_null) {
> +
> +base-commit: 87eee6e2adb8c6bc11e60619c706fa6295096085
> +-- 
> +2.32.0
> +
> diff --git a/gnu/packages/racket.scm b/gnu/packages/racket.scm
> index 0f766e7850..6433897981 100644
> --- a/gnu/packages/racket.scm
> +++ b/gnu/packages/racket.scm
> @@ -200,6 +200,7 @@ (define* (racket-vm-for-system #:optional
>        racket-vm-bc))
>  
>  (define %racket-version "8.5") ; Remember to update chez-scheme-for-racket!
> +(define %zuo-version "1.0") ; defined in racket/src/zuo/zuo.c
>  (define %racket-commit
>    (string-append "v" %racket-version))
>  (define %racket-origin
> @@ -232,6 +233,56 @@ (define %racket-origin
>           ;; Unbundle libffi.
>           (delete-file-recursively "racket/src/bc/foreign/libffi")))))
>  
> +
> +(define-public zuo
> +  (let ((revision #f))
> +    (package
> +      (name "zuo")
> +      (version (string-append %zuo-version
> +                              "-racket"
> +                              "8.6"

Should the 8.6 instead be %racket-version? I understand above it is
currently 8.5 but why is it hardcoded? I'm a little late to the party.

> +                              (if revision "-guix" "")
> +                              (or revision "")))

I'd rather this be (if revision
                     (string-append "-guix" revision)
                     "")

> +      (source
> +       (origin
> +         (inherit %racket-origin)
> +         (uri (git-reference
> +               (url "https://github.com/racket/racket")
> +               (commit "v8.6")))
> +         (sha256
> +          (base32 "1yi36nr7zrdwrnvpmliirxxjz4pyfyhkar6yvk3rapvmg4q2vmnk"))
> +         (patches (append (origin-patches %racket-origin)
> +                          (search-patches "racket-backport-8.6-zuo.patch"
> +                                          "racket-zuo-bin-sh.patch")))
> +         (file-name (git-file-name "racket" "8.6"))))

I see a third instance of "8.6", lets factor this out either use
%racket-version (I see we've decided on updating separately from racket,
so that's out) or zuo-racket-version would also work, as a variable up
with revision.

> +      (outputs '("out" "debug"))
> +      (build-system gnu-build-system)
> +      (arguments
> +       (list
> +        #:out-of-source? #t
> +        #:phases
> +        #~(modify-phases %standard-phases
> +            (add-after 'unpack 'chdir
> +              (lambda args
> +                (chdir "racket/src/zuo"))))))
> +      (home-page "https://github.com/racket/zuo")
> +      ;; ^ This is downstream of https://github.com/racket/racket,
> +      ;; but it's designed to be a friendly landing place
> +      (synopsis "Tiny Racket for build scripts")
> +      (description "You should use Racket to write scripts.  But what if you
> +need something much smaller than Racket for some reason—or what if you're
> +trying to script a build of Racket itself?  Zuo (作) is a tiny Racket with
> +primitives for dealing with files and running processes, and it comes with a
> +@command{make}-like embedded DSL.
> +
> +Zuo is a Racket variant in the sense that program files start with
> +@code{#lang}, and the module path after @code{#lang} determines the parsing
> +and expansion of the file content.  That's how the @command{make}-like DSL is
> +defined, and even the base Zuo language is defined by layers of @code{#lang}s.
> +One of the early layers implements macros.")
> +      (license (list license:asl2.0 license:expat)))))

I'm not sold on the second paragraph, but I understand it's from
upstream so that's not too bad. For the first paragraph I'd drop the
first two sentences and consider @acronym{symbol, Zuo} for the next
sentence.

> +
> +
>  (define racket-vm-common-configure-flags
>    #~`(,@(cond
>           ((false-if-exception
> -- 
> 2.32.0
>
Philip McGrath Aug. 25, 2022, 8:04 p.m. UTC | #2
On Thu, Aug 25, 2022, at 6:30 AM, Efraim Flashner wrote:
> On Thu, Aug 25, 2022 at 04:54:09AM -0400, Philip McGrath wrote:
>> +      (synopsis "Tiny Racket for build scripts")
>> +      (description "You should use Racket to write scripts.  But what if you
>> +need something much smaller than Racket for some reason—or what if you're
>> +trying to script a build of Racket itself?  Zuo (作) is a tiny Racket with
>> +primitives for dealing with files and running processes, and it comes with a
>> +@command{make}-like embedded DSL.
>> +
>> +Zuo is a Racket variant in the sense that program files start with
>> +@code{#lang}, and the module path after @code{#lang} determines the parsing
>> +and expansion of the file content.  That's how the @command{make}-like DSL is
>> +defined, and even the base Zuo language is defined by layers of @code{#lang}s.
>> +One of the early layers implements macros.")
>> +      (license (list license:asl2.0 license:expat)))))
>
> I'm not sold on the second paragraph, but I understand it's from
> upstream so that's not too bad. For the first paragraph I'd drop the
> first two sentences and consider @acronym{symbol, Zuo} for the next
> sentence.
>

That seems reasonable. For acronym, though, the manual says that "in Texinfo, an acronym (but not an abbreviation) should consist only of capital letters and periods, no lowercase," and when I tried '@abbr{Zuo, 作}' it was rejected as "invalid Texinfo markup". I'm also not sure that the generated HTML would be semantically correct.

How does this seem?

      (description "Zuo (作) is a tiny Racket with primitives for dealing
with files and running processes.  It comes with a @command{make}-like
embedded DSL, which is used to build Racket itself.

Zuo is a Racket variant in the sense that program files start with
@code{#lang}, and the module path after @code{#lang} determines the parsing
and expansion of the file content.  That's how the @command{make}-like DSL is
defined, and even the base Zuo language is defined by layers of @code{#lang}s.
One of the early layers implements macros.")

-Philip
Liliana Marie Prikler Aug. 26, 2022, 12:01 p.m. UTC | #3
Am Donnerstag, dem 25.08.2022 um 16:04 -0400 schrieb Philip McGrath:
> How does this seem?
> 
>       (description "Zuo (作) is a tiny Racket with primitives for
> dealing
I don't think (作) adds anything meaningful.  Perhaps a Chinese
translation might want to use that character, but in English we have to
deal with the fact that most no one will understand that. 
> with files and running processes.  It comes with a @command{make}-
> like
> embedded DSL, which is used to build Racket itself.
> 
> Zuo is a Racket variant in the sense that program files start with
> @code{#lang}, and the module path after @code{#lang} determines the
> parsing
> and expansion of the file content.  That's how the @command{make}-
> like DSL is
> defined, and even the base Zuo language is defined by layers of
> @code{#lang}s.
> One of the early layers implements macros.")
I'd probably cut out the middle sentence in this paragraph, but
otherwise LGTM.

Cheers
Philip McGrath Aug. 27, 2022, 6:08 p.m. UTC | #4
On Fri, Aug 26, 2022, at 8:01 AM, Liliana Marie Prikler wrote:
> Am Donnerstag, dem 25.08.2022 um 16:04 -0400 schrieb Philip McGrath:
>> How does this seem?
>> 
>>       (description "Zuo (作) is a tiny Racket with primitives for
>> dealing
> I don't think (作) adds anything meaningful.  Perhaps a Chinese
> translation might want to use that character, but in English we have to
> deal with the fact that most no one will understand that. 

I think "(作)" concisely answers the question, "Why is this called Zuo?" (Answer: 作 means, roughly, "make".)

-Philip
Liliana Marie Prikler Aug. 27, 2022, 6:58 p.m. UTC | #5
Am Samstag, dem 27.08.2022 um 14:08 -0400 schrieb Philip McGrath:
> On Fri, Aug 26, 2022, at 8:01 AM, Liliana Marie Prikler wrote:
> > Am Donnerstag, dem 25.08.2022 um 16:04 -0400 schrieb Philip
> > McGrath:
> > > How does this seem?
> > > 
> > >       (description "Zuo (作) is a tiny Racket with primitives for
> > > dealing
> > I don't think (作) adds anything meaningful.  Perhaps a Chinese
> > translation might want to use that character, but in English we
> > have to
> > deal with the fact that most no one will understand that. 
> 
> I think "(作)" concisely answers the question, "Why is this called
> Zuo?" (Answer: 作 means, roughly, "make".)
To the average English speaker, which you'll have to assume in a
description, it really doesn't.  You'll have to know that Zuo means
make, at which point it is no longer that concise :)
Philip McGrath Aug. 27, 2022, 7:54 p.m. UTC | #6
On Sat, Aug 27, 2022, at 2:58 PM, Liliana Marie Prikler wrote:
> Am Samstag, dem 27.08.2022 um 14:08 -0400 schrieb Philip McGrath:
>> On Fri, Aug 26, 2022, at 8:01 AM, Liliana Marie Prikler wrote:
>> > Am Donnerstag, dem 25.08.2022 um 16:04 -0400 schrieb Philip
>> > McGrath:
>> > > How does this seem?
>> > > 
>> > >       (description "Zuo (作) is a tiny Racket with primitives for
>> > > dealing
>> > I don't think (作) adds anything meaningful.  Perhaps a Chinese
>> > translation might want to use that character, but in English we
>> > have to
>> > deal with the fact that most no one will understand that. 
>> 
>> I think "(作)" concisely answers the question, "Why is this called
>> Zuo?" (Answer: 作 means, roughly, "make".)
> To the average English speaker, which you'll have to assume in a
> description, it really doesn't.  You'll have to know that Zuo means
> make, at which point it is no longer that concise :)

I really think this is quite normal English usage. Consider, for example, The Chicago Manual of Style, 16th ed., 6.93 (Parentheses for glosses or translations), 11.7 (Translated titles), and, most specifically, 11.119 (Inclusion of Chinese and Japanese characters), which says that "Chinese and Japanese characters, immediately following the romanized version of the item they represent, are sometimes necessary to help readers identify references cited or terms used" and that "where needed in running text, they may be enclosed in parentheses."

When I search for the ascii string "zuo" in a general search engine, I see results about a wholesale furniture company, a "cloud-based subscription management platform provider", a music video, a video game, and several individuals whose names contain "zuo" before I get to any information about a Chinese word or character.

I don't think it's absolutely essential, but I don't see why including it would be a problem.

-Philip
Liliana Marie Prikler Aug. 27, 2022, 9:18 p.m. UTC | #7
Am Samstag, dem 27.08.2022 um 15:54 -0400 schrieb Philip McGrath:
> When I search for the ascii string "zuo" in a general search
> engine[...]
The home-page field exists, as does `guix build -S'.  One more reason
to use the subtree repo.

Cheers
Philip McGrath Aug. 27, 2022, 9:28 p.m. UTC | #8
On Sat, Aug 27, 2022, at 5:18 PM, Liliana Marie Prikler wrote:
> Am Samstag, dem 27.08.2022 um 15:54 -0400 schrieb Philip McGrath:
>> When I search for the ascii string "zuo" in a general search
>> engine[...]
> The home-page field exists, as does `guix build -S'.  One more reason
> to use the subtree repo.
>
> Cheers

I understand that you don't think mentioning 作 is necessary. I don't understand why you seem to think mentioning 作 is bad.
Liliana Marie Prikler Aug. 27, 2022, 10:26 p.m. UTC | #9
Am Samstag, dem 27.08.2022 um 17:28 -0400 schrieb Philip McGrath:
> On Sat, Aug 27, 2022, at 5:18 PM, Liliana Marie Prikler wrote:
> > Am Samstag, dem 27.08.2022 um 15:54 -0400 schrieb Philip McGrath:
> > > When I search for the ascii string "zuo" in a general search
> > > engine[...]
> > The home-page field exists, as does `guix build -S'.  One more
> > reason
> > to use the subtree repo.
> > 
> > Cheers
> 
> I understand that you don't think mentioning 作 is necessary. I don't
> understand why you seem to think mentioning 作 is bad.
A package description is not a Wikipedia entry.  Different styles
apply.  In an encyclopedia, the bracket form you mentioned can be a
handy way of including "useful" information right at the start when the
article itself is much more long-winded.  This is not the case here,
though, and the entire bracket expression only serves as a distraction
from the rest of the sentence.
diff mbox series

Patch

diff --git a/gnu/local.mk b/gnu/local.mk
index babd54c8c6..c9c3061b33 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1769,8 +1769,10 @@  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-backport-8.6-zuo.patch		\
   %D%/packages/patches/racket-chez-scheme-bin-sh.patch		\
   %D%/packages/patches/racket-rktio-bin-sh.patch		\
+  %D%/packages/patches/racket-zuo-bin-sh.patch			\
   %D%/packages/patches/remake-impure-dirs.patch			\
   %D%/packages/patches/restic-0.9.6-fix-tests-for-go1.15.patch	\
   %D%/packages/patches/retroarch-LIBRETRO_DIRECTORY.patch	\
diff --git a/gnu/packages/patches/racket-backport-8.6-zuo.patch b/gnu/packages/patches/racket-backport-8.6-zuo.patch
new file mode 100644
index 0000000000..b86679b7ec
--- /dev/null
+++ b/gnu/packages/patches/racket-backport-8.6-zuo.patch
@@ -0,0 +1,481 @@ 
+From 8761fc06b188b9ca2f4b7f2b7d1235075c44a321 Mon Sep 17 00:00:00 2001
+From: Matthew Flatt <mflatt@racket-lang.org>
+Date: Sat, 23 Jul 2022 17:10:58 -0600
+Subject: [PATCH 1/4] Zuo: support cross compilation via `configure` and
+ `CC_FOR_BUILD`
+
+(cherry picked from commit 798a989ba6d1a30c491a3120b2c2f1570ecab911)
+---
+ racket/src/zuo/Makefile.in  |  7 ++++++-
+ racket/src/zuo/README.md    | 10 ++++++++++
+ racket/src/zuo/configure    | 15 +++++++++++++++
+ racket/src/zuo/configure.ac | 11 +++++++++++
+ 4 files changed, 42 insertions(+), 1 deletion(-)
+
+diff --git a/racket/src/zuo/Makefile.in b/racket/src/zuo/Makefile.in
+index 5d16e145bf..747b584c5c 100644
+--- a/racket/src/zuo/Makefile.in
++++ b/racket/src/zuo/Makefile.in
+@@ -17,6 +17,11 @@ CPPFLAGS = @CPPFLAGS@
+ LDFLAGS = @LDFLAGS@
+ LIBS = @LIBS@
+ 
++CC_FOR_BUILD = @CC_FOR_BUILD@
++CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
++LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
++LIBS_FOR_BUILD = @LIBS_FOR_BUILD@
++
+ EMBED_LIBS = @EMBED_LIBS@
+ 
+ .PHONY: zuos-to-run-and-install
+@@ -24,7 +29,7 @@ zuos-to-run-and-install: zuo
+ 	./zuo . zuos-to-run-and-install
+ 
+ zuo: $(srcdir)/zuo.c
+-	$(CC) $(CPPFLAGS) $(CFLAGS) -DZUO_LIB_PATH='"'"$(srcdir)/lib"'"' -o zuo $(srcdir)/zuo.c $(LDFLAGS) $(LIBS)
++	$(CC_FOR_BUILD) $(FLAGS_FOR_BUILD) -DZUO_LIB_PATH='"'"$(srcdir)/lib"'"' -o zuo $(srcdir)/zuo.c $(LDFLAGS_FOR_BUILD) $(LIBS_FOR_BUILD)
+ 
+ .PHONY: check
+ check: zuo
+diff --git a/racket/src/zuo/README.md b/racket/src/zuo/README.md
+index 17c88ee9ec..3aad504b7e 100644
+--- a/racket/src/zuo/README.md
++++ b/racket/src/zuo/README.md
+@@ -84,6 +84,16 @@ A boot image is machine-independent, whether in a stand-alone file or
+ embedded in `.c` source.
+ 
+ 
++Cross Compiling
++---------------
++
++If you use `./configure --host=...` to cross compile, then you will
++also need to add something like `CC_FOR_BUILD=cc` as a `./configure`
++argument to specify the compiler for a `zuo` to use on the build
++machine. If necessary, you can also specify `CFLAGS_FOR_BUILD`,
++`LDFLAGS_FOR_BUILD`, and/or `LIBS_FOR_BUILD`.
++
++
+ Embedding Zuo in Another Application
+ ------------------------------------
+ 
+diff --git a/racket/src/zuo/configure b/racket/src/zuo/configure
+index 1fa34a3fe8..575ce07d96 100755
+--- a/racket/src/zuo/configure
++++ b/racket/src/zuo/configure
+@@ -589,6 +589,10 @@ enable_embed="zuo"
+ ac_subst_vars='LTLIBOBJS
+ LIBOBJS
+ EMBED_LIBS
++LIBS_FOR_BUILD
++LDFLAGS_FOR_BUILD
++CFLAGS_FOR_BUILD
++CC_FOR_BUILD
+ OBJEXT
+ EXEEXT
+ ac_ct_CC
+@@ -2584,6 +2588,17 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
+ ac_compiler_gnu=$ac_cv_c_compiler_gnu
+ 
+ 
++if test "${CC_FOR_BUILD}" = ""; then
++  CC_FOR_BUILD='$(CC) -O2'
++  CFLAGS_FOR_BUILD='$(CPPFLAGS) $(CFLAGS)'
++  LDFLAGS_FOR_BUILD='$(LDFLAGS)'
++  LIBS_FOR_BUILD='$(LIBS)'
++fi
++
++
++
++
++
+ 
+ { $as_echo "$as_me:${as_lineno-$LINENO}: zuo libraries to embed: \"${EMBED_LIBS}\"" >&5
+ $as_echo "$as_me: zuo libraries to embed: \"${EMBED_LIBS}\"" >&6;}
+diff --git a/racket/src/zuo/configure.ac b/racket/src/zuo/configure.ac
+index 89b3c6391d..598ff79629 100644
+--- a/racket/src/zuo/configure.ac
++++ b/racket/src/zuo/configure.ac
+@@ -25,6 +25,17 @@ AS_IF([test "x$enable_embed" = xno],
+ AC_PROG_MAKE_SET()
+ AC_PROG_CC
+ 
++if test "${CC_FOR_BUILD}" = ""; then
++  CC_FOR_BUILD='$(CC) -O2'
++  CFLAGS_FOR_BUILD='$(CPPFLAGS) $(CFLAGS)'
++  LDFLAGS_FOR_BUILD='$(LDFLAGS)'
++  LIBS_FOR_BUILD='$(LIBS)'
++fi
++AC_SUBST(CC_FOR_BUILD)
++AC_SUBST(CFLAGS_FOR_BUILD)
++AC_SUBST(LDFLAGS_FOR_BUILD)
++AC_SUBST(LIBS_FOR_BUILD)
++
+ AC_SUBST(EMBED_LIBS)
+ AC_MSG_NOTICE([zuo libraries to embed: "${EMBED_LIBS}"])
+ 
+-- 
+2.32.0
+
+
+From f65194ea41eb472fbdd45d5f6c13eabe5e681704 Mon Sep 17 00:00:00 2001
+From: Matthew Flatt <mflatt@racket-lang.org>
+Date: Sat, 23 Jul 2022 17:47:03 -0600
+Subject: [PATCH 2/4] Zuo: sort hash keys
+
+Printing in a sorted order is helpful to make things more
+deterministic independent of symbol inputs. Making `hash-keys`
+produce a sorted list generalizes that determinism.
+
+(cherry picked from commit 4e7ffd3b365d01c5d0993c0b3fd24c9623962edf)
+---
+ racket/src/zuo/build.zuo              |  5 ++-
+ racket/src/zuo/tests/hash.zuo         |  8 ++--
+ racket/src/zuo/zuo-doc/lang-zuo.scrbl | 18 +++++++--
+ racket/src/zuo/zuo.c                  | 57 ++++++++++++++++++++++++++-
+ 4 files changed, 78 insertions(+), 10 deletions(-)
+
+diff --git a/racket/src/zuo/build.zuo b/racket/src/zuo/build.zuo
+index c1b5e8ce66..129240120a 100644
+--- a/racket/src/zuo/build.zuo
++++ b/racket/src/zuo/build.zuo
+@@ -47,7 +47,10 @@
+     (target (at-dir (add-exe name))
+             (lambda (path token)
+               (rule (list image_zuo.c
+-                          (input-data-target 'config config)
++                          (input-data-target 'config (cons
++                                                      lib-path
++                                                      (map (lambda (key) (hash-ref config key))
++                                                           '(CC CPPFLAGS CFLAGS LDFLAGS LIBS))))
+                           (quote-module-path))
+                     (lambda ()
+                       (define l (split-path path))
+diff --git a/racket/src/zuo/tests/hash.zuo b/racket/src/zuo/tests/hash.zuo
+index a35741c730..0d3d7f3af6 100644
+--- a/racket/src/zuo/tests/hash.zuo
++++ b/racket/src/zuo/tests/hash.zuo
+@@ -35,9 +35,7 @@
+ 
+ (check (hash-keys (hash)) '())
+ (check (hash-keys (hash 'a 1)) '(a))
+-(check (let ([keys (hash-keys (hash 'a 1 'b 2))])
+-         (or (equal? keys '(a b))
+-             (equal? keys '(b a)))))
++(check (hash-keys (hash 'a 1 'b 2)) '(a b)) ; always in order
+ (check (length (hash-keys (hash 'a 1 'b 2 'c 3))) 3)
+ (check (length (hash-keys (hash 'a 1 'b 2 'a 3))) 2)
+ (check-arg-fail (hash-keys 0) "not a hash table")
+@@ -50,3 +48,7 @@
+ (check (hash-keys-subset? (hash 'a 1 'b 2) (hash 'b 1)) #f)
+ (check-arg-fail (hash-keys-subset? 0 (hash)) "not a hash table")
+ (check-arg-fail (hash-keys-subset? (hash) 0) "not a hash table")
++
++;; print sorts keys alphabetically:
++(check (~a (hash 'a 1 'b 2)) "#hash((a . 1) (b . 2))")
++(check (~a (hash 'b 2 'a 1)) "#hash((a . 1) (b . 2))")
+diff --git a/racket/src/zuo/zuo-doc/lang-zuo.scrbl b/racket/src/zuo/zuo-doc/lang-zuo.scrbl
+index 94641d041e..4605e47471 100644
+--- a/racket/src/zuo/zuo-doc/lang-zuo.scrbl
++++ b/racket/src/zuo/zuo-doc/lang-zuo.scrbl
+@@ -538,10 +538,20 @@ support to convert the textual form back into a hash table value.
+ 
+ Analogous to @realracket*[hash? hash hash-ref hash-set hash-remove
+ hash-keys hash-count hash-keys-subset?] from @racketmodname[racket].
+-Besides being constrained to symbol keys, there is one additional
+-difference: the third argument to @racket[hash-ref], when supplied,
+-is always used as a value to return if a key is missing, as
+-opposed to a failure thunk.}
++
++Besides being constrained to symbol keys, there are two additional
++differences:
++
++@itemlist[
++
++ @item{the third argument to @racket[hash-ref], when supplied, is
++       always used as a value to return if a key is missing, as
++       opposed to a failure thunk; and}
++
++ @item{the @racket[hash-keys] function returns interned keys sorted
++       alphabetically.}
++
++]}
+ 
+ 
+ @section{Procedures}
+diff --git a/racket/src/zuo/zuo.c b/racket/src/zuo/zuo.c
+index 2957d478af..88d5747326 100644
+--- a/racket/src/zuo/zuo.c
++++ b/racket/src/zuo/zuo.c
+@@ -1298,6 +1298,59 @@ static zuo_t *zuo_trie_keys(zuo_t *trie_in, zuo_t *accum) {
+   return accum;
+ }
+ 
++/*======================================================================*/
++/* symbol-list sorting                                                  */
++/*======================================================================*/
++
++/* merge sort used to make hash printing deterministic */
++static zuo_t *zuo_symbol_list_sort(zuo_t *l_in) {
++  zuo_t *l, *left, *right, *first, *last;
++  zuo_uint_t len = 0, i;
++
++  for (l = l_in, len = 0; l != z.o_null; l = _zuo_cdr(l))
++    len++;
++
++  if (len < 2)
++    return l_in;
++
++  left = z.o_null;
++  for (l = l_in, i = len >> 1; i > 0; l = _zuo_cdr(l), i--)
++    left = zuo_cons(_zuo_car(l), left);
++  right = l;
++
++  left = zuo_symbol_list_sort(left);
++  right = zuo_symbol_list_sort(right);
++
++  first = last = z.o_null;
++  while ((left != z.o_null) && (right != z.o_null)) {
++    zuo_t *p;
++
++    if (strcmp(ZUO_STRING_PTR(((zuo_symbol_t *)_zuo_car(left))->str),
++               ZUO_STRING_PTR(((zuo_symbol_t *)_zuo_car(right))->str))
++        < 1) {
++      p = zuo_cons(_zuo_car(left), z.o_null);
++      left = _zuo_cdr(left);
++    } else {
++      p = zuo_cons(_zuo_car(right), z.o_null);
++      right = _zuo_cdr(right);
++    }
++
++    if (first == z.o_null)
++      first = p;
++    else
++      ((zuo_pair_t *)last)->cdr = p;
++    last = p;
++  }
++
++  ((zuo_pair_t *)last)->cdr = ((left != z.o_null) ? left : right);
++
++  return first;
++}
++
++static zuo_t *zuo_trie_sorted_keys(zuo_t *trie_in, zuo_t *accum) {
++  return zuo_symbol_list_sort(zuo_trie_keys(trie_in, accum));
++}
++
+ /*======================================================================*/
+ /* terminal support                                                     */
+ /*======================================================================*/
+@@ -1571,7 +1624,7 @@ static void zuo_out(zuo_out_t *out, zuo_t *obj, zuo_print_mode_t mode) {
+         out_string(out, "opaque");
+       out_string(out, ">");
+     } else if (obj->tag == zuo_trie_node_tag) {
+-      zuo_t *keys = zuo_trie_keys(obj, z.o_null);
++      zuo_t *keys = zuo_trie_sorted_keys(obj, z.o_null);
+       if (mode == zuo_print_mode) {
+         out_string(out, "(hash");
+         if (keys != z.o_null)
+@@ -2587,7 +2640,7 @@ static zuo_t *zuo_hash_remove(zuo_t *ht, zuo_t *sym) {
+ 
+ static zuo_t *zuo_hash_keys(zuo_t *ht) {
+   check_hash("hash-keys", ht);
+-  return zuo_trie_keys(ht, z.o_null);
++  return zuo_trie_sorted_keys(ht, z.o_null);
+ }
+ 
+ static zuo_t *zuo_hash_keys_subset_p(zuo_t *ht, zuo_t *ht2) {
+-- 
+2.32.0
+
+
+From f2eecaa1dd875479d2cf51566223b3d0d7b9f738 Mon Sep 17 00:00:00 2001
+From: Matthew Flatt <mflatt@racket-lang.org>
+Date: Sat, 23 Jul 2022 18:06:41 -0600
+Subject: [PATCH 3/4] Zuo: check for nul characters in `string->symbol`
+
+(cherry picked from commit e20022ccfad40d0ba2e77aa75bc4f775018c781f)
+---
+ racket/src/zuo/tests/symbol.zuo       |  3 +++
+ racket/src/zuo/zuo-doc/lang-zuo.scrbl |  4 ++-
+ racket/src/zuo/zuo.c                  | 37 +++++++++++++++++----------
+ 3 files changed, 29 insertions(+), 15 deletions(-)
+
+diff --git a/racket/src/zuo/tests/symbol.zuo b/racket/src/zuo/tests/symbol.zuo
+index 7775aeeb04..5600a89755 100644
+--- a/racket/src/zuo/tests/symbol.zuo
++++ b/racket/src/zuo/tests/symbol.zuo
+@@ -19,3 +19,6 @@
+ (check (not (equal? 'apple (string->uninterned-symbol "apple"))))
+ (check-arg-fail (string->symbol 'apple) not-string)
+ (check-arg-fail (string->uninterned-symbol 'apple) not-string)
++
++(check-arg-fail (string->symbol "apple\0spice") "without a nul character")
++(check (symbol? (string->uninterned-symbol "apple\0spice")))
+diff --git a/racket/src/zuo/zuo-doc/lang-zuo.scrbl b/racket/src/zuo/zuo-doc/lang-zuo.scrbl
+index 4605e47471..07dd5815b0 100644
+--- a/racket/src/zuo/zuo-doc/lang-zuo.scrbl
++++ b/racket/src/zuo/zuo-doc/lang-zuo.scrbl
+@@ -500,7 +500,9 @@ back into Zuo.
+ )]{
+ 
+ Analogous to @realracket*[symbol? symbol->string string->symbol
+-string->uninterned-symbol] from @racketmodname[racket].}
++string->uninterned-symbol] from @racketmodname[racket], but
++@racket[string->symbol] accepts only strings that do not contain the
++null character.}
+ 
+ 
+ @section{Hash Tables (Persistent Maps)}
+diff --git a/racket/src/zuo/zuo.c b/racket/src/zuo/zuo.c
+index 88d5747326..17f161826d 100644
+--- a/racket/src/zuo/zuo.c
++++ b/racket/src/zuo/zuo.c
+@@ -1323,7 +1323,7 @@ static zuo_t *zuo_symbol_list_sort(zuo_t *l_in) {
+ 
+   first = last = z.o_null;
+   while ((left != z.o_null) && (right != z.o_null)) {
+-    zuo_t *p;
++    zuo_t *p, *s_left, *s_right;
+ 
+     if (strcmp(ZUO_STRING_PTR(((zuo_symbol_t *)_zuo_car(left))->str),
+                ZUO_STRING_PTR(((zuo_symbol_t *)_zuo_car(right))->str))
+@@ -2573,8 +2573,28 @@ static zuo_t *zuo_substring(zuo_t *obj, zuo_t *start_i, zuo_t *end_i) {
+   return zuo_sized_string((const char *)&((zuo_string_t *)obj)->s[s_idx], e_idx - s_idx);
+ }
+ 
++static int zuo_is_string_without_nul(zuo_t *obj) {
++  zuo_int_t i;
++
++  if ((obj->tag != zuo_string_tag)
++      || ZUO_STRING_LEN(obj) == 0)
++    return 0;
++
++  for (i = ZUO_STRING_LEN(obj); i--; ) {
++    if (((zuo_string_t *)obj)->s[i] == 0)
++      return 0;
++  }
++
++  return 1;
++}
++
+ static zuo_t *zuo_string_to_symbol(zuo_t *obj) {
+-  check_string("string->symbol", obj);
++  if (!zuo_is_string_without_nul(obj)) {
++    const char *who = "string->symbol";
++    check_string(who, obj);
++    zuo_fail_arg(who, "string without a nul character", obj);
++  }
++
+   return zuo_symbol_from_string(ZUO_STRING_PTR(obj), obj);
+ }
+ 
+@@ -3577,18 +3597,7 @@ static void *zuo_envvars_block(const char *who, zuo_t *envvars)
+ #endif
+ 
+ static int zuo_is_path_string(zuo_t *obj) {
+-  zuo_int_t i;
+-
+-  if ((obj->tag != zuo_string_tag)
+-      || ZUO_STRING_LEN(obj) == 0)
+-    return 0;
+-
+-  for (i = ZUO_STRING_LEN(obj); i--; ) {
+-    if (((zuo_string_t *)obj)->s[i] == 0)
+-      return 0;
+-  }
+-
+-  return 1;
++  return zuo_is_string_without_nul(obj);
+ }
+ 
+ static zuo_t *zuo_path_string_p(zuo_t *obj) {
+-- 
+2.32.0
+
+
+From de6618cb3819d25580e3cd400ea09c8cf4f673a9 Mon Sep 17 00:00:00 2001
+From: Matthew Flatt <mflatt@racket-lang.org>
+Date: Sat, 23 Jul 2022 19:50:46 -0600
+Subject: [PATCH 4/4] Zuo: CPPFLAGS_FOR_BUILD, too
+
+(cherry picked from commit cf82706c4b298f654a04c4bc8d98dff39b62a2ac)
+---
+ racket/src/zuo/Makefile.in  | 3 ++-
+ racket/src/zuo/configure    | 5 ++++-
+ racket/src/zuo/configure.ac | 4 +++-
+ 3 files changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/racket/src/zuo/Makefile.in b/racket/src/zuo/Makefile.in
+index 747b584c5c..0376c038a8 100644
+--- a/racket/src/zuo/Makefile.in
++++ b/racket/src/zuo/Makefile.in
+@@ -19,6 +19,7 @@ LIBS = @LIBS@
+ 
+ CC_FOR_BUILD = @CC_FOR_BUILD@
+ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
++CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+ LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+ LIBS_FOR_BUILD = @LIBS_FOR_BUILD@
+ 
+@@ -29,7 +30,7 @@ zuos-to-run-and-install: zuo
+ 	./zuo . zuos-to-run-and-install
+ 
+ zuo: $(srcdir)/zuo.c
+-	$(CC_FOR_BUILD) $(FLAGS_FOR_BUILD) -DZUO_LIB_PATH='"'"$(srcdir)/lib"'"' -o zuo $(srcdir)/zuo.c $(LDFLAGS_FOR_BUILD) $(LIBS_FOR_BUILD)
++	$(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) -DZUO_LIB_PATH='"'"$(srcdir)/lib"'"' -o zuo $(srcdir)/zuo.c $(LDFLAGS_FOR_BUILD) $(LIBS_FOR_BUILD)
+ 
+ .PHONY: check
+ check: zuo
+diff --git a/racket/src/zuo/configure b/racket/src/zuo/configure
+index 575ce07d96..7ac453e3bc 100755
+--- a/racket/src/zuo/configure
++++ b/racket/src/zuo/configure
+@@ -591,6 +591,7 @@ LIBOBJS
+ EMBED_LIBS
+ LIBS_FOR_BUILD
+ LDFLAGS_FOR_BUILD
++CPPFLAGS_FOR_BUILD
+ CFLAGS_FOR_BUILD
+ CC_FOR_BUILD
+ OBJEXT
+@@ -2590,7 +2591,8 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
+ 
+ if test "${CC_FOR_BUILD}" = ""; then
+   CC_FOR_BUILD='$(CC) -O2'
+-  CFLAGS_FOR_BUILD='$(CPPFLAGS) $(CFLAGS)'
++  CPPFLAGS_FOR_BUILD='$(CPPFLAGS)'
++  CFLAGS_FOR_BUILD='$(CFLAGS)'
+   LDFLAGS_FOR_BUILD='$(LDFLAGS)'
+   LIBS_FOR_BUILD='$(LIBS)'
+ fi
+@@ -2600,6 +2602,7 @@ fi
+ 
+ 
+ 
++
+ { $as_echo "$as_me:${as_lineno-$LINENO}: zuo libraries to embed: \"${EMBED_LIBS}\"" >&5
+ $as_echo "$as_me: zuo libraries to embed: \"${EMBED_LIBS}\"" >&6;}
+ 
+diff --git a/racket/src/zuo/configure.ac b/racket/src/zuo/configure.ac
+index 598ff79629..051ea0beb5 100644
+--- a/racket/src/zuo/configure.ac
++++ b/racket/src/zuo/configure.ac
+@@ -27,12 +27,14 @@ AC_PROG_CC
+ 
+ if test "${CC_FOR_BUILD}" = ""; then
+   CC_FOR_BUILD='$(CC) -O2'
+-  CFLAGS_FOR_BUILD='$(CPPFLAGS) $(CFLAGS)'
++  CPPFLAGS_FOR_BUILD='$(CPPFLAGS)'
++  CFLAGS_FOR_BUILD='$(CFLAGS)'
+   LDFLAGS_FOR_BUILD='$(LDFLAGS)'
+   LIBS_FOR_BUILD='$(LIBS)'
+ fi
+ AC_SUBST(CC_FOR_BUILD)
+ AC_SUBST(CFLAGS_FOR_BUILD)
++AC_SUBST(CPPFLAGS_FOR_BUILD)
+ AC_SUBST(LDFLAGS_FOR_BUILD)
+ AC_SUBST(LIBS_FOR_BUILD)
+ 
+-- 
+2.32.0
+
diff --git a/gnu/packages/patches/racket-zuo-bin-sh.patch b/gnu/packages/patches/racket-zuo-bin-sh.patch
new file mode 100644
index 0000000000..bcdcb8e963
--- /dev/null
+++ b/gnu/packages/patches/racket-zuo-bin-sh.patch
@@ -0,0 +1,74 @@ 
+From 73d9b77a11b4516905caf579abb559736f715ea6 Mon Sep 17 00:00:00 2001
+From: Philip McGrath <philip@philipmcgrath.com>
+Date: Mon, 11 Apr 2022 20:43:18 -0400
+Subject: [PATCH] Zuo: patch zuo_process for "/bin/sh" on Guix
+
+If:
+
+    1. The nonstandard but ubiquitous macro `_PATH_BSHELL` from
+       <paths.h> is defined; and
+
+    2. `zuo_process` is called with the exact path "/bin/sh"; and
+
+    3. The path specified by `_PATH_BSHELL` exists;
+
+then `zuo_process` will execute the file specified by `_PATH_BSHELL`
+instead of "/bin/sh".
+
+Checking that the path specified by `_PATH_BSHELL` exists safeguards
+against obscure errors if attempting to use stand-alone executables
+built by the patched Racket in non-Guix envoronments.
+---
+ racket/src/zuo/zuo.c | 20 ++++++++++++++++++--
+ 1 file changed, 18 insertions(+), 2 deletions(-)
+
+diff --git a/racket/src/zuo/zuo.c b/racket/src/zuo/zuo.c
+index 17f161826d..c4fb3929bb 100644
+--- a/racket/src/zuo/zuo.c
++++ b/racket/src/zuo/zuo.c
+@@ -15,6 +15,7 @@
+ #include <string.h>
+ #include <ctype.h>
+ #ifdef ZUO_UNIX
++# include <paths.h> /* PATCHED for Guix */
+ # include <fcntl.h>
+ # include <unistd.h>
+ # include <errno.h>
+@@ -5730,7 +5731,10 @@ static void zuo_pipe(zuo_raw_handle_t *_r, zuo_raw_handle_t *_w)
+ zuo_t *zuo_process(zuo_t *command_and_args)
+ {
+   const char *who = "process";
+-  zuo_t *command = _zuo_car(command_and_args);
++  /* BEGIN PATCH for Guix */
++  zuo_t *_guix_orig_command = _zuo_car(command_and_args);
++  zuo_t *command;
++  /* END PATCH for Guix */
+   zuo_t *args = _zuo_cdr(command_and_args), *rev_args = z.o_null;
+   zuo_t *options = z.o_empty_hash, *opt;
+   zuo_t *dir, *l, *p_handle, *result;
+@@ -5741,7 +5745,19 @@ zuo_t *zuo_process(zuo_t *command_and_args)
+   void *env;
+   int as_child, exact_cmdline;
+ 
+-  check_path_string(who, command);
++  /* BEGIN PATCH for Guix */
++  check_path_string(who, _guix_orig_command);
++#if defined(_PATH_BSHELL)
++  command =
++    ((z.o_false == zuo_string_eql(_guix_orig_command, zuo_string("/bin/sh")))
++     || (z.o_false == zuo_stat(zuo_string(_PATH_BSHELL), z.o_false, z.o_true)))
++    ? _guix_orig_command
++    : zuo_string(_PATH_BSHELL);
++#else
++  command = _guix_orig_command;
++#endif
++  /* END PATCH for Guix */
++
+   for (l = args; l->tag == zuo_pair_tag; l = _zuo_cdr(l)) {
+     zuo_t *a = _zuo_car(l);
+     if (a == z.o_null) {
+
+base-commit: 87eee6e2adb8c6bc11e60619c706fa6295096085
+-- 
+2.32.0
+
diff --git a/gnu/packages/racket.scm b/gnu/packages/racket.scm
index 0f766e7850..6433897981 100644
--- a/gnu/packages/racket.scm
+++ b/gnu/packages/racket.scm
@@ -200,6 +200,7 @@  (define* (racket-vm-for-system #:optional
       racket-vm-bc))
 
 (define %racket-version "8.5") ; Remember to update chez-scheme-for-racket!
+(define %zuo-version "1.0") ; defined in racket/src/zuo/zuo.c
 (define %racket-commit
   (string-append "v" %racket-version))
 (define %racket-origin
@@ -232,6 +233,56 @@  (define %racket-origin
          ;; Unbundle libffi.
          (delete-file-recursively "racket/src/bc/foreign/libffi")))))
 
+
+(define-public zuo
+  (let ((revision #f))
+    (package
+      (name "zuo")
+      (version (string-append %zuo-version
+                              "-racket"
+                              "8.6"
+                              (if revision "-guix" "")
+                              (or revision "")))
+      (source
+       (origin
+         (inherit %racket-origin)
+         (uri (git-reference
+               (url "https://github.com/racket/racket")
+               (commit "v8.6")))
+         (sha256
+          (base32 "1yi36nr7zrdwrnvpmliirxxjz4pyfyhkar6yvk3rapvmg4q2vmnk"))
+         (patches (append (origin-patches %racket-origin)
+                          (search-patches "racket-backport-8.6-zuo.patch"
+                                          "racket-zuo-bin-sh.patch")))
+         (file-name (git-file-name "racket" "8.6"))))
+      (outputs '("out" "debug"))
+      (build-system gnu-build-system)
+      (arguments
+       (list
+        #:out-of-source? #t
+        #:phases
+        #~(modify-phases %standard-phases
+            (add-after 'unpack 'chdir
+              (lambda args
+                (chdir "racket/src/zuo"))))))
+      (home-page "https://github.com/racket/zuo")
+      ;; ^ This is downstream of https://github.com/racket/racket,
+      ;; but it's designed to be a friendly landing place
+      (synopsis "Tiny Racket for build scripts")
+      (description "You should use Racket to write scripts.  But what if you
+need something much smaller than Racket for some reason—or what if you're
+trying to script a build of Racket itself?  Zuo (作) is a tiny Racket with
+primitives for dealing with files and running processes, and it comes with a
+@command{make}-like embedded DSL.
+
+Zuo is a Racket variant in the sense that program files start with
+@code{#lang}, and the module path after @code{#lang} determines the parsing
+and expansion of the file content.  That's how the @command{make}-like DSL is
+defined, and even the base Zuo language is defined by layers of @code{#lang}s.
+One of the early layers implements macros.")
+      (license (list license:asl2.0 license:expat)))))
+
+
 (define racket-vm-common-configure-flags
   #~`(,@(cond
          ((false-if-exception