racket.scm 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2013, 2014, 2015, 2016, 2018, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2017, 2018, 2019, 2020 Tobias Geerinckx-Rice <me@tobias.gr>
  4. ;;; Copyright © 2020 Pierre Neidhardt <mail@ambrevar.xyz>
  5. ;;; Copyright © 2021 Philip McGrath <philip@philipmcgrath.com>
  6. ;;;
  7. ;;; This file is part of GNU Guix.
  8. ;;;
  9. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  10. ;;; under the terms of the GNU General Public License as published by
  11. ;;; the Free Software Foundation; either version 3 of the License, or (at
  12. ;;; your option) any later version.
  13. ;;;
  14. ;;; GNU Guix is distributed in the hope that it will be useful, but
  15. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ;;; GNU General Public License for more details.
  18. ;;;
  19. ;;; You should have received a copy of the GNU General Public License
  20. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  21. (define-module (gnu packages racket)
  22. #:use-module ((guix licenses)
  23. #:select (asl2.0 expat lgpl3+))
  24. #:use-module (guix packages)
  25. #:use-module (guix download)
  26. #:use-module (guix git-download)
  27. #:use-module (guix utils)
  28. #:use-module (guix gexp)
  29. #:use-module (guix build-system gnu)
  30. #:use-module (srfi srfi-1)
  31. #:use-module (ice-9 match)
  32. #:use-module (gnu packages)
  33. #:use-module (gnu packages autotools)
  34. #:use-module (gnu packages bash)
  35. #:use-module (gnu packages chez)
  36. #:use-module (gnu packages compression)
  37. #:use-module (gnu packages databases)
  38. #:use-module (gnu packages fontutils)
  39. #:use-module (gnu packages gl)
  40. #:use-module (gnu packages glib)
  41. #:use-module (gnu packages gtk)
  42. #:use-module (gnu packages image)
  43. #:use-module (gnu packages libedit)
  44. #:use-module (gnu packages libffi)
  45. #:use-module (gnu packages multiprecision)
  46. #:use-module (gnu packages sqlite)
  47. #:use-module (gnu packages tls)
  48. #:use-module (gnu packages xorg))
  49. ;; Commentary:
  50. ;;
  51. ;; Here's how bootstrapping minimal Racket works:
  52. ;;
  53. ;; - Racket BC [CGC] can be built with only a C compiler (except for
  54. ;; one caveat discussed below).
  55. ;; - Racket BC [3M] needs an existing Racket to run "xform",
  56. ;; which transforms its own C source code to add additional annotations
  57. ;; for the precise garbage collector.
  58. ;; - Racket CS needs (bootfiles for) Racket's fork of Chez Scheme.
  59. ;; It also needs an existing Racket to compile Racket-implemented
  60. ;; parts of the runtime system to R6RS libraries.
  61. ;; - Chez Scheme also needs bootfiles for itself, but Racket can simulate
  62. ;; enough of Chez Scheme to load Racket's fork of the Chez Scheme compiler
  63. ;; purely from source into Racket and apply the compiler to itself,
  64. ;; producing the needed bootfiles (albeit very slowly).
  65. ;; Any variant of Racket since version 7.1 can run the simulation.
  66. ;;
  67. ;; So, we build CGC to build 3M to build bootfiles and CS.
  68. ;;
  69. ;; One remaining bootstrapping limitation is that Racket's reader, module
  70. ;; system, and macro expander are implemented in Racket. For Racket CS,
  71. ;; they are compiled to R6RS libraries as discussed above. This note from the
  72. ;; README file applies to all such subsystems:
  73. ;;
  74. ;; The Racket version must be practically the same as the current Racket
  75. ;; verson, although it can be the Racket BC implementation (instead of
  76. ;; the Racket CS implementation).
  77. ;;
  78. ;; Unlike Chez Scheme boot files, the files generated in "schemified"
  79. ;; are human-readable and -editable Scheme code. That provides a way
  80. ;; out of bootstrapping black holes, even without BC.
  81. ;;
  82. ;; However, other Racket subsystems implemented in Racket for Racket CS
  83. ;; use older C implementations for Racket BC, whereas the reader, expander,
  84. ;; and module system were completely replaced with the Racket implementation
  85. ;; as of Racket 7.0.
  86. ;;
  87. ;; For Racket BC, the compiled "linklet" s-expressions (primitive modules)
  88. ;; are embeded in C as a static string constant. Eventually, they are further
  89. ;; compiled by the C-implemented Racket BC bytecode and JIT compilers.
  90. ;; (On platforms where Racket BC's JIT is not supported, yet another compiler
  91. ;; instead compiles the linklets to C code, but this is not a bootstrapping
  92. ;; issue.)
  93. ;;
  94. ;; Code:
  95. (define cfg-flag:sh-for-rktio
  96. `(string-append "CPPFLAGS=-DGUIX_RKTIO_PATCH_BIN_SH="
  97. (assoc-ref %build-inputs "sh")
  98. "/bin/sh"))
  99. (define cfg-flag:enable-lt
  100. `(string-append "--enable-lt="
  101. (assoc-ref %build-inputs "libtool")
  102. "/bin/libtool"))
  103. (define cfg-flag:enable-racket
  104. `(let ((racket (assoc-ref %build-inputs "racket")))
  105. (string-append "--enable-racket="
  106. racket
  107. "/bin/racket")))
  108. (define unpack-nanopass+stex
  109. ;; Copied from chez-scheme.
  110. ;; TODO: Eventually, we should refactor Chez Scheme
  111. ;; enough to share more directly, so that we can make
  112. ;; Racket's version of Chez avalable as a Guix package,
  113. ;; e.g. for architectures not supported upstream.
  114. ;; For now, we let Racket drive the Chez build process
  115. ;; other than this step.
  116. `(for-each (lambda (dep)
  117. (define src
  118. (assoc-ref (or native-inputs inputs) dep))
  119. (copy-recursively src dep
  120. #:keep-mtime? #t))
  121. '("nanopass" "stex")))
  122. (define-public racket-minimal
  123. (package
  124. (name "racket-minimal")
  125. (version "8.2") ; note: remember to also update racket!
  126. (source
  127. (origin
  128. (method git-fetch)
  129. (uri (git-reference
  130. (url "https://github.com/racket/racket")
  131. (commit (string-append "v" version))))
  132. (sha256
  133. "061bhiyjlvazph0dj9i3i3x2q5z53rp8h5cjwg3frjimkr45lncn")
  134. (file-name (git-file-name name version))
  135. (patches (search-patches "racket-minimal-sh-via-rktio.patch"
  136. ;; Remove the following in version 8.3:
  137. "racket-minimal-backport-1629887.patch"))
  138. (modules '((guix build utils)))
  139. (snippet
  140. (with-imported-modules '((guix build utils))
  141. #~(begin
  142. ;; Unbundle Chez submodules.
  143. (with-directory-excursion "racket/src/ChezScheme"
  144. ;; Remove bundled libraries (copied from 'chez-scheme').
  145. (for-each delete-file-recursively
  146. '("stex"
  147. "nanopass"
  148. "lz4"
  149. "zlib")))
  150. ;; Unbundle libffi.
  151. (delete-file-recursively "racket/src/bc/foreign/libffi"))))))
  152. (inputs
  153. `(;; common to all racket-minimal variants:
  154. ("openssl" ,openssl)
  155. ("sqlite" ,sqlite)
  156. ("sh" ,bash-minimal)
  157. ;; only for CS
  158. ("zlib" ,zlib)
  159. ("zlib:static" ,zlib "static")
  160. ("lz4" ,lz4)
  161. ("lz4:static" ,lz4 "static")))
  162. (native-inputs
  163. `(("bootfiles" ,racket-bootstrap-chez-bootfiles)
  164. ,@(package-native-inputs racket-bootstrap-chez-bootfiles)))
  165. (build-system gnu-build-system)
  166. (arguments
  167. `(#:configure-flags
  168. (list "--enable-csonly"
  169. "--enable-libz"
  170. "--enable-liblz4"
  171. ,cfg-flag:enable-racket
  172. ,cfg-flag:sh-for-rktio)
  173. #:out-of-source? #true
  174. ;; Tests are in packages like racket-test-core and
  175. ;; main-distribution-test that aren't part of the main distribution.
  176. #:tests? #f
  177. #:modules ((ice-9 match)
  178. (guix build gnu-build-system)
  179. (guix build utils))
  180. #:phases
  181. (modify-phases %standard-phases
  182. (add-after 'unpack 'unpack-nanopass+stex
  183. (lambda* (#:key inputs native-inputs #:allow-other-keys)
  184. (with-directory-excursion "racket/src/ChezScheme"
  185. ,unpack-nanopass+stex)
  186. #t))
  187. (add-after 'unpack-nanopass+stex 'unpack-bootfiles
  188. (lambda* (#:key inputs #:allow-other-keys)
  189. (with-directory-excursion "racket/src/ChezScheme"
  190. (copy-recursively
  191. (string-append (assoc-ref inputs "bootfiles") "/boot")
  192. "boot"))
  193. #t))
  194. (add-before 'configure 'initialize-config.rktd
  195. (lambda* (#:key inputs #:allow-other-keys)
  196. (define (write-racket-hash alist)
  197. ;; inside must use dotted pair notation
  198. (display "#hash(")
  199. (for-each (match-lambda
  200. ((k . v)
  201. (format #t "(~s . ~s)" k v)))
  202. alist)
  203. (display ")\n"))
  204. (mkdir-p "racket/etc")
  205. (with-output-to-file "racket/etc/config.rktd"
  206. (lambda ()
  207. (write-racket-hash
  208. `((lib-search-dirs
  209. . (#f ,@(map (lambda (lib)
  210. (string-append (assoc-ref inputs lib)
  211. "/lib"))
  212. '("openssl"
  213. "sqlite"))))
  214. (build-stamp . "")
  215. (catalogs
  216. . (,(string-append
  217. "https://download.racket-lang.org/releases/"
  218. ,version
  219. "/catalog/")
  220. #f))))))
  221. #t))
  222. (add-before 'configure 'change-directory
  223. (lambda _
  224. (chdir "racket/src")
  225. #t))
  226. (add-after 'install 'remove-pkgs-directory
  227. ;; If the configured pkgs-dir exists, "pkgs.rktd" does not
  228. ;; exist, and a lock file does not exist, commands like
  229. ;; `raco pkg show` will try to create a lock file and fail
  230. ;; due to the read-only store.
  231. ;; Arguably this may be a bug in `pkg/private/lock`:
  232. ;; see <https://github.com/racket/racket/issues/3851>.
  233. ;; As a workaround, remove the directory.
  234. (lambda* (#:key outputs #:allow-other-keys)
  235. ;; rmdir because we want an error if it isn't empty
  236. (rmdir (string-append (assoc-ref outputs "out")
  237. "/share/racket/pkgs"))
  238. #t)))))
  239. (home-page "https://racket-lang.org")
  240. (synopsis "Racket without bundled packages such as DrRacket")
  241. (description
  242. "Racket is a general-purpose programming language in the Scheme family,
  243. with a large set of libraries and a compiler based on Chez Scheme. Racket is
  244. also a platform for language-oriented programming, from small domain-specific
  245. languages to complete language implementations.
  246. The ``minimal Racket'' distribution includes just enough of Racket for you to
  247. use @command{raco pkg} to install more. Bundled packages, such as the
  248. DrRacket IDE, are not included.")
  249. ;; https://download.racket-lang.org/license.html
  250. ;; The LGPL components are only used by Racket BC.
  251. (license (list asl2.0 expat))))
  252. (define-public racket-minimal-bc-3m
  253. (hidden-package
  254. (package
  255. (inherit racket-minimal)
  256. (name "racket-minimal-bc-3m")
  257. (inputs
  258. `(("libffi" ,libffi) ;; <- only for BC variants
  259. ,@(fold alist-delete
  260. (package-inputs racket-minimal)
  261. '("zlib" "zlib:static" "lz4" "lz4:static"))))
  262. (native-inputs
  263. `(("libtool" ,libtool)
  264. ("racket" ,(if (%current-target-system)
  265. racket-minimal
  266. racket-minimal-bc-cgc))))
  267. (arguments
  268. (substitute-keyword-arguments (package-arguments racket-minimal)
  269. ((#:configure-flags _ '())
  270. `(list "--enable-bconly"
  271. ,cfg-flag:enable-racket
  272. ,cfg-flag:enable-lt
  273. ,cfg-flag:sh-for-rktio))
  274. ((#:phases usual-phases)
  275. `(modify-phases ,usual-phases
  276. (delete 'unpack-nanopass+stex)
  277. (delete 'unpack-bootfiles)))))
  278. (synopsis "Minimal Racket with the BC [3M] runtime system")
  279. (description "The Racket BC (``before Chez'' or ``bytecode'')
  280. implementation was the default before Racket 8.0. It uses a compiler written
  281. in C targeting architecture-independent bytecode, plus a JIT compiler on most
  282. platforms. Racket BC has a different C API and supports a slightly different
  283. set of architectures than the current default runtime system, Racket CS (based
  284. on ``Chez Scheme'').
  285. This package is the normal implementation of Racket BC with a precise garbage
  286. collector, 3M (``Moving Memory Manager'').")
  287. ;; https://download.racket-lang.org/license.html
  288. ;; The LGPL components are only used by Racket BC.
  289. (license (list lgpl3+ asl2.0 expat)))))
  290. (define-public racket-minimal-bc-cgc
  291. (package
  292. (inherit racket-minimal-bc-3m)
  293. (name "racket-minimal-bc-cgc")
  294. (native-inputs
  295. (alist-delete "racket" (package-native-inputs racket-minimal-bc-3m)))
  296. (arguments
  297. (substitute-keyword-arguments (package-arguments racket-minimal-bc-3m)
  298. ((#:configure-flags _ '())
  299. `(list "--enable-cgcdefault"
  300. ,cfg-flag:enable-lt
  301. ,cfg-flag:sh-for-rktio))))
  302. (synopsis "Old Racket implementation used for bootstrapping")
  303. (description "This variant of the Racket BC (``before Chez'' or
  304. ``bytecode'') implementation is not recommended for general use. It uses
  305. CGC (a ``Conservative Garbage Collector''), which was succeeded as default in
  306. PLT Scheme version 370 (which translates to 3.7 in the current versioning
  307. scheme) by the 3M variant, which in turn was succeeded in version 8.0 by the
  308. Racket CS implementation.
  309. Racket BC [CGC] is primarily used for bootstrapping Racket BC [3M]. It may
  310. also be used for embedding applications without the annotations needed in C
  311. code to use the 3M garbage collector.")))
  312. (define-public racket-bootstrap-chez-bootfiles
  313. (hidden-package
  314. (package
  315. (inherit racket-minimal)
  316. (name "racket-bootstrap-chez-bootfiles")
  317. (inputs `())
  318. (native-inputs
  319. `(("racket" ,(if (%current-target-system)
  320. racket-minimal
  321. racket-minimal-bc-3m))
  322. ("stex" ,@(assoc-ref (package-native-inputs chez-scheme) "stex"))
  323. ("nanopass" ,@(assoc-ref (package-native-inputs chez-scheme)
  324. "nanopass"))))
  325. (arguments
  326. `(#:phases
  327. (modify-phases %standard-phases
  328. (add-after 'unpack 'unpack-nanopass+stex
  329. (lambda* (#:key inputs native-inputs #:allow-other-keys)
  330. (with-directory-excursion "racket/src/ChezScheme"
  331. ,unpack-nanopass+stex)
  332. #t))
  333. (delete 'configure)
  334. (delete 'patch-generated-file-shebangs)
  335. (replace 'build
  336. (lambda* (#:key inputs outputs #:allow-other-keys)
  337. (with-directory-excursion "racket/src/ChezScheme"
  338. (invoke (string-append (assoc-ref inputs "racket")
  339. "/bin/racket")
  340. "rktboot/main.rkt"
  341. "--dest" (assoc-ref outputs "out")))
  342. #t))
  343. (delete 'check)
  344. (delete 'install))))
  345. (synopsis "Chez Scheme bootfiles bootstrapped by Racket")
  346. (description "Chez Scheme is a self-hosting compiler: building it
  347. requires ``bootfiles'' containing the Scheme-implemented portions compiled for
  348. the current platform. (Chez can then cross-compile bootfiles for all other
  349. supported platforms.)
  350. The Racket package @code{cs-bootstrap} (part of the main Racket Git
  351. repository) implements enough of a Chez Scheme simulation to load the Chez
  352. Scheme compiler purely from source into Racket and apply the compiler to
  353. itself, thus bootstrapping Chez Scheme. Bootstrapping takes about 10 times as
  354. long as using an existing Chez Scheme, but @code{cs-bootstrap} supports Racket
  355. 7.1 and later, including the Racket BC variant.
  356. Note that the generated bootfiles are specific to Racket's fork of Chez
  357. Scheme, and @code{cs-bootstrap} does not currently support building upstream
  358. Chez Scheme.")
  359. (license (list asl2.0)))))
  360. (define %installer-mirrors
  361. ;; Source:
  362. ;; https://github.com/racket/racket-lang-org/blob/master/download/data.rkt#L58
  363. ;; Matthew Flatt says: "note that many are commented out"
  364. ;; INVARIANT: End with a trailing "/"!
  365. '("https://mirror.racket-lang.org/installers/"
  366. "https://www.cs.utah.edu/plt/installers/"
  367. "https://plt.cs.northwestern.edu/racket-mirror/"
  368. "https://mirror.csclub.uwaterloo.ca/racket/racket-installers/"
  369. ;; Universität Tübingen is using a self-signed HTTPS certificate:
  370. "http://mirror.informatik.uni-tuebingen.de/mirror/racket/"
  371. "https://racket.infogroep.be/"
  372. ))
  373. (define %main-repo-main-distribution-pkgs
  374. ;; These are the packages developed in the main Racket Git repository
  375. ;; that are part of the main distribution.
  376. '("at-exp-lib"
  377. "base"
  378. "compiler-lib"
  379. ;; NOT "compiler-test"
  380. "compiler"
  381. "net-doc"
  382. "net-lib"
  383. ;; NOT "net-test"
  384. "net"
  385. ;; NOT "plt-services"
  386. ;; NOT "racket-benchmarks"
  387. ;; NOT "racket-build-guide"
  388. "racket-doc"
  389. "racket-index"
  390. "racket-lib"
  391. ;; NOT "racket-test-core"
  392. ;; NOT "racket-test-extra"
  393. ;; NOT "racket-test"
  394. "zo-lib"))
  395. (define-public racket
  396. (package
  397. (inherit racket-minimal)
  398. (name "racket")
  399. (version (package-version racket-minimal)) ; needed for origin uri to work
  400. (source
  401. (origin
  402. (method url-fetch)
  403. (uri (map (lambda (base)
  404. (string-append base version "/racket-src.tgz"))
  405. %installer-mirrors))
  406. (sha256
  407. (base32
  408. "10sgzsraxzxp1k2y2wvz8rcjwvhbcd6k72l9lyqr34yazlwfdz26"))
  409. (snippet
  410. #~(begin
  411. (use-modules (guix build utils)
  412. (ice-9 match)
  413. (ice-9 regex))
  414. ;; unbundle minimal Racket
  415. (for-each delete-file-recursively
  416. '("collects"
  417. "doc"
  418. "etc"
  419. "README"
  420. "src"))
  421. ;; unbundle package sources included elsewhere
  422. (with-directory-excursion "share/pkgs"
  423. (for-each delete-file-recursively
  424. '#+%main-repo-main-distribution-pkgs))
  425. #t))))
  426. (inputs
  427. `(("cairo" ,cairo)
  428. ("fontconfig" ,fontconfig)
  429. ("glib" ,glib)
  430. ("glu" ,glu)
  431. ("gmp" ,gmp)
  432. ("gtk+" ,gtk+) ; propagates gdk-pixbuf+svg
  433. ("libjpeg" ,libjpeg-turbo)
  434. ("libpng" ,libpng)
  435. ("libx11" ,libx11)
  436. ("mesa" ,mesa)
  437. ("mpfr" ,mpfr)
  438. ("pango" ,pango)
  439. ("unixodbc" ,unixodbc)
  440. ("libedit" ,libedit)))
  441. (native-inputs
  442. `(("racket" ,racket-minimal)
  443. ("extend-layer" ,extend-layer)
  444. ("main-repo" ,(package-source racket-minimal))))
  445. (arguments
  446. `(#:phases
  447. (modify-phases %standard-phases
  448. (add-before 'configure 'unpack-packages
  449. (let ((unpack (assoc-ref %standard-phases 'unpack)))
  450. (lambda* (#:key native-inputs inputs outputs #:allow-other-keys)
  451. (let* ((racket (assoc-ref (or native-inputs inputs) "racket"))
  452. (prefix (assoc-ref outputs "out"))
  453. (pkgs-dir (string-append prefix "/share/racket/pkgs")))
  454. (mkdir-p pkgs-dir)
  455. (copy-recursively
  456. "share/links.rktd"
  457. (string-append prefix "/share/racket/links.rktd"))
  458. (copy-recursively "share/pkgs" pkgs-dir)
  459. ;; NOTE: unpack changes the working directory
  460. (unpack #:source (assoc-ref (or native-inputs inputs)
  461. "main-repo"))
  462. (for-each (lambda (pkg)
  463. (define dest (string-append pkgs-dir "/" pkg))
  464. (mkdir-p dest)
  465. (copy-recursively (string-append "pkgs/" pkg)
  466. dest))
  467. ',%main-repo-main-distribution-pkgs)
  468. #t))))
  469. (replace 'configure
  470. (lambda* (#:key native-inputs inputs outputs #:allow-other-keys)
  471. (let ((racket (assoc-ref (or native-inputs inputs) "racket"))
  472. (prefix (assoc-ref outputs "out")))
  473. (apply invoke
  474. (string-append racket "/bin/racket")
  475. (assoc-ref inputs "extend-layer")
  476. racket
  477. prefix
  478. (map
  479. (lambda (lib)
  480. (string-append (assoc-ref inputs lib) "/lib"))
  481. '("cairo"
  482. "fontconfig"
  483. "glib"
  484. "glu"
  485. "gmp"
  486. "gtk+"
  487. "libjpeg"
  488. "libpng"
  489. "libx11"
  490. "mesa"
  491. "mpfr"
  492. "pango"
  493. "unixodbc"
  494. "libedit")))
  495. #t)))
  496. (replace 'build
  497. (lambda* (#:key native-inputs inputs outputs #:allow-other-keys)
  498. (invoke (string-append (assoc-ref (or native-inputs inputs)
  499. "racket")
  500. "/bin/racket")
  501. "--config"
  502. (string-append (assoc-ref outputs "out")
  503. "/etc/racket")
  504. "-l"
  505. "raco"
  506. "setup")
  507. #t))
  508. (delete 'install))
  509. ;; we still don't have these:
  510. #:tests? #f))
  511. (synopsis "A programmable programming language in the Scheme family")
  512. (description
  513. "Racket is a general-purpose programming language in the Scheme family,
  514. with a large set of libraries and a compiler based on Chez Scheme. Racket is
  515. also a platform for language-oriented programming, from small domain-specific
  516. languages to complete language implementations.
  517. The main Racket distribution comes with many bundled packages, including the
  518. DrRacket IDE, libraries for GUI and web programming, and implementations of
  519. languages such as Typed Racket, R5RS and R6RS Scheme, Algol 60, and Datalog.")))
  520. (define extend-layer
  521. (scheme-file
  522. "extend-layer.rkt"
  523. `(module
  524. extend-layer racket/base
  525. (require racket/cmdline
  526. racket/match
  527. racket/file
  528. racket/list
  529. racket/pretty)
  530. (define config-file-pth
  531. "etc/racket/config.rktd")
  532. (define (build-path-string . args)
  533. (path->string (apply build-path args)))
  534. (define rx:racket
  535. ;; Guile's reader doesn't support #rx"racket"
  536. (regexp "racket"))
  537. (command-line
  538. #:args (parent-layer prefix . lib-dir*)
  539. (let* ([config
  540. (for/fold
  541. ([config (file->value (build-path parent-layer
  542. config-file-pth))])
  543. ([spec (in-list
  544. '((lib-dir lib-search-dirs "lib/racket")
  545. (share-dir share-search-dirs "share/racket")
  546. (links-file
  547. links-search-files
  548. "share/racket/links.rktd")
  549. (pkgs-dir pkgs-search-dirs "share/racket/pkgs")
  550. (bin-dir bin-search-dirs "bin")
  551. (man-dir man-search-dirs "share/man")
  552. (doc-dir doc-search-dirs "share/doc/racket")
  553. (include-dir
  554. include-search-dirs
  555. "include/racket")))])
  556. (match-define (list main-key search-key pth) spec)
  557. (hash-set*
  558. config
  559. main-key
  560. (build-path-string prefix pth)
  561. search-key
  562. (list* #f
  563. (hash-ref config
  564. main-key
  565. (build-path-string parent-layer pth))
  566. (filter values (hash-ref config search-key null)))))]
  567. [config
  568. (hash-set config
  569. 'apps-dir
  570. (build-path-string prefix "share/applications"))]
  571. [config
  572. ;; place new foreign lib-search-dirs before old
  573. ;; foreign dirs, but after Racket layers
  574. (let-values
  575. ([(rkt extra)
  576. (partition (lambda (pth)
  577. (or (not pth)
  578. (regexp-match? rx:racket pth)))
  579. (hash-ref config 'lib-search-dirs))])
  580. (hash-set config
  581. 'lib-search-dirs
  582. (append rkt
  583. lib-dir*
  584. extra)))]
  585. [bin-dir
  586. (hash-ref config 'bin-dir)]
  587. [config
  588. (hash-set* config
  589. 'config-tethered-console-bin-dir bin-dir
  590. 'config-tethered-gui-bin-dir bin-dir)]
  591. [new-config-pth
  592. (build-path prefix config-file-pth)])
  593. (make-parent-directory* new-config-pth)
  594. (call-with-output-file*
  595. new-config-pth
  596. (lambda (out)
  597. (pretty-write config out))))))))