1{
2 config,
3 options,
4 lib,
5 pkgs,
6 ...
7}:
8let
9 cfg = config.nixpkgs;
10 opt = options.nixpkgs;
11
12 isConfig = x: builtins.isAttrs x || lib.isFunction x;
13
14 optCall = f: x: if lib.isFunction f then f x else f;
15
16 mergeConfig =
17 lhs_: rhs_:
18 let
19 lhs = optCall lhs_ { inherit pkgs; };
20 rhs = optCall rhs_ { inherit pkgs; };
21 in
22 lib.recursiveUpdate lhs rhs
23 // lib.optionalAttrs (lhs ? packageOverrides) {
24 packageOverrides =
25 pkgs:
26 optCall lhs.packageOverrides pkgs // optCall (lib.attrByPath [ "packageOverrides" ] { } rhs) pkgs;
27 }
28 // lib.optionalAttrs (lhs ? perlPackageOverrides) {
29 perlPackageOverrides =
30 pkgs:
31 optCall lhs.perlPackageOverrides pkgs
32 // optCall (lib.attrByPath [ "perlPackageOverrides" ] { } rhs) pkgs;
33 };
34
35 configType = lib.mkOptionType {
36 name = "nixpkgs-config";
37 description = "nixpkgs config";
38 check =
39 x:
40 let
41 traceXIfNot = c: if c x then true else lib.traceSeqN 1 x false;
42 in
43 traceXIfNot isConfig;
44 merge = args: lib.foldr (def: mergeConfig def.value) { };
45 };
46
47 overlayType = lib.mkOptionType {
48 name = "nixpkgs-overlay";
49 description = "nixpkgs overlay";
50 check = lib.isFunction;
51 merge = lib.mergeOneOption;
52 };
53
54 pkgsType = lib.types.pkgs // {
55 # This type is only used by itself, so let's elaborate the description a bit
56 # for the purpose of documentation.
57 description = "An evaluation of Nixpkgs; the top level attribute set of packages";
58 };
59
60 hasBuildPlatform = opt.buildPlatform.highestPrio < (lib.mkOptionDefault { }).priority;
61 hasHostPlatform = opt.hostPlatform.isDefined;
62 hasPlatform = hasHostPlatform || hasBuildPlatform;
63
64 # Context for messages
65 hostPlatformLine = lib.optionalString hasHostPlatform "${lib.showOptionWithDefLocs opt.hostPlatform}";
66 buildPlatformLine = lib.optionalString hasBuildPlatform "${lib.showOptionWithDefLocs opt.buildPlatform}";
67
68 legacyOptionsDefined =
69 lib.optional (opt.localSystem.highestPrio < (lib.mkDefault { }).priority) opt.system
70 ++ lib.optional (opt.localSystem.highestPrio < (lib.mkOptionDefault { }).priority) opt.localSystem
71 ++ lib.optional (opt.crossSystem.highestPrio < (lib.mkOptionDefault { }).priority) opt.crossSystem;
72
73 defaultPkgs =
74 if opt.hostPlatform.isDefined then
75 let
76 isCross = cfg.buildPlatform != cfg.hostPlatform;
77 systemArgs =
78 if isCross then
79 {
80 localSystem = cfg.buildPlatform;
81 crossSystem = cfg.hostPlatform;
82 }
83 else
84 {
85 localSystem = cfg.hostPlatform;
86 };
87 in
88 import ../../.. (
89 {
90 inherit (cfg) config overlays;
91 }
92 // systemArgs
93 )
94 else
95 import ../../.. {
96 inherit (cfg)
97 config
98 overlays
99 localSystem
100 crossSystem
101 ;
102 };
103
104 finalPkgs = if opt.pkgs.isDefined then cfg.pkgs.appendOverlays cfg.overlays else defaultPkgs;
105
106in
107
108{
109 imports = [
110 ./assertions.nix
111 ./meta.nix
112 (lib.mkRemovedOptionModule [ "nixpkgs" "initialSystem" ]
113 "The NixOS options `nesting.clone` and `nesting.children` have been deleted, and replaced with named specialisation. Therefore `nixpgks.initialSystem` has no effect anymore."
114 )
115 ];
116
117 options.nixpkgs = {
118
119 pkgs = lib.mkOption {
120 defaultText = lib.literalExpression ''
121 import "''${nixos}/.." {
122 inherit (cfg) config overlays localSystem crossSystem;
123 }
124 '';
125 type = pkgsType;
126 example = lib.literalExpression "import <nixpkgs> {}";
127 description = ''
128 If set, the pkgs argument to all NixOS modules is the value of
129 this option, extended with `nixpkgs.overlays`, if
130 that is also set. Either `nixpkgs.crossSystem` or
131 `nixpkgs.localSystem` will be used in an assertion
132 to check that the NixOS and Nixpkgs architectures match. Any
133 other options in `nixpkgs.*`, notably `config`,
134 will be ignored.
135
136 If unset, the pkgs argument to all NixOS modules is determined
137 as shown in the default value for this option.
138
139 The default value imports the Nixpkgs source files
140 relative to the location of this NixOS module, because
141 NixOS and Nixpkgs are distributed together for consistency,
142 so the `nixos` in the default value is in fact a
143 relative path. The `config`, `overlays`,
144 `localSystem`, and `crossSystem` come
145 from this option's siblings.
146
147 This option can be used by applications like NixOps to increase
148 the performance of evaluation, or to create packages that depend
149 on a container that should be built with the exact same evaluation
150 of Nixpkgs, for example. Applications like this should set
151 their default value using `lib.mkDefault`, so
152 user-provided configuration can override it without using
153 `lib`.
154
155 Note that using a distinct version of Nixpkgs with NixOS may
156 be an unexpected source of problems. Use this option with care.
157 '';
158 };
159
160 config = lib.mkOption {
161 default = { };
162 example = lib.literalExpression ''
163 { allowBroken = true; allowUnfree = true; }
164 '';
165 type = configType;
166 description = ''
167 Global configuration for Nixpkgs.
168 The complete list of [Nixpkgs configuration options](https://nixos.org/manual/nixpkgs/unstable/#sec-config-options-reference) is in the [Nixpkgs manual section on global configuration](https://nixos.org/manual/nixpkgs/unstable/#chap-packageconfig).
169
170 Ignored when {option}`nixpkgs.pkgs` is set.
171 '';
172 };
173
174 overlays = lib.mkOption {
175 default = [ ];
176 example = lib.literalExpression ''
177 [
178 (self: super: {
179 openssh = super.openssh.override {
180 hpnSupport = true;
181 kerberos = self.libkrb5;
182 };
183 })
184 ]
185 '';
186 type = lib.types.listOf overlayType;
187 description = ''
188 List of overlays to apply to Nixpkgs.
189 This option allows modifying the Nixpkgs package set accessed through the `pkgs` module argument.
190
191 For details, see the [Overlays chapter in the Nixpkgs manual](https://nixos.org/manual/nixpkgs/stable/#chap-overlays).
192
193 If the {option}`nixpkgs.pkgs` option is set, overlays specified using `nixpkgs.overlays` will be applied after the overlays that were already included in `nixpkgs.pkgs`.
194 '';
195 };
196
197 hostPlatform = lib.mkOption {
198 type = lib.types.either lib.types.str lib.types.attrs; # TODO utilize lib.systems.parsedPlatform
199 example = {
200 system = "aarch64-linux";
201 };
202 # Make sure that the final value has all fields for sake of other modules
203 # referring to this. TODO make `lib.systems` itself use the module system.
204 apply = lib.systems.elaborate;
205 description = ''
206 Specifies the platform where the NixOS configuration will run.
207
208 To cross-compile, set also `nixpkgs.buildPlatform`.
209
210 Ignored when `nixpkgs.pkgs` is set.
211 '';
212 };
213
214 buildPlatform = lib.mkOption {
215 type = lib.types.either lib.types.str lib.types.attrs; # TODO utilize lib.systems.parsedPlatform
216 default = cfg.hostPlatform;
217 example = {
218 system = "x86_64-linux";
219 };
220 # Make sure that the final value has all fields for sake of other modules
221 # referring to this.
222 apply =
223 inputBuildPlatform:
224 let
225 elaborated = lib.systems.elaborate inputBuildPlatform;
226 in
227 if lib.systems.equals elaborated cfg.hostPlatform then
228 cfg.hostPlatform # make identical, so that `==` equality works; see https://github.com/NixOS/nixpkgs/issues/278001
229 else
230 elaborated;
231 defaultText = lib.literalExpression ''config.nixpkgs.hostPlatform'';
232 description = ''
233 Specifies the platform on which NixOS should be built.
234 By default, NixOS is built on the system where it runs, but you can
235 change where it's built. Setting this option will cause NixOS to be
236 cross-compiled.
237
238 For instance, if you're doing distributed multi-platform deployment,
239 or if you're building machines, you can set this to match your
240 development system and/or build farm.
241
242 Ignored when `nixpkgs.pkgs` is set.
243 '';
244 };
245
246 localSystem = lib.mkOption {
247 type = lib.types.attrs; # TODO utilize lib.systems.parsedPlatform
248 default = { inherit (cfg) system; };
249 example = {
250 system = "aarch64-linux";
251 };
252 # Make sure that the final value has all fields for sake of other modules
253 # referring to this. TODO make `lib.systems` itself use the module system.
254 apply = lib.systems.elaborate;
255 defaultText = lib.literalExpression ''config.nixpkgs.system'';
256 description = ''
257 Systems with a recently generated `hardware-configuration.nix`
258 do not need to specify this option, unless cross-compiling, in which case
259 you should set *only* {option}`nixpkgs.buildPlatform`.
260
261 If this is somehow not feasible, you may fall back to removing the
262 {option}`nixpkgs.hostPlatform` line from the generated config and
263 use the old options.
264
265 Specifies the platform on which NixOS should be built. When
266 `nixpkgs.crossSystem` is unset, it also specifies
267 the platform *for* which NixOS should be
268 built. If this option is unset, it defaults to the platform
269 type of the machine where evaluation happens. Specifying this
270 option is useful when doing distributed multi-platform
271 deployment, or when building virtual machines. See its
272 description in the Nixpkgs manual for more details.
273
274 Ignored when `nixpkgs.pkgs` or `hostPlatform` is set.
275 '';
276 };
277
278 # TODO deprecate. "crossSystem" is a nonsense identifier, because "cross"
279 # is a relation between at least 2 systems in the context of a
280 # specific build step, not a single system.
281 crossSystem = lib.mkOption {
282 type = lib.types.nullOr lib.types.attrs; # TODO utilize lib.systems.parsedPlatform
283 default = null;
284 example = {
285 system = "aarch64-linux";
286 };
287 description = ''
288 Systems with a recently generated `hardware-configuration.nix`
289 may instead specify *only* {option}`nixpkgs.buildPlatform`,
290 or fall back to removing the {option}`nixpkgs.hostPlatform` line from the generated config.
291
292 Specifies the platform for which NixOS should be
293 built. Specify this only if it is different from
294 `nixpkgs.localSystem`, the platform
295 *on* which NixOS should be built. In other
296 words, specify this to cross-compile NixOS. Otherwise it
297 should be set as null, the default. See its description in the
298 Nixpkgs manual for more details.
299
300 Ignored when `nixpkgs.pkgs` or `hostPlatform` is set.
301 '';
302 };
303
304 system = lib.mkOption {
305 type = lib.types.str;
306 example = "i686-linux";
307 default =
308 if opt.hostPlatform.isDefined then
309 throw ''
310 Neither ${opt.system} nor any other option in nixpkgs.* is meant
311 to be read by modules and configurations.
312 Use pkgs.stdenv.hostPlatform instead.
313 ''
314 else
315 throw ''
316 Neither ${opt.hostPlatform} nor the legacy option ${opt.system} has been set.
317 You can set ${opt.hostPlatform} in hardware-configuration.nix by re-running
318 a recent version of nixos-generate-config.
319 The option ${opt.system} is still fully supported for NixOS 22.05 interoperability,
320 but will be deprecated in the future, so we recommend to set ${opt.hostPlatform}.
321 '';
322 defaultText = lib.literalMD ''
323 Traditionally `builtins.currentSystem`, but unset when invoking NixOS through `lib.nixosSystem`.
324 '';
325 description = ''
326 This option does not need to be specified for NixOS configurations
327 with a recently generated `hardware-configuration.nix`.
328
329 Specifies the Nix platform type on which NixOS should be built.
330 It is better to specify `nixpkgs.localSystem` instead.
331 ```
332 {
333 nixpkgs.system = ..;
334 }
335 ```
336 is the same as
337 ```
338 {
339 nixpkgs.localSystem.system = ..;
340 }
341 ```
342 See `nixpkgs.localSystem` for more information.
343
344 Ignored when `nixpkgs.pkgs`, `nixpkgs.localSystem` or `nixpkgs.hostPlatform` is set.
345 '';
346 };
347 };
348
349 config = {
350 _module.args = {
351 pkgs =
352 # We explicitly set the default override priority, so that we do not need
353 # to evaluate finalPkgs in case an override is placed on `_module.args.pkgs`.
354 # After all, to determine a definition priority, we need to evaluate `._type`,
355 # which is somewhat costly for Nixpkgs. With an explicit priority, we only
356 # evaluate the wrapper to find out that the priority is lower, and then we
357 # don't need to evaluate `finalPkgs`.
358 lib.mkOverride lib.modules.defaultOverridePriority finalPkgs.__splicedPackages;
359 };
360
361 assertions =
362 let
363 # Whether `pkgs` was constructed by this module. This is false when any of
364 # nixpkgs.pkgs or _module.args.pkgs is set.
365 constructedByMe =
366 # We set it with default priority and it can not be merged, so if the
367 # pkgs module argument has that priority, it's from us.
368 (lib.modules.mergeAttrDefinitionsWithPrio options._module.args).pkgs.highestPrio
369 == lib.modules.defaultOverridePriority
370 # Although, if nixpkgs.pkgs is set, we did forward it, but we did not construct it.
371 && !opt.pkgs.isDefined;
372 in
373 [
374 (
375 let
376 nixosExpectedSystem =
377 if config.nixpkgs.crossSystem != null then
378 config.nixpkgs.crossSystem.system or (lib.systems.parse.doubleFromSystem (
379 lib.systems.parse.mkSystemFromString config.nixpkgs.crossSystem.config
380 ))
381 else
382 config.nixpkgs.localSystem.system or (lib.systems.parse.doubleFromSystem (
383 lib.systems.parse.mkSystemFromString config.nixpkgs.localSystem.config
384 ));
385 nixosOption =
386 if config.nixpkgs.crossSystem != null then "nixpkgs.crossSystem" else "nixpkgs.localSystem";
387 pkgsSystem = finalPkgs.stdenv.targetPlatform.system;
388 in
389 {
390 assertion = constructedByMe -> !hasPlatform -> nixosExpectedSystem == pkgsSystem;
391 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.";
392 }
393 )
394 {
395 assertion = constructedByMe -> hasPlatform -> legacyOptionsDefined == [ ];
396 message = ''
397 Your system configures nixpkgs with the platform parameter${lib.optionalString hasBuildPlatform "s"}:
398 ${hostPlatformLine}${buildPlatformLine}
399 However, it also defines the legacy options:
400 ${lib.concatMapStrings lib.showOptionWithDefLocs legacyOptionsDefined}
401 For a future proof system configuration, we recommend to remove
402 the legacy definitions.
403 '';
404 }
405 {
406 assertion = opt.pkgs.isDefined -> cfg.config == { };
407 message = ''
408 Your system configures nixpkgs with an externally created instance.
409 `nixpkgs.config` options should be passed when creating the instance instead.
410
411 Current value:
412 ${lib.generators.toPretty { multiline = true; } cfg.config}
413
414 Defined in:
415 ${lib.concatMapStringsSep "\n" (file: " - ${file}") opt.config.files}
416 '';
417 }
418 ];
419 };
420
421 # needs a full nixpkgs path to import nixpkgs
422 meta.buildDocsInSandbox = false;
423}