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 pname 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}";
181 source ${./setup-hook.sh}
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
191 # Copy compiled files to store
193 # Make sure to include '$' in regex to prevent skipping
194 # stuff like 'iolib.asdf.asd' for system 'iolib.asd'
196 # Same with '/': `local-time.asd` for system `cl-postgres+local-time.asd`
199 mkSystemsRegex = systems:
200 concatMapStringsSep "\\|" (replaceStrings ["." "+"] ["[.]" "[+]"]) systems;
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
212 dontPatchShebangs = true;
214 # Not sure if it's needed, but caused problems with SBCL
215 # save-lisp-and-die binaries in the past
219 src = if builtins.length (args.patches or []) > 0
220 then pkgs.applyPatches { inherit (args) src 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;
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
236 # They can use the auto-imported quicklisp packages as dependencies,
237 # but some of those don't work out of the box.
239 # E.g if a QL package depends on cl-unicode it won't build out of
241 commonLispPackagesFor = spec:
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';
249 # Build the set of packages imported from quicklisp using `lisp`
250 quicklispPackagesFor = spec:
252 build-asdf-system' = body: build-asdf-system (body // spec);
253 in pkgs.callPackage ./ql.nix {
254 build-asdf-system = build-asdf-system';
257 # Creates a lisp wrapper with `packages` installed
259 # `packages` is a function that takes `clpkgs` - a set of lisp
260 # packages - as argument and returns the list of packages to be
262 # TODO(kasper): assert each package has the same lisp and asdf?
263 lispWithPackages = clpkgs: packages:
264 let first = head (lib.attrValues clpkgs); in
266 inherit (first) pkg program flags faslExt asdf;
267 # See dontUnpack in build-asdf-system
269 pname = first.pkg.pname;
270 version = "with-packages";
271 lispLibs = packages clpkgs;
273 }).overrideAttrs(o: {
274 nativeBuildInputs = [ pkgs.makeBinaryWrapper ];
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 [])}"
295 , program ? pkg.meta.mainProgram or pkg.pname
297 , asdf ? pkgs.asdf_3_3
298 , packageOverrides ? (self: super: {})
301 spec = { inherit pkg faslExt program flags asdf; };
302 pkgs = (commonLispPackagesFor spec).overrideScope packageOverrides;
303 withPackages = lispWithPackages pkgs;
304 withOverrides = packageOverrides:
306 inherit pkg faslExt program flags asdf;
307 inherit packageOverrides;
309 buildASDFSystem = args: build-asdf-system (args // spec);
311 inherit pkgs withPackages withOverrides buildASDFSystem;