Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1# lisp-modules {#lisp} 2 3This document describes the Nixpkgs infrastructure for building Common Lisp 4systems that use [ASDF](https://asdf.common-lisp.dev/) (Another System 5Definition Facility). It lives in `pkgs/development/lisp-modules`. 6 7## Overview {#lisp-overview} 8 9The main entry point of the API are the Common Lisp implementation packages 10themselves (e.g. `abcl`, `ccl`, `clasp-common-lisp`, `clisp`, `ecl`, 11`sbcl`). They have the `pkgs` and `withPackages` attributes, which can be used 12to discover available packages and to build wrappers, respectively. 13 14The `pkgs` attribute set contains packages that were automatically 15[imported](#lisp-importing-packages-from-quicklisp) from Quicklisp, and any 16other [manually defined](#lisp-defining-packages-inside) ones. Not every package 17works for all the CL implementations (e.g. `nyxt` only makes sense for `sbcl`). 18 19The `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, 22and `CL_SOURCE_REGISTRY`/`ASDF_OUTPUT_TRANSLATIONS` configured to 23[find the desired systems on runtime](#lisp-loading-systems). 24 25In addition, Lisps have the `withOverrides` function, which can be used to 26[substitute](#lisp-including-external-pkg-in-scope) any package in the scope of 27their `pkgs`. This will also be useful together with `overrideLispAttrs` when 28[dealing with slashy systems](#lisp-dealing-with-slashy-systems), because they 29should stay in the main package and be built by specifying the `systems` 30argument to `build-asdf-system`. 31 32## The 90% use case example {#lisp-use-case-example} 33 34The most common way to use the library is to run ad-hoc wrappers like this: 35 36`nix-shell -p 'sbcl.withPackages (ps: with ps; [ alexandria ])'` 37 38Then, in a shell: 39 40``` 41$ sbcl 42* (load (sb-ext:posix-getenv "ASDF")) 43* (asdf:load-system 'alexandria) 44``` 45 46Also one can create a `pkgs.mkShell` environment in `shell.nix`/`flake.nix`: 47 48```nix 49let 50 sbcl' = sbcl.withPackages (ps: [ ps.alexandria ]); 51in 52mkShell { 53 packages = [ sbcl' ]; 54} 55``` 56 57Such a Lisp can be now used e.g. to compile your sources: 58 59```nix 60{ 61 buildPhase = '' 62 runHook preBuild 63 64 ${sbcl'}/bin/sbcl --load my-build-file.lisp 65 66 runHook postBuild 67 ''; 68} 69``` 70 71## Importing packages from Quicklisp {#lisp-importing-packages-from-quicklisp} 72 73To save some work of writing Nix expressions, there is a script that imports all 74the packages distributed by Quicklisp into `imported.nix`. This works by parsing 75its `releases.txt` and `systems.txt` files, which are published every couple of 76months on [quicklisp.org](https://beta.quicklisp.org/dist/quicklisp.txt). 77 78The import process is implemented in the `import` directory as Common Lisp 79code in the `org.lispbuilds.nix` ASDF system. To run the script, one can 80execute `ql-import.lisp`: 81 82``` 83cd pkgs/development/lisp-modules 84nix-shell --run 'sbcl --script ql-import.lisp' 85``` 86 87The script will: 88 891. Download the latest Quicklisp `systems.txt` and `releases.txt` files 902. Generate a temporary SQLite database of all QL systems in `packages.sqlite` 913. Generate an `imported.nix` file from the database 92 93(The `packages.sqlite` file can be deleted at will, because it is regenerated 94each time the script runs.) 95 96The maintainer's job is to: 97 981. Re-run the `ql-import.lisp` script when there is a new Quicklisp release 992. [Add any missing native dependencies](#lisp-quicklisp-adding-native-dependencies) in `ql.nix` 1003. For packages that still don't build, [package them manually](#lisp-defining-packages-inside) in `packages.nix` 101 102Also, the `imported.nix` file **must not be edited manually**! It should only be 103generated as described in this section (by running `ql-import.lisp`). 104 105### Adding native dependencies {#lisp-quicklisp-adding-native-dependencies} 106 107The Quicklisp files contain ASDF dependency data, but don't include native 108library (CFFI) dependencies, and, in the case of ABCL, Java dependencies. 109 110The `ql.nix` file contains a long list of overrides, where these dependencies 111can be added. 112 113Packages defined in `packages.nix` contain these dependencies naturally. 114 115### Trusting `systems.txt` and `releases.txt` {#lisp-quicklisp-trusting} 116 117The previous implementation of `lisp-modules` didn't fully trust the Quicklisp 118data, because there were times where the dependencies specified were not 119complete and caused broken builds. It instead used a `nix-shell` environment to 120discover real dependencies by using the ASDF APIs. 121 122The current implementation has chosen to trust this data, because it's faster to 123parse a text file than to build each system to generate its Nix file, and 124because that way packages can be mass-imported. Because of that, there may come 125a day where some packages will break, due to bugs in Quicklisp. In that case, 126the fix could be a manual override in `packages.nix` and `ql.nix`. 127 128A known fact is that Quicklisp doesn't include dependencies on slashy systems in 129its data. This is an example of a situation where such fixes were used, e.g. to 130replace the `systems` attribute of the affected packages. (See the definition of 131`iolib`). 132 133### Quirks {#lisp-quicklisp-quirks} 134 135During Quicklisp import: 136 137- `+` in names is converted to `_plus{_,}`: `cl+ssl`->`cl_plus_ssl`, `alexandria+`->`alexandria_plus` 138- `.` in names is converted to `_dot_`: `iolib.base`->`iolib_dot_base` 139- names starting with a number have a `_` prepended (`3d-vectors`->`_3d-vectors`) 140- `_` in names is converted to `__` for reversibility 141 142## Defining packages manually inside Nixpkgs {#lisp-defining-packages-inside} 143 144Packages that for some reason are not in Quicklisp, and so cannot be 145auto-imported, or don't work straight from the import, are defined in the 146`packages.nix` file. 147 148In that file, use the `build-asdf-system` function, which is a wrapper around 149`mkDerivation` for building ASDF systems. Various other hacks are present, such 150as `build-with-compile-into-pwd` for systems which create files during 151compilation (such as cl-unicode). 152 153The `build-asdf-system` function is documented 154[here](#lisp-defining-packages-outside). Also, `packages.nix` is full of 155examples of how to use it. 156 157## Defining packages manually outside Nixpkgs {#lisp-defining-packages-outside} 158 159Lisp derivations (`abcl`, `sbcl` etc.) also export the `buildASDFSystem` 160function, which is similar to `build-asdf-system` from `packages.nix`, but is 161part of the public API. 162 163It takes the following arguments: 164 165- `pname`: the package name 166- `version`: the package version 167- `src`: the package source 168- `patches`: patches to apply to the source before build 169- `nativeLibs`: native libraries used by CFFI and grovelling 170- `javaLibs`: Java libraries for ABCL 171- `lispLibs`: dependencies on other packages build with `buildASDFSystem` 172- `systems`: list of systems to build 173 174It can be used to define packages outside Nixpkgs, and, for example, add them 175into the package scope with `withOverrides`. 176 177### Including an external package in scope {#lisp-including-external-pkg-in-scope} 178 179A package defined outside Nixpkgs using `buildASDFSystem` can be woven into the 180Nixpkgs-provided scope like this: 181 182```nix 183let 184 alexandria = sbcl.buildASDFSystem rec { 185 pname = "alexandria"; 186 version = "1.4"; 187 src = fetchFromGitLab { 188 domain = "gitlab.common-lisp.net"; 189 owner = "alexandria"; 190 repo = "alexandria"; 191 tag = "v${version}"; 192 hash = "sha256-1Hzxt65dZvgOFIljjjlSGgKYkj+YBLwJCACi5DZsKmQ="; 193 }; 194 }; 195 sbcl' = sbcl.withOverrides ( 196 self: super: { 197 inherit alexandria; 198 } 199 ); 200in 201sbcl'.pkgs.alexandria 202``` 203 204## Overriding package attributes {#lisp-overriding-package-attributes} 205 206Packages export the `overrideLispAttrs` function, which can be used to build a 207new package with different parameters. 208 209Example of overriding `alexandria`: 210 211```nix 212sbcl.pkgs.alexandria.overrideLispAttrs (oldAttrs: rec { 213 version = "1.4"; 214 src = fetchFromGitLab { 215 domain = "gitlab.common-lisp.net"; 216 owner = "alexandria"; 217 repo = "alexandria"; 218 tag = "v${version}"; 219 hash = "sha256-1Hzxt65dZvgOFIljjjlSGgKYkj+YBLwJCACi5DZsKmQ="; 220 }; 221}) 222``` 223 224### Dealing with slashy systems {#lisp-dealing-with-slashy-systems} 225 226Slashy (secondary) systems should not exist in their own packages! Instead, they 227should be included in the parent package as an extra entry in the `systems` 228argument to the `build-asdf-system`/`buildASDFSystem` functions. 229 230The reason is that ASDF searches for a secondary system in the `.asd` of the 231parent package. Thus, having them separate would cause either one of them not to 232load cleanly, because one will contains FASLs of itself but not the other, and 233vice versa. 234 235To package slashy systems, use `overrideLispAttrs`, like so: 236 237```nix 238ecl.pkgs.alexandria.overrideLispAttrs (oldAttrs: { 239 systems = oldAttrs.systems ++ [ "alexandria/tests" ]; 240 lispLibs = oldAttrs.lispLibs ++ [ ecl.pkgs.rt ]; 241}) 242``` 243 244See the [respective section](#lisp-including-external-pkg-in-scope) on using 245`withOverrides` for how to weave it back into `ecl.pkgs`. 246 247Note that sometimes the slashy systems might not only have more dependencies 248than the main one, but create a circular dependency between `.asd` 249files. Unfortunately, in this case an adhoc solution becomes necessary. 250 251## Building Wrappers {#lisp-building-wrappers} 252 253Wrappers can be built using the `withPackages` function of Common Lisp 254implementations (`abcl`, `ecl`, `sbcl` etc.): 255 256``` 257nix-shell -p 'sbcl.withPackages (ps: [ ps.alexandria ps.bordeaux-threads ])' 258``` 259 260Such a wrapper can then be used like this: 261 262``` 263$ sbcl 264* (load (sb-ext:posix-getenv "ASDF")) 265* (asdf:load-system 'alexandria) 266* (asdf:load-system 'bordeaux-threads) 267``` 268 269### Loading ASDF {#lisp-loading-asdf} 270 271For best results, avoid calling `(require 'asdf)` When using the 272library-generated wrappers. 273 274Use `(load (ext:getenv "ASDF"))` instead, supplying your implementation's way of 275getting an environment variable for `ext:getenv`. This will load the 276(pre-compiled to FASL) Nixpkgs-provided version of ASDF. 277 278### Loading systems {#lisp-loading-systems} 279 280There, you can use `asdf:load-system`. This works by setting the right 281values for the `CL_SOURCE_REGISTRY`/`ASDF_OUTPUT_TRANSLATIONS` environment 282variables, so that systems are found in the Nix store and pre-compiled FASLs are 283loaded. 284 285## Adding a new Lisp {#lisp-adding-a-new-lisp} 286 287The function `wrapLisp` is used to wrap Common Lisp implementations. It adds the 288`pkgs`, `withPackages`, `withOverrides` and `buildASDFSystem` attributes to the 289derivation. 290 291`wrapLisp` takes these arguments: 292 293- `pkg`: the Lisp package 294- `faslExt`: Implementation-specific extension for FASL files 295- `program`: The name of executable file in `${pkg}/bin/` (Default: `pkg.pname`) 296- `flags`: A list of flags to always pass to `program` (Default: `[]`) 297- `asdf`: The ASDF version to use (Default: `pkgs.asdf_3_3`) 298- `packageOverrides`: Package overrides config (Default: `(self: super: {})`) 299 300This example wraps CLISP: 301 302```nix 303wrapLisp { 304 pkg = clisp; 305 faslExt = "fas"; 306 flags = [ 307 "-E" 308 "UTF8" 309 ]; 310} 311```