about summary refs log tree commit diff
path: root/nix/buildLisp/default.nix
blob: 5a2b7853dcdbc9db1c32515edac165150fd63a0d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# buildLisp provides Nix functions to build Common Lisp packages,
# targeting SBCL.
#
# buildLisp is designed to enforce conventions and do away with the
# free-for-all of existing Lisp build systems.

{ pkgs ? { third_party = import <nixpkgs> {}; }
, ... }:

let
  inherit (builtins) map elemAt match;
  inherit (pkgs.third_party) lib runCommand writeText sbcl;

  #
  # Internal helper definitions
  #

  # 'genCompileLisp' generates a Lisp file that instructs SBCL to
  # compile the provided list of Lisp source files to $out.
  genCompileLisp = srcs: writeText "compile.lisp" ''
      ;; This file compiles the specified sources into the Nix build
      ;; directory, creating one FASL file for each source.
      (require 'sb-posix)

      (defun nix-compile-lisp (srcfile)
        (let ((outfile (make-pathname :type "fasl"
                                      :directory (or (sb-posix:getenv "NIX_BUILD_TOP")
                                                     (error "not running in a Nix build"))
                                      :defaults srcfile)))
          (multiple-value-bind (_outfile _warnings-p failure-p)
              (compile-file srcfile :output-file outfile)
            (when failure-p
              (sb-posix:exit 1)))))

      (let ((*compile-verbose* t)
            ;; FASL files are compiled into the working directory of the
            ;; build and *then* moved to the correct out location.
            (pwd (sb-posix:getcwd)))

        ;; These forms were inserted by the Nix build:
        ${
          lib.concatStringsSep "\n" (map (src: "(nix-compile-lisp \"${src}\")") srcs)
        }
      )
    '';

  #
  # Public API functions
  #

  # Add an `overrideLisp` attribute to a function result that works
  # similar to `overrideAttrs`, but is used specifically for the
  # arguments passed to Lisp builders.
  makeOverridable = f: orig: (f orig) // {
    overrideLisp = new: makeOverridable f (orig // (new orig));
  };

  # 'library' builds a list of Common Lisp files into a single FASL
  # which can then be loaded into SBCL.
  library = { name, srcs, deps ? [] }: runCommand "${name}-cllib" {} ''
    ${sbcl}/bin/sbcl --script ${genCompileLisp srcs}

    # FASL files can be combined by simply concatenating them together:
    mkdir $out
    cat ./*.fasl > $out/${name}.fasl
  '';

  # 'program' creates an executable containing a dumped image of the
  # specified sources and dependencies.
  program = {};

  # 'sbclWith' creates an image with the specified libraries /
  # programs loaded.
  sbclWith = {};
in {
  library = makeOverridable library;
  program = makeOverridable program;
  sbclWith = makeOverridable sbclWith;
}