on fa2fa13 help sign in
haskell.nix/modules/package.nix
360 lines 10 kB history raw
1# package descriptions in hackage will look like:
2# { system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs }:
3# { flags = { flag1 = false; flags2 = true; ... };
4# package = { specVersion = "X.Y"; identifier = { name = "..."; version = "a.b.c.d"; };
5# license = "..."; copyright = "..."; maintainer = "..."; author = "...";
6# homepage = "..."; url = "..."; synopsis = "..."; description = "...";
7# buildType = "Simple"; # or Custom, Autoconf, ...
8# };
9# components = {
10# "..." = { depends = [ (hsPkgs.base) ... ]; };
11# exes = { "..." = { depends = ... };
12# "..." = { depends = ... }; };
13# tests = { "..." = { depends = ... }; ... };
14# };
16{ parentConfig, mod_args, listOfFilteringNulls, componentOptions, packageOptions }:
17{ lib, config, pkgs, haskellLib, ... }:
19with lib;
20with types;
22# Work around issue that can cause _lots_ of files to be copied into the store.
23# See https://github.com/NixOS/nixpkgs/pull/64691
24let
25 path = types.path // { check = x: types.path.check (x.origSrc or x); };
27 componentType = submodule {
28 # add the shared componentOptions
29 options = (packageOptions config) // {
30 buildable = mkOption {
31 type = bool;
32 default = true;
33 };
34 plugins = mkOption {
35 type = listOf (submodule {
36 options = {
37 library = mkOption {
38 type = unspecified;
39 };
40 moduleName = mkOption {
41 type = str;
42 };
43 args = mkOption {
44 type = listOf str;
45 default = [];
46 };
47 };
48 });
49 default = [];
50 };
51 depends = mkOption {
52 type = listOfFilteringNulls unspecified;
53 default = [];
54 };
55 libs = mkOption {
56 type = listOfFilteringNulls (either (nullOr package) (listOfFilteringNulls package));
57 default = [];
58 };
59 frameworks = mkOption {
60 type = listOfFilteringNulls package;
61 default = [];
62 };
63 pkgconfig = mkOption {
64 type = listOf (listOfFilteringNulls package);
65 default = [];
66 };
67 build-tools = mkOption {
68 type = listOfFilteringNulls unspecified;
69 default = [];
70 };
71 modules = mkOption {
72 type = listOfFilteringNulls unspecified;
73 default = [];
74 };
75 asmSources = mkOption {
76 type = listOfFilteringNulls unspecified;
77 default = [];
78 };
79 cmmSources = mkOption {
80 type = listOfFilteringNulls unspecified;
81 default = [];
82 };
83 cSources = mkOption {
84 type = listOfFilteringNulls unspecified;
85 default = [];
86 };
87 cxxSources = mkOption {
88 type = listOfFilteringNulls unspecified;
89 default = [];
90 };
91 jsSources = mkOption {
92 type = listOfFilteringNulls unspecified;
93 default = [];
94 };
95 hsSourceDirs = mkOption {
96 type = listOfFilteringNulls unspecified;
97 default = ["."];
98 };
99 includeDirs = mkOption {
100 type = listOfFilteringNulls unspecified;
101 default = [];
102 };
103 includes = mkOption {
104 type = listOfFilteringNulls unspecified;
105 default = [];
106 };
107 mainPath = mkOption {
108 type = listOfFilteringNulls unspecified;
109 default = [];
110 };
111 extraSrcFiles = mkOption {
112 type = listOfFilteringNulls unspecified;
113 default = [];
114 };
115 platforms = mkOption {
116 type = nullOr (listOfFilteringNulls unspecified);
117 default = null;
118 };
119 };
120 };
122in {
123 # This is how the Nix expressions generated by *-to-nix receive
124 # their flags argument.
125 config._module.args = mod_args // { flags = config.flags; };
127 options = (packageOptions parentConfig) // {
128 # TODO: Add descriptions to everything.
129 flags = mkOption {
130 type = attrsOf bool;
131 };
132 package = {
133 specVersion = mkOption {
134 type = str;
135 };
137 identifier.name = mkOption {
138 type = str;
139 };
141 identifier.version = mkOption {
142 type = str;
143 };
145 license = mkOption {
146 type = str;
147 };
149 copyright = mkOption {
150 type = str;
151 };
153 maintainer = mkOption {
154 type = str;
155 };
157 author = mkOption {
158 type = str;
159 };
161 homepage = mkOption {
162 type = str;
163 };
165 url = mkOption {
166 type = str;
167 };
169 synopsis = mkOption {
170 type = str;
171 };
173 description = mkOption {
174 type = str;
175 };
177 buildType = mkOption {
178 type = str;
179 };
181 setup-depends = mkOption {
182 type = listOfFilteringNulls unspecified;
183 default = [];
184 };
186 detailLevel = mkOption {
187 type = str;
188 default = "MinimalDetails";
189 };
191 licenseFiles = mkOption {
192 type = listOfFilteringNulls unspecified;
193 default = [];
194 };
196 dataDir = mkOption {
197 type = str;
198 default = "";
199 };
201 dataFiles = mkOption {
202 type = listOfFilteringNulls unspecified;
203 default = [];
204 };
206 extraSrcFiles = mkOption {
207 type = listOfFilteringNulls unspecified;
208 default = [];
209 };
211 extraTmpFiles = mkOption {
212 type = listOfFilteringNulls unspecified;
213 default = [];
214 };
216 extraDocFiles = mkOption {
217 type = listOfFilteringNulls unspecified;
218 default = [];
219 };
221 cleanHpack = mkOption {
222 type = bool;
223 default = false;
224 };
226 isLocal = mkOption {
227 type = bool;
228 default = false;
229 };
231 isProject = mkOption {
232 type = bool;
233 default = false;
234 };
236 buildable = mkOption {
237 type = bool;
238 default = true;
239 };
240 };
242 components = {
243 setup = mkOption {
244 type = nullOr componentType;
245 default = {
246 depends = [];
247 libs = [];
248 frameworks = [];
249 doExactConfig = false;
250 # We have to set hsSourceDirs or cleanCabalComponent will
251 # include everything (and as a result all the components of
252 # the package will depend on everything in the package).
253 # TODO find a better way
254 hsSourceDirs = ["setup-src"];
255 includeDirs = [];
256 asmSources = [];
257 cSources = [];
258 cmmSources = [];
259 cxxSources = [];
260 jsSources = [];
261 extraSrcFiles = [ "Setup.hs" "Setup.lhs" ];
262 platforms = null;
263 };
264 };
265 library = mkOption {
266 type = nullOr componentType;
267 default = null;
268 };
269 sublibs = mkOption {
270 type = attrsOf componentType;
271 default = {};
272 };
273 foreignlibs = mkOption {
274 type = attrsOf componentType;
275 default = {};
276 };
277 exes = mkOption {
278 type = attrsOf componentType;
279 default = {};
280 };
281 tests = mkOption {
282 type = attrsOf componentType;
283 default = {};
284 };
285 benchmarks = mkOption {
286 type = attrsOf componentType;
287 default = {};
288 };
289 };
291 name = mkOption {
292 type = str;
293 default = "${config.package.identifier.name}-${config.package.identifier.version}";
294 defaultText = "\${config.package.identifier.name}-\${config.package.identifier.version}";
295 };
296 sha256 = mkOption {
297 type = nullOr str;
298 default = null;
299 };
300 src = mkOption {
301 type = either path package;
302 default = pkgs.fetchurl { url = "mirror://hackage/${config.name}.tar.gz"; inherit (config) sha256; };
303 defaultText = "pkgs.fetchurl { url = \"mirror://hackage/\${config.name}.tar.gz\"; inherit (config) sha256; };";
304 };
305 cabal-generator = mkOption {
306 type = nullOr str;
307 default = null;
308 };
309 revision = mkOption {
310 type = nullOr int;
311 default = null;
312 };
313 revisionSha256 = mkOption {
314 type = nullOr str;
315 default = null;
316 };
317 patches = mkOption {
318 type = listOf (either unspecified path);
319 default = [];
320 };
321 # This used to be `components.all` but it has been added back as `allComponent` to
322 # to avoid confusion. It is not mapped by `builder/hspkg-builder.nix` to anything
323 # you can build. Instead it is used internally when `configureAllComponents`
324 # is set or for tests whe on `cabal-doctest` is in the `setup-depends` of the package.
325 allComponent = mkOption {
326 type = componentType;
327 apply = all: all // {
328 # TODO: Should this check for the entire component
329 # definition to match, rather than just the identifier?
330 depends = builtins.filter (p: p.identifier != config.package.identifier) all.depends;
331 };
332 description = "The merged dependencies of all other components";
333 };
334 };
336 # This has one quirk. Manually setting options on the all component
337 # will be considered a conflict. This is almost always fine; most
338 # settings should be modified in either the package options, or an
339 # individual component's options. When this isn't sufficient,
340 # mkForce is a reasonable workaround.
341 #
342 # An alternative solution to mkForce for many of the options where
343 # this is relevant would be to switch from the bool type to
344 # something like an anyBool type, which would merge definitions by
345 # returning true if any is true.
346 config.allComponent =
347 let allComps = haskellLib.getAllComponents config;
348 in lib.mkMerge (
349 builtins.map (c:
350 # Exclude attributes that are likely to have conflicting definitions
351 # (a common use case for `all` is in `shellFor` and it only has an
352 # install phase).
353 builtins.removeAttrs c ["preCheck" "postCheck" "keepSource"]
354 ) allComps
355 ) // {
356 # If any one of the components needs us to keep the source
357 # then keep it for the `all` component
358 keepSource = lib.foldl' (x: comp: x || comp.keepSource) false allComps;
359 };