-
Notifications
You must be signed in to change notification settings - Fork 13
/
buildIdris.nix
182 lines (145 loc) · 4.8 KB
/
buildIdris.nix
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
{ stdenv, lib, makeWrapper, symlinkJoin, idris2, addLibraries, zsh }:
# # minimum requirements
{ name
, version ? "0.0"
, src
# Idris-specific options
, idrisLibraries ? [ ]
, idrisTestLibraries ? [ ]
, codegen ? null
, ipkgFile ? "${name}.ipkg"
, executable ? ""
, runtimeLibs ? false
# accept other arguments
, doCheck ? false
, ...
} @ cfg:
let
buildcommand = "${idris2.executable}" +
(if codegen == null then "" else " --codegen ${codegen}");
# Idris, and any packages needed to run tests
testIdris = addLibraries idris2 (idrisLibraries ++ lib.optionals doCheck idrisTestLibraries);
/* An intermediate derivation, which contains the source *and* the build products.
Without this, each of `pkg`, `pkg.withSource`, `pkg.asLib`, and `pkg.docs` has to
compile the project independently.
We're not using multi-output derivations because, depending on FFI, valid executables may
not be buildable as libraries.
*/
ttc = stdenv.mkDerivation (cfg // {
name = "${name}-ttc-${if version == null then "0.0" else version}";
nativeBuildInputs =
[ (addLibraries idris2 idrisLibraries) makeWrapper ]
++ cfg.nativeBuildInputs or [ ];
propagatedBuildInputs = lib.optional stdenv.isDarwin [ zsh ]
++ cfg.propagatedBuildInputs or [ ];
checkInputs = [ testIdris ] ++ cfg.checkInputs or [ ];
buildPhase = cfg.buildPhase or ''
runHook preBuild
${buildcommand} --build ${ipkgFile}
runHook postBuild
'';
inherit doCheck;
checkPhase = cfg.checkPhase or (
''
runHook preCheck
# if there is a 'test.ipkg' near the project root, build it
find . -maxdepth 2 -name test.ipkg -exec ${buildcommand} --build {} \;
runHook postCheck
''
);
installPhase = ''
# Cache everything for specialized builds
mkdir $out/
cp -r * $out/
'';
});
# Primary output; the executable
build = stdenv.mkDerivation (cfg // {
name = "${name}-${if version == null then "0.0" else version}";
src = ttc;
inherit (ttc.drvAttrs) nativeBuildInputs propagatedBuildInputs;
buildPhase = ''
echo "${ttc.name} already built; doing nothing"
'';
installPhase = cfg.binInstallPhase or (
let
forwardLibs =
if runtimeLibs then ''
wrapProgram $out/bin/${executable} \
--set-default IDRIS2_PREFIX "~/.idris2" \
--suffix LD_LIBRARY_PATH ':' "${idris2.support}/${idris2.name}/lib" \
--suffix IDRIS2_LIBS ':' "${idris2.support}/${idris2.name}/lib" \
--suffix IDRIS2_DATA ':' "${idris2.support}/${idris2.name}/support" \
'' else "";
in
cfg.installPhase or ''
runHook preBinInstall
mkdir $out
# if there is something in build/exec, copy it to $out/bin
if [ "$(ls build/exec)" ]; then
mkdir -p $out/bin
mv build/exec/* $out/bin
${forwardLibs}
else
echo "build succeeded; no executable produced" > $out/${name}.out
fi
runHook postBinInstall
''
);
});
# Library, for when something else depends on modules in this package
installLibrary = withSource:
let
thisLib = build.overrideAttrs
(_: {
installPhase = ''
runHook preLibInstall
# Prepare the install location
export IDRIS2_PREFIX=$out/
mkdir -p $(idris2 --libdir)
# Install
idris2 --install${if withSource then "-with-src" else ""} ${ipkgFile}
runHook postLibInstall
'';
});
in
# If (A < B) and (B < C); include A when buliding C
symlinkJoin
{
inherit (thisLib) name;
paths = [ thisLib ] ++ map (p: if withSource then p.withSource else p.asLib) idrisLibraries;
};
# Documenation output
docs =
build.overrideAttrs
({ name, ... }: {
name = name + "-docs";
buildPhase = cfg.docBuildPhase or ''
runHook preDocBuild
idris2 --mkdoc ${ipkgFile}
runHook postDocBuild
'';
installPhase = cfg.docInstallPhase or ''
runHook preDocInstall
mkdir -p $out/doc/${name}
mv build/docs/* $out/doc/${name}/
runHook postDocInstall
'';
});
in
# `$ nix build .#mypkg` =>
# build/exec/main
# becomes
# $out/bin/main
#
# `$ nix build .#mypkg.asLib` =>
# build/ttc/mypkg-0.0/*
# becomes
# $out/idris2-0.4.0/mypkg-0.0/*
build // {
asLib = installLibrary false;
withSource = installLibrary true;
docs = docs;
allDocs = symlinkJoin { name = "idris2-docs"; paths = [ docs ] ++ map (p: p.docs) (idrisLibraries ++ idrisTestLibraries); };
idrisAttrs = cfg;
} // (if executable == "" then { } else { inherit executable; })