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)
61 # Stolen from python-packages.nix
62 # Actually no idea how this works
63 makeOverridableLispPackage = f: origArgs:
66 overrideWith = newArgs: origArgs // (if pkgs.lib.isFunction newArgs then newArgs origArgs else newArgs);
68 if builtins.isAttrs ff then (ff // {
69 overrideLispAttrs = newArgs: makeOverridableLispPackage f (overrideWith newArgs);
71 else if builtins.isFunction ff then {
72 overrideLispAttrs = newArgs: makeOverridableLispPackage f (overrideWith newArgs);
77 buildAsdf = { asdf, pkg, program, flags, faslExt }:
79 inherit (asdf) pname version;
82 cp -v ${asdf}/lib/common-lisp/asdf/build/asdf.lisp asdf.lisp
83 ${pkg}/bin/${program} ${toString flags} < <(echo '(compile-file "asdf.lisp")')
87 cp -v asdf.${faslExt} $out
93 # Wrapper around stdenv.mkDerivation for building ASDF systems.
95 build-asdf-system = makeOverridableLispPackage (
101 # Native libraries, will be appended to the library path
104 # Java libraries for ABCL, will be appended to the class path
108 # these should be packages built with `build-asdf-system`
109 # TODO(kasper): use propagatedBuildInputs
112 # Derivation containing the CL implementation package
115 # Name of the Lisp executable
116 program ? pkg.meta.mainProgram or pkg.pname,
118 # General flags to the Lisp executable
121 # Extension for implementation-dependent FASL files
124 # ASDF amalgamation file to use
125 # Created in build/asdf.lisp by `make` in ASDF source tree
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.
132 # .asd's not listed in `systems` are removed in
133 # installPhase. This prevents asdf from referring to uncompiled
134 # systems on run time.
136 # Also useful when the pname is different than the system name,
137 # such as when using reverse domain naming.
140 # The .asd files that this package provides
141 # TODO(kasper): remove
144 # Other args to mkDerivation
148 (stdenv.mkDerivation (rec {
150 version nativeLibs javaLibs lispLibs systems asds
151 pkg program flags faslExt
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.
161 # `lisp` must evaluate this file then exit immediately. For
162 # example, SBCL's --script flag does just that.
165 # Every other library worked fine with asdf:compile-system in
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}";
183 source ${./setup-hook.sh}
186 runHook postConfigure
189 buildPhase = optionalString (src != null) ''
192 export CL_SOURCE_REGISTRY=$CL_SOURCE_REGISTRY:$src//
193 export ASDF_OUTPUT_TRANSLATIONS="$src:$(pwd):${storeDir}:${storeDir}"
194 ${pkg}/bin/${program} ${toString flags} < $buildScript
199 # Copy compiled files to store
201 # Make sure to include '$' in regex to prevent skipping
202 # stuff like 'iolib.asdf.asd' for system 'iolib.asd'
204 # Same with '/': `local-time.asd` for system `cl-postgres+local-time.asd`
207 mkSystemsRegex = systems:
208 concatMapStringsSep "\\|" (replaceStrings ["." "+"] ["[.]" "[+]"]) systems;
216 # Remove all .asd files except for those in `systems`.
217 find $out -name "*.asd" \
218 | grep -v "/\(${mkSystemsRegex systems}\)\.asd$" \
219 | xargs rm -fv || true
224 dontPatchShebangs = true;
226 # Not sure if it's needed, but caused problems with SBCL
227 # save-lisp-and-die binaries in the past
231 isJVM = args.pkg.pname == "abcl";
232 javaLibs = lib.optionals isJVM args.javaLibs or [];
234 pname = "${args.pkg.pname}-${args.pname}";
235 src = if args?patches || args?postPatch
236 then pkgs.applyPatches {
238 patches = args.patches or [];
239 postPatch = args.postPatch or "";
244 propagatedBuildInputs = args.propagatedBuildInputs or []
245 ++ lispLibs ++ javaLibs ++ nativeLibs;
246 meta = (args.meta or {}) // {
247 maintainers = args.meta.maintainers or lib.teams.lisp.members;
250 # Useful for overriding
251 # Overriding code would prefer to use pname from the attribute set
252 # However, pname is extended with the implementation name
253 # Moreover, it is used in the default list of systems to load
254 # So we pass the original pname
258 # Build the set of lisp packages using `lisp`
259 # These packages are defined manually for one reason or another:
260 # - The library is not in quicklisp
261 # - The library that is in quicklisp is broken
262 # - Special build procedure such as cl-unicode, asdf
264 # They can use the auto-imported quicklisp packages as dependencies,
265 # but some of those don't work out of the box.
267 # E.g if a QL package depends on cl-unicode it won't build out of
269 commonLispPackagesFor = spec:
271 build-asdf-system' = body: build-asdf-system (body // spec);
272 in pkgs.callPackage ./packages.nix {
273 inherit spec quicklispPackagesFor;
274 build-asdf-system = build-asdf-system';
277 # Build the set of packages imported from quicklisp using `lisp`
278 quicklispPackagesFor = spec:
280 build-asdf-system' = body: build-asdf-system (body // spec);
281 in pkgs.callPackage ./ql.nix {
282 build-asdf-system = build-asdf-system';
285 # Creates a lisp wrapper with `packages` installed
287 # `packages` is a function that takes `clpkgs` - a set of lisp
288 # packages - as argument and returns the list of packages to be
290 # TODO(kasper): assert each package has the same lisp and asdf?
291 lispWithPackages = clpkgs: packages:
292 let first = head (lib.attrValues clpkgs); in
294 inherit (first) pkg program flags faslExt asdf;
295 # See dontUnpack in build-asdf-system
298 version = "packages";
299 lispLibs = packages clpkgs;
301 }).overrideAttrs(o: {
302 nativeBuildInputs = [ pkgs.makeBinaryWrapper ];
306 ${o.pkg}/bin/${o.program} \
307 $out/bin/${o.program} \
308 --add-flags "${toString o.flags}" \
309 --set ASDF "${o.asdfFasl}/asdf.${o.faslExt}" \
310 --prefix CL_SOURCE_REGISTRY : "$CL_SOURCE_REGISTRY''${CL_SOURCE_REGISTRY:+:}" \
311 --prefix ASDF_OUTPUT_TRANSLATIONS : "$(echo $CL_SOURCE_REGISTRY | sed s,//:,::,g):" \
312 --prefix LD_LIBRARY_PATH : "$LD_LIBRARY_PATH" \
313 --prefix DYLD_LIBRARY_PATH : "$DYLD_LIBRARY_PATH" \
314 --prefix CLASSPATH : "$CLASSPATH" \
315 --prefix GI_TYPELIB_PATH : "$GI_TYPELIB_PATH" \
316 --prefix PATH : "${makeBinPath (o.propagatedBuildInputs or [])}"
323 , program ? pkg.meta.mainProgram or pkg.pname
325 , asdf ? pkgs.asdf_3_3
326 , packageOverrides ? (self: super: {})
329 spec = { inherit pkg faslExt program flags asdf; };
330 pkgs = (commonLispPackagesFor spec).overrideScope packageOverrides;
331 withPackages = lispWithPackages pkgs;
332 withOverrides = packageOverrides:
334 inherit pkg faslExt program flags asdf;
335 inherit packageOverrides;
337 buildASDFSystem = args: build-asdf-system (args // spec);
339 inherit pkgs withPackages withOverrides buildASDFSystem;