1{
2 stdenv,
3 lib,
4 idris2,
5 makeBinaryWrapper,
6}:
7# Usage: let
8# pkg = idris2Packages.buildIdris {
9# src = ...;
10# ipkgName = "my-pkg";
11# idrisLibraries = [ ];
12# };
13# in {
14# lib1 = pkg.library { withSource = true; };
15#
16# # implicitly without source:
17# lib2 = pkg.library';
18#
19# bin = pkg.executable;
20# }
21#
22{
23 src,
24 ipkgName, # ipkg filename without the extension
25 version ? "unversioned",
26 idrisLibraries, # Other libraries built with buildIdris
27 ...
28}@attrs:
29
30let
31 # loop over idrisLibraries and normalize them by turning any that are
32 # direct outputs of the buildIdris function into the `.library {}`
33 # property.
34 idrisLibraryLibs = map (
35 idrisLib:
36 if lib.isDerivation idrisLib then
37 idrisLib
38 else if builtins.isFunction idrisLib then
39 idrisLib { }
40 else if (builtins.isAttrs idrisLib && idrisLib ? "library") then
41 idrisLib.library { }
42 else
43 throw "Found an Idris2 library dependency that was not the result of the buildIdris function"
44 ) idrisLibraries;
45
46 propagate =
47 libs: lib.unique (lib.concatMap (nextLib: [ nextLib ] ++ nextLib.propagatedIdrisLibraries) libs);
48 ipkgFileName = ipkgName + ".ipkg";
49 idrName = "idris2-${idris2.version}";
50 libSuffix = "lib/${idrName}";
51 libDirs = libs: (lib.makeSearchPath libSuffix libs) + ":${idris2}/${idrName}";
52 supportDir = "${idris2}/${idrName}/lib";
53 drvAttrs = builtins.removeAttrs attrs [
54 "ipkgName"
55 "idrisLibraries"
56 ];
57
58 mkDerivation =
59 withSource:
60 let
61 applyWithSource = lib: if withSource then lib.withSource else lib;
62 propagatedIdrisLibraries = map applyWithSource (propagate idrisLibraryLibs);
63 in
64 stdenv.mkDerivation (
65 finalAttrs:
66 drvAttrs
67 // {
68 pname = ipkgName;
69 inherit src version;
70 nativeBuildInputs = [
71 idris2
72 makeBinaryWrapper
73 ]
74 ++ attrs.nativeBuildInputs or [ ];
75 buildInputs = propagatedIdrisLibraries ++ attrs.buildInputs or [ ];
76
77 env.IDRIS2_PACKAGE_PATH = libDirs propagatedIdrisLibraries;
78
79 buildPhase = ''
80 runHook preBuild
81 idris2 --build ${ipkgFileName}
82 runHook postBuild
83 '';
84
85 passthru = {
86 inherit propagatedIdrisLibraries;
87 }
88 // (attrs.passthru or { });
89
90 shellHook = ''
91 export IDRIS2_PACKAGE_PATH="${finalAttrs.env.IDRIS2_PACKAGE_PATH}"
92 '';
93 }
94 );
95
96 mkExecutable =
97 withSource:
98 let
99 derivation = mkDerivation withSource;
100 in
101 derivation.overrideAttrs {
102 installPhase = ''
103 runHook preInstall
104 mkdir -p $out/bin
105 scheme_app="$(find ./build/exec -name '*_app')"
106 if [ "$scheme_app" = ''' ]; then
107 mv -- build/exec/* $out/bin/
108 chmod +x $out/bin/*
109 # ^ remove after Idris2 0.8.0 is released. will be superfluous:
110 # https://github.com/idris-lang/Idris2/pull/3189
111 else
112 cd build/exec/*_app
113 rm -f ./libidris2_support.{so,dylib}
114 for file in *.so; do
115 bin_name="''${file%.so}"
116 mv -- "$file" "$out/bin/$bin_name"
117
118 wrapProgram "$out/bin/$bin_name" \
119 --prefix LD_LIBRARY_PATH : ${supportDir} \
120 --prefix DYLD_LIBRARY_PATH : ${supportDir}
121 done
122 fi
123 runHook postInstall
124 '';
125
126 # allow an executable's dependencies to be built with source. this is convenient when
127 # building a development shell for the executable using `mkShell`'s `inputsFrom`.
128 passthru = derivation.passthru // {
129 withSource = mkExecutable true;
130 };
131 };
132
133 mkLibrary =
134 withSource:
135 let
136 installCmd = if withSource then "--install-with-src" else "--install";
137 derivation = mkDerivation withSource;
138 in
139 derivation.overrideAttrs {
140 installPhase = ''
141 runHook preInstall
142 mkdir -p $out/${libSuffix}
143 export IDRIS2_PREFIX=$out/lib
144 idris2 ${installCmd} ${ipkgFileName}
145 runHook postInstall
146 '';
147
148 # allow a library built without source to be changed to one with source
149 # via a passthru attribute; i.e. `my-pkg.library'.withSource`.
150 # this is convenient because a library derivation can be distributed as
151 # without-source by default but downstream projects can still build it
152 # with-source. We surface this regardless of whether the original library
153 # was built with source because that allows downstream to call this
154 # property unconditionally.
155 passthru = derivation.passthru // {
156 withSource = mkLibrary true;
157 };
158 };
159
160in
161{
162 executable = mkExecutable false;
163
164 library =
165 {
166 withSource ? false,
167 }:
168 mkLibrary withSource;
169
170 # Make a library without source; you can still use the `withSource` attribute
171 # on the resulting derivation to build the library with source at a later time.
172 library' = mkLibrary false;
173}