typioca: 2.7.0 -> 2.8.0
[NixPkgs.git] / pkgs / development / lisp-modules / nix-cl.nix
blob3f45f58110e90b2032fa904e22c7cd46d8838569
1 # TODO:
2 # - faster build by using lisp with preloaded asdf?
3 # - dont include java libs unless abcl?
4 # - dont use build-asdf-system to build lispWithPackages?
5 # - make the lisp packages overridable? (e.g. buildInputs glibc->musl)
6 # - build asdf with nix and use that instead of one shipped with impls
7 #   (e.g. to fix build with clisp - does anyone use clisp?)
8 # - claspPackages ? (gotta package clasp with nix first)
9 # - hard one: remove unrelated sources ( of systems not being built)
10 # - figure out a less awkward way to patch sources
11 #   (have to build from src directly for SLIME to work, so can't just patch sources in place)
13 { pkgs
14 , lib
15 , stdenv
16 , ... }:
18 let
20   inherit (lib)
21     length
22     filter
23     foldl
24     unique
25     id
26     concat
27     concatMap
28     mutuallyExclusive
29     findFirst
30     remove
31     setAttr
32     getAttr
33     hasAttr
34     attrNames
35     attrValues
36     filterAttrs
37     mapAttrs
38     splitString
39     concatStringsSep
40     concatMapStringsSep
41     replaceStrings
42     removeSuffix
43     hasInfix
44     optionalString
45     makeBinPath
46     makeLibraryPath
47     makeSearchPath
48     recurseIntoAttrs
49   ;
51   inherit (builtins)
52     head
53     tail
54     elem
55     split
56     storeDir;
58   inherit (pkgs)
59     substituteAll;
61   # Stolen from python-packages.nix
62   # Actually no idea how this works
63   makeOverridableLispPackage = f: origArgs:
64     let
65       ff = f origArgs;
66       overrideWith = newArgs: origArgs // (if pkgs.lib.isFunction newArgs then newArgs origArgs else newArgs);
67     in
68       if builtins.isAttrs ff then (ff // {
69         overrideLispAttrs = newArgs: makeOverridableLispPackage f (overrideWith newArgs);
70       })
71       else if builtins.isFunction ff then {
72         overrideLispAttrs = newArgs: makeOverridableLispPackage f (overrideWith newArgs);
73         __functor = self: ff;
74       }
75       else ff;
77   buildAsdf = { asdf, pkg, program, flags, faslExt }:
78     stdenv.mkDerivation {
79       inherit (asdf) pname version;
80       dontUnpack = true;
81       buildPhase = ''
82         cp -v ${asdf}/lib/common-lisp/asdf/build/asdf.lisp asdf.lisp
83         ${pkg}/bin/${program} ${toString flags} < <(echo '(compile-file "asdf.lisp")')
84       '';
85       installPhase = ''
86         mkdir -p $out
87         cp -v asdf.${faslExt} $out
88       '';
89     };
92   #
93   # Wrapper around stdenv.mkDerivation for building ASDF systems.
94   #
95   build-asdf-system = makeOverridableLispPackage (
96     { pname,
97       version,
98       src ? null,
99       patches ? [],
101       # Native libraries, will be appended to the library path
102       nativeLibs ? [],
104       # Java libraries for ABCL, will be appended to the class path
105       javaLibs ? [],
107       # Lisp dependencies
108       # these should be packages built with `build-asdf-system`
109       # TODO(kasper): use propagatedBuildInputs
110       lispLibs ? [],
112       # Derivation containing the CL implementation package
113       pkg,
115       # Name of the Lisp executable
116       program ? pkg.meta.mainProgram or pkg.pname,
118       # General flags to the Lisp executable
119       flags ? [],
121       # Extension for implementation-dependent FASL files
122       faslExt,
124       # ASDF amalgamation file to use
125       # Created in build/asdf.lisp by `make` in ASDF source tree
126       asdf,
128       # Some libraries have multiple systems under one project, for
129       # example, cffi has cffi-grovel, cffi-toolchain etc.  By
130       # default, only the `pname` system is build.
131       #
132       # .asd's not listed in `systems` are removed in
133       # installPhase. This prevents asdf from referring to uncompiled
134       # systems on run time.
135       #
136       # Also useful when the pname is different than the system name,
137       # such as when using reverse domain naming.
138       systems ? [ pname ],
140       # The .asd files that this package provides
141       # TODO(kasper): remove
142       asds ? systems,
144       # Other args to mkDerivation
145       ...
146     } @ args:
148     stdenv.mkDerivation (rec {
149       inherit
150         pname version nativeLibs javaLibs lispLibs systems asds
151         pkg program flags faslExt
152       ;
154       # When src is null, we are building a lispWithPackages and only
155       # want to make use of the dependency environment variables
156       # generated by build-asdf-system
157       dontUnpack = src == null;
159       # Portable script to build the systems.
160       #
161       # `lisp` must evaluate this file then exit immediately. For
162       # example, SBCL's --script flag does just that.
163       #
164       # NOTE:
165       # Every other library worked fine with asdf:compile-system in
166       # buildScript.
167       #
168       # cl-syslog, for some reason, signals that CL-SYSLOG::VALID-SD-ID-P
169       # is undefined with compile-system, but works perfectly with
170       # load-system. Strange.
172       # TODO(kasper) portable quit
173       asdfFasl = buildAsdf { inherit asdf pkg program flags faslExt; };
175       buildScript = substituteAll {
176         src = ./builder.lisp;
177         asdf = "${asdfFasl}/asdf.${faslExt}";
178       };
180       preConfigure = ''
181         source ${./setup-hook.sh}
182         buildAsdfPath
183       '';
185       buildPhase = optionalString (src != null) ''
186         export CL_SOURCE_REGISTRY=$CL_SOURCE_REGISTRY:$src//
187         export ASDF_OUTPUT_TRANSLATIONS="$src:$(pwd):${storeDir}:${storeDir}"
188         ${pkg}/bin/${program} ${toString flags} < $buildScript
189       '';
191       # Copy compiled files to store
192       #
193       # Make sure to include '$' in regex to prevent skipping
194       # stuff like 'iolib.asdf.asd' for system 'iolib.asd'
195       #
196       # Same with '/': `local-time.asd` for system `cl-postgres+local-time.asd`
197       installPhase =
198         let
199           mkSystemsRegex = systems:
200             concatMapStringsSep "\\|" (replaceStrings ["." "+"] ["[.]" "[+]"]) systems;
201         in
202       ''
203         mkdir -pv $out
204         cp -r * $out
206         # Remove all .asd files except for those in `systems`.
207         find $out -name "*.asd" \
208         | grep -v "/\(${mkSystemsRegex systems}\)\.asd$" \
209         | xargs rm -fv || true
210       '';
212       dontPatchShebangs = true;
214       # Not sure if it's needed, but caused problems with SBCL
215       # save-lisp-and-die binaries in the past
216       dontStrip = true;
218     } // (args // {
219       src = if builtins.length (args.patches or []) > 0
220             then pkgs.applyPatches { inherit (args) src patches; }
221             else args.src;
222       patches = [];
223       propagatedBuildInputs = args.propagatedBuildInputs or []
224           ++ lispLibs ++ javaLibs ++ nativeLibs;
225       meta = (args.meta or {}) // {
226         maintainers = args.meta.maintainers or lib.teams.lisp.members;
227       };
228     })));
230   # Build the set of lisp packages using `lisp`
231   # These packages are defined manually for one reason or another:
232   # - The library is not in quicklisp
233   # - The library that is in quicklisp is broken
234   # - Special build procedure such as cl-unicode, asdf
235   #
236   # They can use the auto-imported quicklisp packages as dependencies,
237   # but some of those don't work out of the box.
238   #
239   # E.g if a QL package depends on cl-unicode it won't build out of
240   # the box.
241   commonLispPackagesFor = spec:
242     let
243       build-asdf-system' = body: build-asdf-system (body // spec);
244     in pkgs.callPackage ./packages.nix {
245       inherit spec quicklispPackagesFor;
246       build-asdf-system = build-asdf-system';
247     };
249   # Build the set of packages imported from quicklisp using `lisp`
250   quicklispPackagesFor = spec:
251     let
252       build-asdf-system' = body: build-asdf-system (body // spec);
253     in pkgs.callPackage ./ql.nix {
254       build-asdf-system = build-asdf-system';
255     };
257   # Creates a lisp wrapper with `packages` installed
258   #
259   # `packages` is a function that takes `clpkgs` - a set of lisp
260   # packages - as argument and returns the list of packages to be
261   # installed
262   # TODO(kasper): assert each package has the same lisp and asdf?
263   lispWithPackages = clpkgs: packages:
264     let first = head (lib.attrValues clpkgs); in
265     (build-asdf-system {
266       inherit (first) pkg program flags faslExt asdf;
267       # See dontUnpack in build-asdf-system
268       src = null;
269       pname = first.pkg.pname;
270       version = "with-packages";
271       lispLibs = packages clpkgs;
272       systems = [];
273     }).overrideAttrs(o: {
274       nativeBuildInputs = [ pkgs.makeBinaryWrapper ];
275       installPhase = ''
276         mkdir -pv $out/bin
277         makeWrapper \
278           ${o.pkg}/bin/${o.program} \
279           $out/bin/${o.program} \
280           --add-flags "${toString o.flags}" \
281           --set ASDF "${o.asdfFasl}/asdf.${o.faslExt}" \
282           --prefix CL_SOURCE_REGISTRY : "$CL_SOURCE_REGISTRY" \
283           --prefix ASDF_OUTPUT_TRANSLATIONS : "$(echo $CL_SOURCE_REGISTRY | sed s,//:,::,g):" \
284           --prefix LD_LIBRARY_PATH : "$LD_LIBRARY_PATH" \
285           --prefix DYLD_LIBRARY_PATH : "$DYLD_LIBRARY_PATH" \
286           --prefix CLASSPATH : "$CLASSPATH" \
287           --prefix GI_TYPELIB_PATH : "$GI_TYPELIB_PATH" \
288           --prefix PATH : "${makeBinPath (o.propagatedBuildInputs or [])}"
289       '';
290     });
292   wrapLisp = {
293     pkg
294     , faslExt
295     , program ? pkg.meta.mainProgram or pkg.pname
296     , flags ? []
297     , asdf ? pkgs.asdf_3_3
298     , packageOverrides ? (self: super: {})
299   }:
300     let
301       spec = { inherit pkg faslExt program flags asdf; };
302       pkgs = (commonLispPackagesFor spec).overrideScope packageOverrides;
303       withPackages = lispWithPackages pkgs;
304       withOverrides = packageOverrides:
305         wrapLisp {
306           inherit pkg faslExt program flags asdf;
307           inherit packageOverrides;
308         };
309       buildASDFSystem = args: build-asdf-system (args // spec);
310     in pkg // {
311       inherit pkgs withPackages withOverrides buildASDFSystem;
312     };
314 in wrapLisp