diff options
Diffstat (limited to 'gnu/packages/racket.scm')
-rw-r--r-- | gnu/packages/racket.scm | 622 |
1 files changed, 622 insertions, 0 deletions
diff --git a/gnu/packages/racket.scm b/gnu/packages/racket.scm new file mode 100644 index 0000000000..661443e0c3 --- /dev/null +++ b/gnu/packages/racket.scm @@ -0,0 +1,622 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2013, 2014, 2015, 2016, 2018, 2020, 2021 Ludovic Courtès <[email protected]> +;;; Copyright © 2017, 2018, 2019, 2020 Tobias Geerinckx-Rice <[email protected]> +;;; Copyright © 2020 Pierre Neidhardt <[email protected]> +;;; Copyright © 2021 Philip McGrath <[email protected]> +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. + +(define-module (gnu packages racket) + #:use-module ((guix licenses) + #:select (asl2.0 expat lgpl3+)) + #:use-module (guix packages) + #:use-module (guix download) + #:use-module (guix git-download) + #:use-module (guix utils) + #:use-module (guix gexp) + #:use-module (guix build-system gnu) + #:use-module (srfi srfi-1) + #:use-module (ice-9 match) + #:use-module (gnu packages) + #:use-module (gnu packages autotools) + #:use-module (gnu packages bash) + #:use-module (gnu packages chez) + #:use-module (gnu packages compression) + #:use-module (gnu packages databases) + #:use-module (gnu packages fontutils) + #:use-module (gnu packages gl) + #:use-module (gnu packages glib) + #:use-module (gnu packages gtk) + #:use-module (gnu packages image) + #:use-module (gnu packages libedit) + #:use-module (gnu packages libffi) + #:use-module (gnu packages multiprecision) + #:use-module (gnu packages sqlite) + #:use-module (gnu packages tls) + #:use-module (gnu packages xorg)) + +;; Commentary: +;; +;; Here's how bootstrapping minimal 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. +;; +;; 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 +;; as of Racket 7.0. +;; +;; 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 cfg-flag:sh-for-rktio + `(string-append "CPPFLAGS=-DGUIX_RKTIO_PATCH_BIN_SH=" + (assoc-ref %build-inputs "sh") + "/bin/sh")) +(define cfg-flag:enable-lt + `(string-append "--enable-lt=" + (assoc-ref %build-inputs "libtool") + "/bin/libtool")) +(define cfg-flag:enable-racket + `(let ((racket (assoc-ref %build-inputs "racket"))) + (string-append "--enable-racket=" + racket + "/bin/racket"))) + +(define unpack-nanopass+stex + ;; Copied from chez-scheme. + ;; TODO: Eventually, we should refactor Chez Scheme + ;; enough to share more directly, so that we can make + ;; Racket's version of Chez avalable as a Guix package, + ;; e.g. for architectures not supported upstream. + ;; For now, we let Racket drive the Chez build process + ;; other than this step. + `(for-each (lambda (dep) + (define src + (assoc-ref (or native-inputs inputs) dep)) + (copy-recursively src dep + #:keep-mtime? #t)) + '("nanopass" "stex"))) + + +(define-public racket-minimal + (package + (name "racket-minimal") + (version "8.2") ; note: remember to also update racket! + (source + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/racket") + (commit (string-append "v" version)))) + (sha256 + "061bhiyjlvazph0dj9i3i3x2q5z53rp8h5cjwg3frjimkr45lncn") + (file-name (git-file-name name version)) + (patches (search-patches "racket-minimal-sh-via-rktio.patch" + ;; Remove the following in version 8.3: + "racket-minimal-backport-1629887.patch")) + (modules '((guix build utils))) + (snippet + (with-imported-modules '((guix build utils)) + #~(begin + ;; Unbundle Chez submodules. + (with-directory-excursion "racket/src/ChezScheme" + ;; Remove bundled libraries (copied from 'chez-scheme'). + (for-each delete-file-recursively + '("stex" + "nanopass" + "lz4" + "zlib"))) + ;; Unbundle libffi. + (delete-file-recursively "racket/src/bc/foreign/libffi")))))) + (inputs + `(;; common to all racket-minimal variants: + ("openssl" ,openssl) + ("sqlite" ,sqlite) + ("sh" ,bash-minimal) + ;; only for CS + ("zlib" ,zlib) + ("zlib:static" ,zlib "static") + ("lz4" ,lz4) + ("lz4:static" ,lz4 "static"))) + (native-inputs + `(("bootfiles" ,racket-bootstrap-chez-bootfiles) + ,@(package-native-inputs racket-bootstrap-chez-bootfiles))) + (build-system gnu-build-system) + (arguments + `(#:configure-flags + (list "--enable-csonly" + "--enable-libz" + "--enable-liblz4" + ,cfg-flag:enable-racket + ,cfg-flag:sh-for-rktio) + #:out-of-source? #true + ;; Tests are in packages like racket-test-core and + ;; main-distribution-test that aren't part of the main distribution. + #:tests? #f + #:modules ((ice-9 match) + (guix build gnu-build-system) + (guix build utils)) + #:phases + (modify-phases %standard-phases + (add-after 'unpack 'unpack-nanopass+stex + (lambda* (#:key inputs native-inputs #:allow-other-keys) + (with-directory-excursion "racket/src/ChezScheme" + ,unpack-nanopass+stex) + #t)) + (add-after 'unpack-nanopass+stex 'unpack-bootfiles + (lambda* (#:key inputs #:allow-other-keys) + (with-directory-excursion "racket/src/ChezScheme" + (copy-recursively + (string-append (assoc-ref inputs "bootfiles") "/boot") + "boot")) + #t)) + (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")) + (mkdir-p "racket/etc") + (with-output-to-file "racket/etc/config.rktd" + (lambda () + (write-racket-hash + `((lib-search-dirs + . (#f ,@(map (lambda (lib) + (string-append (assoc-ref inputs lib) + "/lib")) + '("openssl" + "sqlite")))) + (build-stamp . "") + (catalogs + . (,(string-append + "https://download.racket-lang.org/releases/" + ,version + "/catalog/") + #f)))))) + #t)) + (add-before 'configure 'change-directory + (lambda _ + (chdir "racket/src") + #t)) + (add-after 'install 'remove-pkgs-directory + ;; If the configured pkgs-dir exists, "pkgs.rktd" does not + ;; exist, and a lock file does not exist, commands like + ;; `raco pkg show` will try to create a lock file and fail + ;; due to the read-only store. + ;; Arguably this may be a bug in `pkg/private/lock`: + ;; see <https://github.com/racket/racket/issues/3851>. + ;; As a workaround, remove the directory. + (lambda* (#:key outputs #:allow-other-keys) + ;; rmdir because we want an error if it isn't empty + (rmdir (string-append (assoc-ref outputs "out") + "/share/racket/pkgs")) + #t))))) + (home-page "https://racket-lang.org") + (synopsis "Racket without bundled packages such as DrRacket") + (description + "Racket is a general-purpose programming language in the Scheme family, +with a large set of libraries and a compiler based on Chez Scheme. Racket is +also a platform for language-oriented programming, from small domain-specific +languages to complete language implementations. + +The ``minimal Racket'' distribution includes just enough of Racket for you to +use @command{raco pkg} to install more. Bundled packages, such as the +DrRacket IDE, are not included.") + ;; https://download.racket-lang.org/license.html + ;; The LGPL components are only used by Racket BC. + (license (list asl2.0 expat)))) + + +(define-public racket-minimal-bc-3m + (hidden-package + (package + (inherit racket-minimal) + (name "racket-minimal-bc-3m") + (inputs + `(("libffi" ,libffi) ;; <- only for BC variants + ,@(fold alist-delete + (package-inputs racket-minimal) + '("zlib" "zlib:static" "lz4" "lz4:static")))) + (native-inputs + `(("libtool" ,libtool) + ("racket" ,(if (%current-target-system) + racket-minimal + racket-minimal-bc-cgc)))) + (arguments + (substitute-keyword-arguments (package-arguments racket-minimal) + ((#:configure-flags _ '()) + `(list "--enable-bconly" + ,cfg-flag:enable-racket + ,cfg-flag:enable-lt + ,cfg-flag:sh-for-rktio)) + ((#:phases usual-phases) + `(modify-phases ,usual-phases + (delete 'unpack-nanopass+stex) + (delete 'unpack-bootfiles))))) + (synopsis "Minimal Racket with the BC [3M] runtime system") + (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''). + +This package is the normal implementation of Racket BC with a precise garbage +collector, 3M (``Moving Memory Manager'').") + ;; https://download.racket-lang.org/license.html + ;; The LGPL components are only used by Racket BC. + (license (list lgpl3+ asl2.0 expat))))) + + +(define-public racket-minimal-bc-cgc + (package + (inherit racket-minimal-bc-3m) + (name "racket-minimal-bc-cgc") + (native-inputs + (alist-delete "racket" (package-native-inputs racket-minimal-bc-3m))) + (arguments + (substitute-keyword-arguments (package-arguments racket-minimal-bc-3m) + ((#:configure-flags _ '()) + `(list "--enable-cgcdefault" + ,cfg-flag:enable-lt + ,cfg-flag:sh-for-rktio)))) + (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 BC [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."))) + + +(define-public racket-bootstrap-chez-bootfiles + (hidden-package + (package + (inherit racket-minimal) + (name "racket-bootstrap-chez-bootfiles") + (inputs `()) + (native-inputs + `(("racket" ,(if (%current-target-system) + racket-minimal + racket-minimal-bc-3m)) + ("stex" ,@(assoc-ref (package-native-inputs chez-scheme) "stex")) + ("nanopass" ,@(assoc-ref (package-native-inputs chez-scheme) + "nanopass")))) + (arguments + `(#:phases + (modify-phases %standard-phases + (add-after 'unpack 'unpack-nanopass+stex + (lambda* (#:key inputs native-inputs #:allow-other-keys) + (with-directory-excursion "racket/src/ChezScheme" + ,unpack-nanopass+stex) + #t)) + (delete 'configure) + (delete 'patch-generated-file-shebangs) + (replace 'build + (lambda* (#:key inputs outputs #:allow-other-keys) + (with-directory-excursion "racket/src/ChezScheme" + (invoke (string-append (assoc-ref inputs "racket") + "/bin/racket") + "rktboot/main.rkt" + "--dest" (assoc-ref outputs "out"))) + #t)) + (delete 'check) + (delete 'install)))) + (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.") + (license (list asl2.0))))) + + +(define %installer-mirrors + ;; Source: + ;; https://github.com/racket/racket-lang-org/blob/master/download/data.rkt#L58 + ;; Matthew Flatt says: "note that many are commented out" + ;; INVARIANT: End with a trailing "/"! + '("https://mirror.racket-lang.org/installers/" + "https://www.cs.utah.edu/plt/installers/" + "https://plt.cs.northwestern.edu/racket-mirror/" + "https://mirror.csclub.uwaterloo.ca/racket/racket-installers/" + ;; Universität Tübingen is using a self-signed HTTPS certificate: + "http://mirror.informatik.uni-tuebingen.de/mirror/racket/" + "https://racket.infogroep.be/" + )) + +(define %main-repo-main-distribution-pkgs + ;; These are the packages developed in the main Racket Git repository + ;; that are part of the main distribution. + '("at-exp-lib" + "base" + "compiler-lib" + ;; NOT "compiler-test" + "compiler" + "net-doc" + "net-lib" + ;; NOT "net-test" + "net" + ;; NOT "plt-services" + ;; NOT "racket-benchmarks" + ;; NOT "racket-build-guide" + "racket-doc" + "racket-index" + "racket-lib" + ;; NOT "racket-test-core" + ;; NOT "racket-test-extra" + ;; NOT "racket-test" + "zo-lib")) + + +(define-public racket + (package + (inherit racket-minimal) + (name "racket") + (version (package-version racket-minimal)) ; needed for origin uri to work + (source + (origin + (method url-fetch) + (uri (map (lambda (base) + (string-append base version "/racket-src.tgz")) + %installer-mirrors)) + (sha256 + (base32 + "10sgzsraxzxp1k2y2wvz8rcjwvhbcd6k72l9lyqr34yazlwfdz26")) + (snippet + #~(begin + (use-modules (guix build utils) + (ice-9 match) + (ice-9 regex)) + ;; unbundle minimal Racket + (for-each delete-file-recursively + '("collects" + "doc" + "etc" + "README" + "src")) + ;; unbundle package sources included elsewhere + (with-directory-excursion "share/pkgs" + (for-each delete-file-recursively + '#+%main-repo-main-distribution-pkgs)) + #t)))) + (inputs + `(("cairo" ,cairo) + ("fontconfig" ,fontconfig) + ("glib" ,glib) + ("glu" ,glu) + ("gmp" ,gmp) + ("gtk+" ,gtk+) ; propagates gdk-pixbuf+svg + ("libjpeg" ,libjpeg-turbo) + ("libpng" ,libpng) + ("libx11" ,libx11) + ("mesa" ,mesa) + ("mpfr" ,mpfr) + ("pango" ,pango) + ("unixodbc" ,unixodbc) + ("libedit" ,libedit))) + (native-inputs + `(("racket" ,racket-minimal) + ("extend-layer" ,extend-layer) + ("main-repo" ,(package-source racket-minimal)))) + (arguments + `(#:phases + (modify-phases %standard-phases + (add-before 'configure 'unpack-packages + (let ((unpack (assoc-ref %standard-phases 'unpack))) + (lambda* (#:key native-inputs inputs outputs #:allow-other-keys) + (let* ((racket (assoc-ref (or native-inputs inputs) "racket")) + (prefix (assoc-ref outputs "out")) + (pkgs-dir (string-append prefix "/share/racket/pkgs"))) + (mkdir-p pkgs-dir) + (copy-recursively + "share/links.rktd" + (string-append prefix "/share/racket/links.rktd")) + (copy-recursively "share/pkgs" pkgs-dir) + ;; NOTE: unpack changes the working directory + (unpack #:source (assoc-ref (or native-inputs inputs) + "main-repo")) + (for-each (lambda (pkg) + (define dest (string-append pkgs-dir "/" pkg)) + (mkdir-p dest) + (copy-recursively (string-append "pkgs/" pkg) + dest)) + ',%main-repo-main-distribution-pkgs) + #t)))) + (replace 'configure + (lambda* (#:key native-inputs inputs outputs #:allow-other-keys) + (let ((racket (assoc-ref (or native-inputs inputs) "racket")) + (prefix (assoc-ref outputs "out"))) + (apply invoke + (string-append racket "/bin/racket") + (assoc-ref inputs "extend-layer") + racket + prefix + (map + (lambda (lib) + (string-append (assoc-ref inputs lib) "/lib")) + '("cairo" + "fontconfig" + "glib" + "glu" + "gmp" + "gtk+" + "libjpeg" + "libpng" + "libx11" + "mesa" + "mpfr" + "pango" + "unixodbc" + "libedit"))) + #t))) + (replace 'build + (lambda* (#:key native-inputs inputs outputs #:allow-other-keys) + (invoke (string-append (assoc-ref (or native-inputs inputs) + "racket") + "/bin/racket") + "--config" + (string-append (assoc-ref outputs "out") + "/etc/racket") + "-l" + "raco" + "setup") + #t)) + (delete 'install)) + ;; we still don't have these: + #:tests? #f)) + (synopsis "A programmable programming language in the Scheme family") + (description + "Racket is a general-purpose programming language in the Scheme family, +with a large set of libraries and a compiler based on Chez Scheme. Racket is +also a platform for language-oriented programming, from small domain-specific +languages to complete language implementations. + +The main Racket distribution comes with many bundled packages, including the +DrRacket IDE, libraries for GUI and web programming, and implementations of +languages such as Typed Racket, R5RS and R6RS Scheme, Algol 60, and Datalog."))) + + +(define extend-layer + (scheme-file + "extend-layer.rkt" + `(module + extend-layer racket/base + (require racket/cmdline + racket/match + racket/file + racket/list + racket/pretty) + (define config-file-pth + "etc/racket/config.rktd") + (define (build-path-string . args) + (path->string (apply build-path args))) + (define rx:racket + ;; Guile's reader doesn't support #rx"racket" + (regexp "racket")) + (command-line + #:args (parent-layer prefix . lib-dir*) + (let* ([config + (for/fold + ([config (file->value (build-path parent-layer + config-file-pth))]) + ([spec (in-list + '((lib-dir lib-search-dirs "lib/racket") + (share-dir share-search-dirs "share/racket") + (links-file + links-search-files + "share/racket/links.rktd") + (pkgs-dir pkgs-search-dirs "share/racket/pkgs") + (bin-dir bin-search-dirs "bin") + (man-dir man-search-dirs "share/man") + (doc-dir doc-search-dirs "share/doc/racket") + (include-dir + include-search-dirs + "include/racket")))]) + (match-define (list main-key search-key pth) spec) + (hash-set* + config + main-key + (build-path-string prefix pth) + search-key + (list* #f + (hash-ref config + main-key + (build-path-string parent-layer pth)) + (filter values (hash-ref config search-key null)))))] + [config + (hash-set config + 'apps-dir + (build-path-string prefix "share/applications"))] + [config + ;; place new foreign lib-search-dirs before old + ;; foreign dirs, but after Racket layers + (let-values + ([(rkt extra) + (partition (lambda (pth) + (or (not pth) + (regexp-match? rx:racket pth))) + (hash-ref config 'lib-search-dirs))]) + (hash-set config + 'lib-search-dirs + (append rkt + lib-dir* + extra)))] + [bin-dir + (hash-ref config 'bin-dir)] + [config + (hash-set* config + 'config-tethered-console-bin-dir bin-dir + 'config-tethered-gui-bin-dir bin-dir)] + [new-config-pth + (build-path prefix config-file-pth)]) + (make-parent-directory* new-config-pth) + (call-with-output-file* + new-config-pth + (lambda (out) + (pretty-write config out)))))))) |