1{ config, options, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.nixpkgs;
7 opt = options.nixpkgs;
8
9 isConfig = x:
10 builtins.isAttrs x || lib.isFunction x;
11
12 optCall = f: x:
13 if lib.isFunction f
14 then f x
15 else f;
16
17 mergeConfig = lhs_: rhs_:
18 let
19 lhs = optCall lhs_ { inherit pkgs; };
20 rhs = optCall rhs_ { inherit pkgs; };
21 in
22 recursiveUpdate lhs rhs //
23 optionalAttrs (lhs ? packageOverrides) {
24 packageOverrides = pkgs:
25 optCall lhs.packageOverrides pkgs //
26 optCall (attrByPath ["packageOverrides"] ({}) rhs) pkgs;
27 } //
28 optionalAttrs (lhs ? perlPackageOverrides) {
29 perlPackageOverrides = pkgs:
30 optCall lhs.perlPackageOverrides pkgs //
31 optCall (attrByPath ["perlPackageOverrides"] ({}) rhs) pkgs;
32 };
33
34 configType = mkOptionType {
35 name = "nixpkgs-config";
36 description = "nixpkgs config";
37 check = x:
38 let traceXIfNot = c:
39 if c x then true
40 else lib.traceSeqN 1 x false;
41 in traceXIfNot isConfig;
42 merge = args: foldr (def: mergeConfig def.value) {};
43 };
44
45 overlayType = mkOptionType {
46 name = "nixpkgs-overlay";
47 description = "nixpkgs overlay";
48 check = lib.isFunction;
49 merge = lib.mergeOneOption;
50 };
51
52 pkgsType = mkOptionType {
53 name = "nixpkgs";
54 description = "An evaluation of Nixpkgs; the top level attribute set of packages";
55 check = builtins.isAttrs;
56 };
57
58 defaultPkgs = import ../../.. {
59 inherit (cfg) config overlays localSystem crossSystem;
60 };
61
62 finalPkgs = if opt.pkgs.isDefined then cfg.pkgs.appendOverlays cfg.overlays else defaultPkgs;
63
64in
65
66{
67 options.nixpkgs = {
68
69 pkgs = mkOption {
70 defaultText = literalExpression ''
71 import "''${nixos}/.." {
72 inherit (cfg) config overlays localSystem crossSystem;
73 }
74 '';
75 type = pkgsType;
76 example = literalExpression "import <nixpkgs> {}";
77 description = ''
78 If set, the pkgs argument to all NixOS modules is the value of
79 this option, extended with <code>nixpkgs.overlays</code>, if
80 that is also set. Either <code>nixpkgs.crossSystem</code> or
81 <code>nixpkgs.localSystem</code> will be used in an assertion
82 to check that the NixOS and Nixpkgs architectures match. Any
83 other options in <code>nixpkgs.*</code>, notably <code>config</code>,
84 will be ignored.
85
86 If unset, the pkgs argument to all NixOS modules is determined
87 as shown in the default value for this option.
88
89 The default value imports the Nixpkgs source files
90 relative to the location of this NixOS module, because
91 NixOS and Nixpkgs are distributed together for consistency,
92 so the <code>nixos</code> in the default value is in fact a
93 relative path. The <code>config</code>, <code>overlays</code>,
94 <code>localSystem</code>, and <code>crossSystem</code> come
95 from this option's siblings.
96
97 This option can be used by applications like NixOps to increase
98 the performance of evaluation, or to create packages that depend
99 on a container that should be built with the exact same evaluation
100 of Nixpkgs, for example. Applications like this should set
101 their default value using <code>lib.mkDefault</code>, so
102 user-provided configuration can override it without using
103 <code>lib</code>.
104
105 Note that using a distinct version of Nixpkgs with NixOS may
106 be an unexpected source of problems. Use this option with care.
107 '';
108 };
109
110 config = mkOption {
111 default = {};
112 example = literalExpression
113 ''
114 { allowBroken = true; allowUnfree = true; }
115 '';
116 type = configType;
117 description = ''
118 The configuration of the Nix Packages collection. (For
119 details, see the Nixpkgs documentation.) It allows you to set
120 package configuration options.
121
122 Ignored when <code>nixpkgs.pkgs</code> is set.
123 '';
124 };
125
126 overlays = mkOption {
127 default = [];
128 example = literalExpression
129 ''
130 [
131 (self: super: {
132 openssh = super.openssh.override {
133 hpnSupport = true;
134 kerberos = self.libkrb5;
135 };
136 })
137 ]
138 '';
139 type = types.listOf overlayType;
140 description = ''
141 List of overlays to use with the Nix Packages collection.
142 (For details, see the Nixpkgs documentation.) It allows
143 you to override packages globally. Each function in the list
144 takes as an argument the <emphasis>original</emphasis> Nixpkgs.
145 The first argument should be used for finding dependencies, and
146 the second should be used for overriding recipes.
147
148 If <code>nixpkgs.pkgs</code> is set, overlays specified here
149 will be applied after the overlays that were already present
150 in <code>nixpkgs.pkgs</code>.
151 '';
152 };
153
154 localSystem = mkOption {
155 type = types.attrs; # TODO utilize lib.systems.parsedPlatform
156 default = { inherit (cfg) system; };
157 example = { system = "aarch64-linux"; config = "aarch64-unknown-linux-gnu"; };
158 # Make sure that the final value has all fields for sake of other modules
159 # referring to this. TODO make `lib.systems` itself use the module system.
160 apply = lib.systems.elaborate;
161 defaultText = literalExpression
162 ''(import "''${nixos}/../lib").lib.systems.examples.aarch64-multiplatform'';
163 description = ''
164 Specifies the platform on which NixOS should be built. When
165 <code>nixpkgs.crossSystem</code> is unset, it also specifies
166 the platform <emphasis>for</emphasis> which NixOS should be
167 built. If this option is unset, it defaults to the platform
168 type of the machine where evaluation happens. Specifying this
169 option is useful when doing distributed multi-platform
170 deployment, or when building virtual machines. See its
171 description in the Nixpkgs manual for more details.
172
173 Ignored when <code>nixpkgs.pkgs</code> is set.
174 '';
175 };
176
177 crossSystem = mkOption {
178 type = types.nullOr types.attrs; # TODO utilize lib.systems.parsedPlatform
179 default = null;
180 example = { system = "aarch64-linux"; config = "aarch64-unknown-linux-gnu"; };
181 description = ''
182 Specifies the platform for which NixOS should be
183 built. Specify this only if it is different from
184 <code>nixpkgs.localSystem</code>, the platform
185 <emphasis>on</emphasis> which NixOS should be built. In other
186 words, specify this to cross-compile NixOS. Otherwise it
187 should be set as null, the default. See its description in the
188 Nixpkgs manual for more details.
189
190 Ignored when <code>nixpkgs.pkgs</code> is set.
191 '';
192 };
193
194 system = mkOption {
195 type = types.str;
196 example = "i686-linux";
197 description = ''
198 Specifies the Nix platform type on which NixOS should be built.
199 It is better to specify <code>nixpkgs.localSystem</code> instead.
200 <programlisting>
201 {
202 nixpkgs.system = ..;
203 }
204 </programlisting>
205 is the same as
206 <programlisting>
207 {
208 nixpkgs.localSystem.system = ..;
209 }
210 </programlisting>
211 See <code>nixpkgs.localSystem</code> for more information.
212
213 Ignored when <code>nixpkgs.localSystem</code> is set.
214 Ignored when <code>nixpkgs.pkgs</code> is set.
215 '';
216 };
217
218 initialSystem = mkOption {
219 type = types.str;
220 internal = true;
221 description = ''
222 Preserved value of <literal>system</literal> passed to <literal>eval-config.nix</literal>.
223 '';
224 };
225 };
226
227 config = {
228 _module.args = {
229 pkgs = finalPkgs;
230 };
231
232 assertions = [
233 (
234 let
235 nixosExpectedSystem =
236 if config.nixpkgs.crossSystem != null
237 then config.nixpkgs.crossSystem.system or (lib.systems.parse.doubleFromSystem (lib.systems.parse.mkSystemFromString config.nixpkgs.crossSystem.config))
238 else config.nixpkgs.localSystem.system or (lib.systems.parse.doubleFromSystem (lib.systems.parse.mkSystemFromString config.nixpkgs.localSystem.config));
239 nixosOption =
240 if config.nixpkgs.crossSystem != null
241 then "nixpkgs.crossSystem"
242 else "nixpkgs.localSystem";
243 pkgsSystem = finalPkgs.stdenv.targetPlatform.system;
244 in {
245 assertion = nixosExpectedSystem == pkgsSystem;
246 message = "The NixOS nixpkgs.pkgs option was set to a Nixpkgs invocation that compiles to target system ${pkgsSystem} but NixOS was configured for system ${nixosExpectedSystem} via NixOS option ${nixosOption}. The NixOS system settings must match the Nixpkgs target system.";
247 }
248 )
249 ];
250 };
251}