Merge pull request #251006 from Uthar/doc-lisp001

doc/lisp: Clarifications in the manual

authored by Weijia Wang and committed by GitHub bd2ccdef fdc0272b

+67 -72
+67 -72
doc/languages-frameworks/lisp.section.md
··· 1 1 # lisp-modules {#lisp} 2 2 3 3 This document describes the Nixpkgs infrastructure for building Common Lisp 4 - libraries that use ASDF (Another System Definition Facility). It lives in 5 - `pkgs/development/lisp-modules`. 4 + systems that use [ASDF](https://asdf.common-lisp.dev/) (Another System 5 + Definition Facility). It lives in `pkgs/development/lisp-modules`. 6 6 7 7 ## Overview {#lisp-overview} 8 8 9 9 The main entry point of the API are the Common Lisp implementation packages 10 - (e.g. `abcl`, `ccl`, `clasp-common-lisp`, `clisp` `ecl`, `sbcl`) 11 - themselves. They have the `pkgs` and `withPackages` attributes, which can be 12 - used to discover available packages and to build wrappers, respectively. 10 + themselves (e.g. `abcl`, `ccl`, `clasp-common-lisp`, `clisp`, `ecl`, 11 + `sbcl`). They have the `pkgs` and `withPackages` attributes, which can be used 12 + to discover available packages and to build wrappers, respectively. 13 13 14 - The `pkgs` attribute set contains packages that were automatically imported from 15 - Quicklisp, and any other manually defined ones. Not every package works for all 16 - the CL implementations (e.g. `nyxt` only makes sense for `sbcl`). 14 + The `pkgs` attribute set contains packages that were automatically 15 + [imported](#lisp-importing-packages-from-quicklisp) from Quicklisp, and any 16 + other [manually defined](#lisp-defining-packages-inside) ones. Not every package 17 + works for all the CL implementations (e.g. `nyxt` only makes sense for `sbcl`). 17 18 18 - The `withPackages` function is of primary utility. It is used to build runnable 19 - wrappers, with a pinned and pre-built ASDF FASL available in the `ASDF` 20 - environment variable, and `CL_SOURCE_REGISTRY`/`ASDF_OUTPUT_TRANSLATIONS` 21 - configured to find the desired systems on runtime. 22 - 23 - With a few exceptions, the primary thing that the infrastructure does is to run 24 - `asdf:load-system` for each system specified in the `systems` argument to 25 - `build-asdf-system`, and save the FASLs to the Nix store. Then, it makes these 26 - FASLs available to wrappers. Any other use-cases, such as producing SBCL 27 - executables with `sb-ext:save-lisp-and-die`, are achieved via overriding the 28 - `buildPhase` etc. 19 + The `withPackages` function is of primary utility. It is used to build 20 + [runnable wrappers](#lisp-building-wrappers), with a pinned and pre-built 21 + [ASDF FASL](#lisp-loading-asdf) available in the `ASDF` environment variable, 22 + and `CL_SOURCE_REGISTRY`/`ASDF_OUTPUT_TRANSLATIONS` configured to 23 + [find the desired systems on runtime](#lisp-loading-systems). 29 24 30 25 In addition, Lisps have the `withOverrides` function, which can be used to 31 - substitute any package in the scope of their `pkgs`. This will be useful 32 - together with `overrideLispAttrs` when dealing with slashy ASDF systems, because 33 - they should stay in the main package and be build by specifying the `systems` 26 + [substitute](#lisp-including-external-pkg-in-scope) any package in the scope of 27 + their `pkgs`. This will also be useful together with `overrideLispAttrs` when 28 + [dealing with slashy systems](#lisp-dealing-with-slashy-systems), because they 29 + should stay in the main package and be built by specifying the `systems` 34 30 argument to `build-asdf-system`. 35 31 36 32 ## The 90% use case example {#lisp-use-case-example} ··· 42 38 Then, in a shell: 43 39 44 40 ``` 45 - $ result/bin/sbcl 41 + $ sbcl 46 42 * (load (sb-ext:posix-getenv "ASDF")) 47 43 * (asdf:load-system 'alexandria) 48 44 ``` ··· 53 49 let 54 50 sbcl' = sbcl.withPackages (ps: [ ps.alexandria ]); 55 51 in mkShell { 56 - buildInputs = [ sbcl' ]; 52 + packages = [ sbcl' ]; 57 53 } 58 54 ``` 59 55 ··· 67 63 68 64 ## Importing packages from Quicklisp {#lisp-importing-packages-from-quicklisp} 69 65 70 - The library is able to very quickly import all the packages distributed by 71 - Quicklisp by parsing its `releases.txt` and `systems.txt` files. These files are 72 - available from [http://beta.quicklisp.org/dist/quicklisp.txt]. 66 + To save some work of writing Nix expressions, there is a script that imports all 67 + the packages distributed by Quicklisp into `imported.nix`. This works by parsing 68 + its `releases.txt` and `systems.txt` files, which are published every couple of 69 + months on [quicklisp.org](http://beta.quicklisp.org/dist/quicklisp.txt). 73 70 74 71 The import process is implemented in the `import` directory as Common Lisp 75 - functions in the `org.lispbuilds.nix` ASDF system. To run the script, one can 72 + code in the `org.lispbuilds.nix` ASDF system. To run the script, one can 76 73 execute `ql-import.lisp`: 77 74 78 75 ``` 76 + cd pkgs/development/lisp-modules 79 77 nix-shell --run 'sbcl --script ql-import.lisp' 80 78 ``` 81 79 82 80 The script will: 83 81 84 82 1. Download the latest Quicklisp `systems.txt` and `releases.txt` files 85 - 2. Generate an SQLite database of all QL systems in `packages.sqlite` 83 + 2. Generate a temporary SQLite database of all QL systems in `packages.sqlite` 86 84 3. Generate an `imported.nix` file from the database 87 85 88 - The maintainer's job there is to: 86 + (The `packages.sqlite` file can be deleted at will, because it is regenerated 87 + each time the script runs.) 89 88 90 - 1. Re-run the `ql-import.lisp` script 91 - 2. Add missing native dependencies in `ql.nix` 92 - 3. For packages that still don't build, package them manually in `packages.nix` 89 + The maintainer's job is to: 90 + 91 + 1. Re-run the `ql-import.lisp` script when there is a new Quicklisp release 92 + 2. [Add any missing native dependencies](#lisp-quicklisp-adding-native-dependencies) in `ql.nix` 93 + 3. For packages that still don't build, [package them manually](#lisp-defining-packages-inside) in `packages.nix` 93 94 94 95 Also, the `imported.nix` file **must not be edited manually**! It should only be 95 - generated as described in this section. 96 + generated as described in this section (by running `ql-import.lisp`). 96 97 97 98 ### Adding native dependencies {#lisp-quicklisp-adding-native-dependencies} 98 99 ··· 108 109 109 110 The previous implementation of `lisp-modules` didn't fully trust the Quicklisp 110 111 data, because there were times where the dependencies specified were not 111 - complete, and caused broken builds. It instead used a `nix-shell` environment to 112 + complete and caused broken builds. It instead used a `nix-shell` environment to 112 113 discover real dependencies by using the ASDF APIs. 113 114 114 115 The current implementation has chosen to trust this data, because it's faster to ··· 126 127 127 128 During Quicklisp import: 128 129 129 - - `+` in names are converted to `_plus{_,}`: `cl+ssl`->`cl_plus_ssl`, `alexandria+`->`alexandria_plus` 130 - - `.` to `_dot_`: `iolib.base`->`iolib_dot_base` 130 + - `+` in names is converted to `_plus{_,}`: `cl+ssl`->`cl_plus_ssl`, `alexandria+`->`alexandria_plus` 131 + - `.` in names is converted to `_dot_`: `iolib.base`->`iolib_dot_base` 131 132 - names starting with a number have a `_` prepended (`3d-vectors`->`_3d-vectors`) 132 133 - `_` in names is converted to `__` for reversibility 133 134 134 135 135 136 ## Defining packages manually inside Nixpkgs {#lisp-defining-packages-inside} 136 137 137 - New packages, that for some reason are not in Quicklisp, and so cannot be 138 - auto-imported, can be written in the `packages.nix` file. 138 + Packages that for some reason are not in Quicklisp, and so cannot be 139 + auto-imported, or don't work straight from the import, are defined in the 140 + `packages.nix` file. 139 141 140 142 In that file, use the `build-asdf-system` function, which is a wrapper around 141 143 `mkDerivation` for building ASDF systems. Various other hacks are present, such 142 144 as `build-with-compile-into-pwd` for systems which create files during 143 - compilation. 145 + compilation (such as cl-unicode). 144 146 145 - The `build-asdf-system` function is documented with comments in 146 - `nix-cl.nix`. Also, `packages.nix` is full of examples of how to use it. 147 + The `build-asdf-system` function is documented 148 + [here](#lisp-defining-packages-outside). Also, `packages.nix` is full of 149 + examples of how to use it. 147 150 148 151 ## Defining packages manually outside Nixpkgs {#lisp-defining-packages-outside} 149 152 150 153 Lisp derivations (`abcl`, `sbcl` etc.) also export the `buildASDFSystem` 151 - function, which is the same as `build-asdf-system`, except for the `lisp` 152 - argument which is set to the given CL implementation. 154 + function, which is similar to `build-asdf-system` from `packages.nix`, but is 155 + part of the public API. 156 + 157 + It takes the following arguments: 158 + 159 + - `pname`: the package name 160 + - `version`: the package version 161 + - `src`: the package source 162 + - `patches`: patches to apply to the source before build 163 + - `nativeLibs`: native libraries used by CFFI and grovelling 164 + - `javaLibs`: Java libraries for ABCL 165 + - `lispLibs`: dependencies on other packages build with `buildASDFSystem` 166 + - `systems`: list of systems to build 153 167 154 168 It can be used to define packages outside Nixpkgs, and, for example, add them 155 - into the package scope with `withOverrides` which will be discussed later on. 169 + into the package scope with `withOverrides`. 156 170 157 171 ### Including an external package in scope {#lisp-including-external-pkg-in-scope} 158 172 ··· 198 212 }) 199 213 ``` 200 214 201 - ## Overriding packages in scope {#lisp-overriding-packages-in-scope} 202 - 203 - Packages can be woven into a new scope by using `withOverrides`: 204 - 205 - ``` 206 - let 207 - sbcl' = sbcl.withOverrides (self: super: { 208 - alexandria = super.alexandria.overrideLispAttrs (oldAttrs: rec { 209 - pname = "alexandria"; 210 - version = "1.4"; 211 - src = fetchFromGitLab { 212 - domain = "gitlab.common-lisp.net"; 213 - owner = "alexandria"; 214 - repo = "alexandria"; 215 - rev = "v${version}"; 216 - hash = "sha256-1Hzxt65dZvgOFIljjjlSGgKYkj+YBLwJCACi5DZsKmQ="; 217 - }; 218 - }); 219 - }); 220 - in builtins.elemAt sbcl'.pkgs.bordeaux-threads.lispLibs 0 221 - ``` 222 - 223 215 ### Dealing with slashy systems {#lisp-dealing-with-slashy-systems} 224 216 225 217 Slashy (secondary) systems should not exist in their own packages! Instead, they ··· 240 232 }) 241 233 ``` 242 234 243 - See the respective section on using `withOverrides` for how to weave it back 244 - into `ecl.pkgs`. 235 + See the [respective section](#lisp-including-external-pkg-in-scope) on using 236 + `withOverrides` for how to weave it back into `ecl.pkgs`. 245 237 246 238 Note that sometimes the slashy systems might not only have more dependencies 247 239 than the main one, but create a circular dependency between `.asd` ··· 253 245 implementations (`abcl`, `ecl`, `sbcl` etc.): 254 246 255 247 ``` 256 - sbcl.withPackages (ps: [ ps.alexandria ps.bordeaux-threads ]) 248 + nix-shell -p 'sbcl.withPackages (ps: [ ps.alexandria ps.bordeaux-threads ])' 257 249 ``` 258 250 259 - Such a wrapper can then be executed like this: 251 + Such a wrapper can then be used like this: 260 252 261 253 ``` 262 - result/bin/sbcl 254 + $ sbcl 255 + * (load (sb-ext:posix-getenv "ASDF")) 256 + * (asdf:load-system 'alexandria) 257 + * (asdf:load-system 'bordeaux-threads) 263 258 ``` 264 259 265 260 ### Loading ASDF {#lisp-loading-asdf}