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 defaultText = lib.literalExpression ''(import "''${nixos}/../lib").lib.systems.examples.aarch64-multiplatform'';
206 description = ''
207 Specifies the platform where the NixOS configuration will run.
208
209 To cross-compile, set also `nixpkgs.buildPlatform`.
210
211 Ignored when `nixpkgs.pkgs` is set.
212 '';
213 };
214
215 buildPlatform = lib.mkOption {
216 type = lib.types.either lib.types.str lib.types.attrs; # TODO utilize lib.systems.parsedPlatform
217 default = cfg.hostPlatform;
218 example = {
219 system = "x86_64-linux";
220 };
221 # Make sure that the final value has all fields for sake of other modules
222 # referring to this.
223 apply =
224 inputBuildPlatform:
225 let
226 elaborated = lib.systems.elaborate inputBuildPlatform;
227 in
228 if lib.systems.equals elaborated cfg.hostPlatform then
229 cfg.hostPlatform # make identical, so that `==` equality works; see https://github.com/NixOS/nixpkgs/issues/278001
230 else
231 elaborated;
232 defaultText = lib.literalExpression ''config.nixpkgs.hostPlatform'';
233 description = ''
234 Specifies the platform on which NixOS should be built.
235 By default, NixOS is built on the system where it runs, but you can
236 change where it's built. Setting this option will cause NixOS to be
237 cross-compiled.
238
239 For instance, if you're doing distributed multi-platform deployment,
240 or if you're building machines, you can set this to match your
241 development system and/or build farm.
242
243 Ignored when `nixpkgs.pkgs` is set.
244 '';
245 };
246
247 localSystem = lib.mkOption {
248 type = lib.types.attrs; # TODO utilize lib.systems.parsedPlatform
249 default = { inherit (cfg) system; };
250 example = {
251 system = "aarch64-linux";
252 };
253 # Make sure that the final value has all fields for sake of other modules
254 # referring to this. TODO make `lib.systems` itself use the module system.
255 apply = lib.systems.elaborate;
256 defaultText = lib.literalExpression ''(import "''${nixos}/../lib").lib.systems.examples.aarch64-multiplatform'';
257 description = ''
258 Systems with a recently generated `hardware-configuration.nix`
259 do not need to specify this option, unless cross-compiling, in which case
260 you should set *only* {option}`nixpkgs.buildPlatform`.
261
262 If this is somehow not feasible, you may fall back to removing the
263 {option}`nixpkgs.hostPlatform` line from the generated config and
264 use the old options.
265
266 Specifies the platform on which NixOS should be built. When
267 `nixpkgs.crossSystem` is unset, it also specifies
268 the platform *for* which NixOS should be
269 built. If this option is unset, it defaults to the platform
270 type of the machine where evaluation happens. Specifying this
271 option is useful when doing distributed multi-platform
272 deployment, or when building virtual machines. See its
273 description in the Nixpkgs manual for more details.
274
275 Ignored when `nixpkgs.pkgs` or `hostPlatform` is set.
276 '';
277 };
278
279 # TODO deprecate. "crossSystem" is a nonsense identifier, because "cross"
280 # is a relation between at least 2 systems in the context of a
281 # specific build step, not a single system.
282 crossSystem = lib.mkOption {
283 type = lib.types.nullOr lib.types.attrs; # TODO utilize lib.systems.parsedPlatform
284 default = null;
285 example = {
286 system = "aarch64-linux";
287 };
288 description = ''
289 Systems with a recently generated `hardware-configuration.nix`
290 may instead specify *only* {option}`nixpkgs.buildPlatform`,
291 or fall back to removing the {option}`nixpkgs.hostPlatform` line from the generated config.
292
293 Specifies the platform for which NixOS should be
294 built. Specify this only if it is different from
295 `nixpkgs.localSystem`, the platform
296 *on* which NixOS should be built. In other
297 words, specify this to cross-compile NixOS. Otherwise it
298 should be set as null, the default. See its description in the
299 Nixpkgs manual for more details.
300
301 Ignored when `nixpkgs.pkgs` or `hostPlatform` is set.
302 '';
303 };
304
305 system = lib.mkOption {
306 type = lib.types.str;
307 example = "i686-linux";
308 default =
309 if opt.hostPlatform.isDefined then
310 throw ''
311 Neither ${opt.system} nor any other option in nixpkgs.* is meant
312 to be read by modules and configurations.
313 Use pkgs.stdenv.hostPlatform instead.
314 ''
315 else
316 throw ''
317 Neither ${opt.hostPlatform} nor the legacy option ${opt.system} has been set.
318 You can set ${opt.hostPlatform} in hardware-configuration.nix by re-running
319 a recent version of nixos-generate-config.
320 The option ${opt.system} is still fully supported for NixOS 22.05 interoperability,
321 but will be deprecated in the future, so we recommend to set ${opt.hostPlatform}.
322 '';
323 defaultText = lib.literalMD ''
324 Traditionally `builtins.currentSystem`, but unset when invoking NixOS through `lib.nixosSystem`.
325 '';
326 description = ''
327 This option does not need to be specified for NixOS configurations
328 with a recently generated `hardware-configuration.nix`.
329
330 Specifies the Nix platform type on which NixOS should be built.
331 It is better to specify `nixpkgs.localSystem` instead.
332 ```
333 {
334 nixpkgs.system = ..;
335 }
336 ```
337 is the same as
338 ```
339 {
340 nixpkgs.localSystem.system = ..;
341 }
342 ```
343 See `nixpkgs.localSystem` for more information.
344
345 Ignored when `nixpkgs.pkgs`, `nixpkgs.localSystem` or `nixpkgs.hostPlatform` is set.
346 '';
347 };
348 };
349
350 config = {
351 _module.args = {
352 pkgs =
353 # We explicitly set the default override priority, so that we do not need
354 # to evaluate finalPkgs in case an override is placed on `_module.args.pkgs`.
355 # After all, to determine a definition priority, we need to evaluate `._type`,
356 # which is somewhat costly for Nixpkgs. With an explicit priority, we only
357 # evaluate the wrapper to find out that the priority is lower, and then we
358 # don't need to evaluate `finalPkgs`.
359 lib.mkOverride lib.modules.defaultOverridePriority finalPkgs.__splicedPackages;
360 };
361
362 assertions =
363 let
364 # Whether `pkgs` was constructed by this module. This is false when any of
365 # nixpkgs.pkgs or _module.args.pkgs is set.
366 constructedByMe =
367 # We set it with default priority and it can not be merged, so if the
368 # pkgs module argument has that priority, it's from us.
369 (lib.modules.mergeAttrDefinitionsWithPrio options._module.args).pkgs.highestPrio
370 == lib.modules.defaultOverridePriority
371 # Although, if nixpkgs.pkgs is set, we did forward it, but we did not construct it.
372 && !opt.pkgs.isDefined;
373 in
374 [
375 (
376 let
377 nixosExpectedSystem =
378 if config.nixpkgs.crossSystem != null then
379 config.nixpkgs.crossSystem.system or (lib.systems.parse.doubleFromSystem (
380 lib.systems.parse.mkSystemFromString config.nixpkgs.crossSystem.config
381 ))
382 else
383 config.nixpkgs.localSystem.system or (lib.systems.parse.doubleFromSystem (
384 lib.systems.parse.mkSystemFromString config.nixpkgs.localSystem.config
385 ));
386 nixosOption =
387 if config.nixpkgs.crossSystem != null then "nixpkgs.crossSystem" else "nixpkgs.localSystem";
388 pkgsSystem = finalPkgs.stdenv.targetPlatform.system;
389 in
390 {
391 assertion = constructedByMe -> !hasPlatform -> nixosExpectedSystem == pkgsSystem;
392 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.";
393 }
394 )
395 {
396 assertion = constructedByMe -> hasPlatform -> legacyOptionsDefined == [ ];
397 message = ''
398 Your system configures nixpkgs with the platform parameter${lib.optionalString hasBuildPlatform "s"}:
399 ${hostPlatformLine}${buildPlatformLine}
400 However, it also defines the legacy options:
401 ${lib.concatMapStrings lib.showOptionWithDefLocs legacyOptionsDefined}
402 For a future proof system configuration, we recommend to remove
403 the legacy definitions.
404 '';
405 }
406 {
407 assertion = opt.pkgs.isDefined -> cfg.config == { };
408 message = ''
409 Your system configures nixpkgs with an externally created instance.
410 `nixpkgs.config` options should be passed when creating the instance instead.
411
412 Current value:
413 ${lib.generators.toPretty { multiline = true; } cfg.config}
414
415 Defined in:
416 ${lib.concatMapStringsSep "\n" (file: " - ${file}") opt.config.files}
417 '';
418 }
419 ];
420 };
421
422 # needs a full nixpkgs path to import nixpkgs
423 meta.buildDocsInSandbox = false;
424}