2024-04-28 17:34:57 +02:00
{ config , options , lib , pkgs , . . . }:
with lib ;
let
cfg = config . nixpkgs ;
opt = options . nixpkgs ;
isConfig = x :
builtins . isAttrs x || lib . isFunction x ;
optCall = f : x :
if lib . isFunction f
then f x
else f ;
mergeConfig = lhs_ : rhs_ :
let
lhs = optCall lhs_ { inherit pkgs ; } ;
rhs = optCall rhs_ { inherit pkgs ; } ;
in
recursiveUpdate lhs rhs //
optionalAttrs ( lhs ? packageOverrides ) {
packageOverrides = pkgs :
optCall lhs . packageOverrides pkgs //
optCall ( attrByPath [ " p a c k a g e O v e r r i d e s " ] { } rhs ) pkgs ;
} //
optionalAttrs ( lhs ? perlPackageOverrides ) {
perlPackageOverrides = pkgs :
optCall lhs . perlPackageOverrides pkgs //
optCall ( attrByPath [ " p e r l P a c k a g e O v e r r i d e s " ] { } rhs ) pkgs ;
} ;
configType = mkOptionType {
name = " n i x p k g s - c o n f i g " ;
description = " n i x p k g s c o n f i g " ;
check = x :
let traceXIfNot = c :
if c x then true
else lib . traceSeqN 1 x false ;
in traceXIfNot isConfig ;
merge = args : foldr ( def : mergeConfig def . value ) { } ;
} ;
overlayType = mkOptionType {
name = " n i x p k g s - o v e r l a y " ;
description = " n i x p k g s o v e r l a y " ;
check = lib . isFunction ;
merge = lib . mergeOneOption ;
} ;
pkgsType = types . pkgs // {
# This type is only used by itself, so let's elaborate the description a bit
# for the purpose of documentation.
description = " A n e v a l u a t i o n o f N i x p k g s ; t h e t o p l e v e l a t t r i b u t e s e t o f p a c k a g e s " ;
} ;
hasBuildPlatform = opt . buildPlatform . highestPrio < ( mkOptionDefault { } ) . priority ;
hasHostPlatform = opt . hostPlatform . isDefined ;
hasPlatform = hasHostPlatform || hasBuildPlatform ;
# Context for messages
hostPlatformLine = optionalString hasHostPlatform " ${ showOptionWithDefLocs opt . hostPlatform } " ;
buildPlatformLine = optionalString hasBuildPlatform " ${ showOptionWithDefLocs opt . buildPlatform } " ;
legacyOptionsDefined =
optional ( opt . localSystem . highestPrio < ( mkDefault { } ) . priority ) opt . system
++ optional ( opt . localSystem . highestPrio < ( mkOptionDefault { } ) . priority ) opt . localSystem
++ optional ( opt . crossSystem . highestPrio < ( mkOptionDefault { } ) . priority ) opt . crossSystem
;
defaultPkgs =
if opt . hostPlatform . isDefined
then
let isCross = cfg . buildPlatform != cfg . hostPlatform ;
systemArgs =
if isCross
then {
localSystem = cfg . buildPlatform ;
crossSystem = cfg . hostPlatform ;
}
else {
localSystem = cfg . hostPlatform ;
} ;
in
2024-09-07 23:05:03 +02:00
import cfg . source ( {
2024-04-28 17:34:57 +02:00
inherit ( cfg ) config overlays ;
} // systemArgs )
else
2024-09-07 23:05:03 +02:00
import cfg . source {
2024-04-28 17:34:57 +02:00
inherit ( cfg ) config overlays localSystem crossSystem ;
} ;
finalPkgs = if opt . pkgs . isDefined then cfg . pkgs . appendOverlays cfg . overlays else defaultPkgs ;
in
{
options . nixpkgs = {
2024-09-07 23:05:03 +02:00
source = mkOption {
type = types . package // {
description = " S o u r c e o f a n i x p k g s r e p o s i t o r y " ;
} ;
default = <nixpkgs> ;
defaultText = " < n i x p k g s > " ;
} ;
2024-04-28 17:34:57 +02:00
pkgs = mkOption {
defaultText = literalExpression ''
import " ' ' ${ nixos } / . . " {
inherit ( cfg ) config overlays localSystem crossSystem ;
}
'' ;
type = pkgsType ;
example = literalExpression " i m p o r t < n i x p k g s > { } " ;
description = ''
If set , the pkgs argument to all NixOS modules is the value of
this option , extended with ` nixpkgs . overlays ` , if
that is also set . Either ` nixpkgs . crossSystem ` or
` nixpkgs . localSystem ` will be used in an assertion
to check that the NixOS and Nixpkgs architectures match . Any
other options in ` nixpkgs . * ` , notably ` config ` ,
will be ignored .
If unset , the pkgs argument to all NixOS modules is determined
as shown in the default value for this option .
The default value imports the Nixpkgs source files
relative to the location of this NixOS module , because
NixOS and Nixpkgs are distributed together for consistency ,
so the ` nixos ` in the default value is in fact a
relative path . The ` config ` , ` overlays ` ,
` localSystem ` , and ` crossSystem ` come
from this option's siblings .
This option can be used by applications like NixOps to increase
the performance of evaluation , or to create packages that depend
on a container that should be built with the exact same evaluation
of Nixpkgs , for example . Applications like this should set
their default value using ` lib . mkDefault ` , so
user-provided configuration can override it without using
` lib ` .
Note that using a distinct version of Nixpkgs with NixOS may
be an unexpected source of problems . Use this option with care .
'' ;
} ;
config = mkOption {
default = { } ;
example = literalExpression
''
{ allowBroken = true ; allowUnfree = true ; }
'' ;
type = configType ;
description = ''
Global configuration for Nixpkgs .
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).
Ignored when { option } ` nixpkgs . pkgs ` is set .
'' ;
} ;
overlays = mkOption {
default = [ ] ;
example = literalExpression
''
[
( self : super : {
openssh = super . openssh . override {
hpnSupport = true ;
kerberos = self . libkrb5 ;
} ;
} )
]
'' ;
type = types . listOf overlayType ;
description = ''
List of overlays to apply to Nixpkgs .
This option allows modifying the Nixpkgs package set accessed through the ` pkgs ` module argument .
For details , see the [ Overlays chapter in the Nixpkgs manual ] ( https://nixos.org/manual/nixpkgs/stable/ #chap-overlays).
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 ` .
'' ;
} ;
hostPlatform = mkOption {
type = types . either types . str types . attrs ; # TODO utilize lib.systems.parsedPlatform
example = { system = " a a r c h 6 4 - l i n u x " ; } ;
# Make sure that the final value has all fields for sake of other modules
# referring to this. TODO make `lib.systems` itself use the module system.
apply = lib . systems . elaborate ;
defaultText = literalExpression
'' ( i m p o r t " ''$ { n i x o s } / . . / l i b " ) . l i b . s y s t e m s . e x a m p l e s . a a r c h 6 4 - m u l t i p l a t f o r m '' ;
description = ''
Specifies the platform where the NixOS configuration will run .
To cross-compile , set also ` nixpkgs . buildPlatform ` .
Ignored when ` nixpkgs . pkgs ` is set .
'' ;
} ;
buildPlatform = mkOption {
type = types . either types . str types . attrs ; # TODO utilize lib.systems.parsedPlatform
default = cfg . hostPlatform ;
example = { system = " x 8 6 _ 6 4 - l i n u x " ; } ;
# Make sure that the final value has all fields for sake of other modules
# referring to this.
apply = inputBuildPlatform :
let elaborated = lib . systems . elaborate inputBuildPlatform ;
in if lib . systems . equals elaborated cfg . hostPlatform
then cfg . hostPlatform # make identical, so that `==` equality works; see https://github.com/NixOS/nixpkgs/issues/278001
else elaborated ;
defaultText = literalExpression
'' c o n f i g . n i x p k g s . h o s t P l a t f o r m '' ;
description = ''
Specifies the platform on which NixOS should be built .
By default , NixOS is built on the system where it runs , but you can
change where it's built . Setting this option will cause NixOS to be
cross-compiled .
For instance , if you're doing distributed multi-platform deployment ,
or if you're building machines , you can set this to match your
development system and/or build farm .
Ignored when ` nixpkgs . pkgs ` is set .
'' ;
} ;
localSystem = mkOption {
type = types . attrs ; # TODO utilize lib.systems.parsedPlatform
default = { inherit ( cfg ) system ; } ;
example = { system = " a a r c h 6 4 - l i n u x " ; } ;
# Make sure that the final value has all fields for sake of other modules
# referring to this. TODO make `lib.systems` itself use the module system.
apply = lib . systems . elaborate ;
defaultText = literalExpression
'' ( i m p o r t " ''$ { n i x o s } / . . / l i b " ) . l i b . s y s t e m s . e x a m p l e s . a a r c h 6 4 - m u l t i p l a t f o r m '' ;
description = ''
Systems with a recently generated ` hardware-configuration . nix `
do not need to specify this option , unless cross-compiling , in which case
you should set * only * { option } ` nixpkgs . buildPlatform ` .
If this is somehow not feasible , you may fall back to removing the
{ option } ` nixpkgs . hostPlatform ` line from the generated config and
use the old options .
Specifies the platform on which NixOS should be built . When
` nixpkgs . crossSystem ` is unset , it also specifies
the platform * for * which NixOS should be
built . If this option is unset , it defaults to the platform
type of the machine where evaluation happens . Specifying this
option is useful when doing distributed multi-platform
deployment , or when building virtual machines . See its
description in the Nixpkgs manual for more details .
Ignored when ` nixpkgs . pkgs ` or ` hostPlatform ` is set .
'' ;
} ;
# TODO deprecate. "crossSystem" is a nonsense identifier, because "cross"
# is a relation between at least 2 systems in the context of a
# specific build step, not a single system.
crossSystem = mkOption {
type = types . nullOr types . attrs ; # TODO utilize lib.systems.parsedPlatform
default = null ;
example = { system = " a a r c h 6 4 - l i n u x " ; } ;
description = ''
Systems with a recently generated ` hardware-configuration . nix `
may instead specify * only * { option } ` nixpkgs . buildPlatform ` ,
or fall back to removing the { option } ` nixpkgs . hostPlatform ` line from the generated config .
Specifies the platform for which NixOS should be
built . Specify this only if it is different from
` nixpkgs . localSystem ` , the platform
* on * which NixOS should be built . In other
words , specify this to cross-compile NixOS . Otherwise it
should be set as null , the default . See its description in the
Nixpkgs manual for more details .
Ignored when ` nixpkgs . pkgs ` or ` hostPlatform ` is set .
'' ;
} ;
system = mkOption {
type = types . str ;
example = " i 6 8 6 - l i n u x " ;
default =
if opt . hostPlatform . isDefined
then
throw ''
Neither $ { opt . system } nor any other option in nixpkgs . * is meant
to be read by modules and configurations .
Use pkgs . stdenv . hostPlatform instead .
''
else
throw ''
Neither $ { opt . hostPlatform } nor the legacy option $ { opt . system } has been set .
You can set $ { opt . hostPlatform } in hardware-configuration . nix by re-running
a recent version of nixos-generate-config .
The option $ { opt . system } is still fully supported for NixOS 22 .05 interoperability ,
but will be deprecated in the future , so we recommend to set $ { opt . hostPlatform } .
'' ;
defaultText = lib . literalMD ''
Traditionally ` builtins . currentSystem ` , but unset when invoking NixOS through ` lib . nixosSystem ` .
'' ;
description = ''
This option does not need to be specified for NixOS configurations
with a recently generated ` hardware-configuration . nix ` .
Specifies the Nix platform type on which NixOS should be built .
It is better to specify ` nixpkgs . localSystem ` instead .
` ` `
{
nixpkgs . system = . . ;
}
` ` `
is the same as
` ` `
{
nixpkgs . localSystem . system = . . ;
}
` ` `
See ` nixpkgs . localSystem ` for more information .
Ignored when ` nixpkgs . pkgs ` , ` nixpkgs . localSystem ` or ` nixpkgs . hostPlatform ` is set .
'' ;
} ;
} ;
config = {
_module . args = {
pkgs =
# We explicitly set the default override priority, so that we do not need
# to evaluate finalPkgs in case an override is placed on `_module.args.pkgs`.
# After all, to determine a definition priority, we need to evaluate `._type`,
# which is somewhat costly for Nixpkgs. With an explicit priority, we only
# evaluate the wrapper to find out that the priority is lower, and then we
# don't need to evaluate `finalPkgs`.
lib . mkOverride lib . modules . defaultOverridePriority
finalPkgs . __splicedPackages ;
lim = lib . mkOverride lib . modules . defaultOverridePriority
finalPkgs . __splicedPackages . lim ;
} ;
assertions = let
# Whether `pkgs` was constructed by this module. This is false when any of
# nixpkgs.pkgs or _module.args.pkgs is set.
constructedByMe =
# We set it with default priority and it can not be merged, so if the
# pkgs module argument has that priority, it's from us.
( lib . modules . mergeAttrDefinitionsWithPrio options . _module . args ) . pkgs . highestPrio
== lib . modules . defaultOverridePriority
# Although, if nixpkgs.pkgs is set, we did forward it, but we did not construct it.
&& ! opt . pkgs . isDefined ;
in [
(
let
nixosExpectedSystem =
if config . nixpkgs . crossSystem != null
then config . nixpkgs . crossSystem . system or ( lib . systems . parse . doubleFromSystem ( lib . systems . parse . mkSystemFromString config . nixpkgs . crossSystem . config ) )
else config . nixpkgs . localSystem . system or ( lib . systems . parse . doubleFromSystem ( lib . systems . parse . mkSystemFromString config . nixpkgs . localSystem . config ) ) ;
nixosOption =
if config . nixpkgs . crossSystem != null
then " n i x p k g s . c r o s s S y s t e m "
else " n i x p k g s . l o c a l S y s t e m " ;
pkgsSystem = finalPkgs . stdenv . targetPlatform . system ;
in {
assertion = constructedByMe -> ! hasPlatform -> nixosExpectedSystem == pkgsSystem ;
message = " T h e N i x O S n i x p k g s . p k g s o p t i o n w a s s e t t o a N i x p k g s i n v o c a t i o n t h a t c o m p i l e s t o t a r g e t s y s t e m ${ pkgsSystem } b u t N i x O S w a s c o n f i g u r e d f o r s y s t e m ${ nixosExpectedSystem } v i a N i x O S o p t i o n ${ nixosOption } . T h e N i x O S s y s t e m s e t t i n g s m u s t m a t c h t h e N i x p k g s t a r g e t s y s t e m . " ;
}
)
{
assertion = constructedByMe -> hasPlatform -> legacyOptionsDefined == [ ] ;
message = ''
Your system configures nixpkgs with the platform parameter $ { optionalString hasBuildPlatform " s " }:
$ { hostPlatformLine
} $ { buildPlatformLine
}
However , it also defines the legacy options :
$ { concatMapStrings showOptionWithDefLocs legacyOptionsDefined }
For a future proof system configuration , we recommend to remove
the legacy definitions .
'' ;
}
{
assertion = opt . pkgs . isDefined -> cfg . config == { } ;
message = ''
Your system configures nixpkgs with an externally created instance .
` nixpkgs . config ` options should be passed when creating the instance instead .
Current value :
$ { lib . generators . toPretty { multiline = true ; } opt . config }
'' ;
}
] ;
} ;
}