Toggle diff (414 lines)
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-sch