1 { config, lib, pkgs, ... }:
10 ${if config.boot.initrd.systemd.enable then ''
11 cp ${config.system.build.bootStage2} $out/prepare-root
12 substituteInPlace $out/prepare-root --subst-var-by systemConfig $out
13 # This must not be a symlink or the abs_path of the grub builder for the tests
14 # will resolve the symlink and we end up with a path that doesn't point to a
16 cp "$systemd/lib/systemd/systemd" $out/init
18 cp ${config.system.build.bootStage2} $out/init
19 substituteInPlace $out/init --subst-var-by systemConfig $out
22 ln -s ${config.system.build.etc}/etc $out/etc
24 ${lib.optionalString config.system.etc.overlay.enable ''
25 ln -s ${config.system.build.etcMetadataImage} $out/etc-metadata-image
26 ln -s ${config.system.build.etcBasedir} $out/etc-basedir
29 ln -s ${config.system.path} $out/sw
30 ln -s "$systemd" $out/systemd
32 echo -n "systemd ${toString config.systemd.package.interfaceVersion}" > $out/init-interface-version
33 echo -n "$nixosLabel" > $out/nixos-version
34 echo -n "${config.boot.kernelPackages.stdenv.hostPlatform.system}" > $out/system
36 ${config.system.systemBuilderCommands}
38 cp "$extraDependenciesPath" "$out/extra-dependencies"
40 ${optionalString (!config.boot.isContainer && config.boot.bootspec.enable) ''
41 ${config.boot.bootspec.writer}
42 ${optionalString config.boot.bootspec.enableValidation
43 ''${config.boot.bootspec.validator} "$out/${config.boot.bootspec.filename}"''}
46 ${config.system.extraSystemBuilderCmds}
49 # Putting it all together. This builds a store path containing
50 # symlinks to the various parts of the built configuration (the
51 # kernel, systemd units, init scripts, etc.) as well as a script
52 # `switch-to-configuration' that activates the configuration and
53 # makes it bootable. See `activatable-system.nix`.
54 baseSystem = pkgs.stdenvNoCC.mkDerivation ({
55 name = "nixos-system-${config.system.name}-${config.system.nixos.label}";
56 preferLocalBuild = true;
57 allowSubstitutes = false;
58 passAsFile = [ "extraDependencies" ];
59 buildCommand = systemBuilder;
61 systemd = config.systemd.package;
63 nixosLabel = config.system.nixos.label;
65 inherit (config.system) extraDependencies;
66 } // config.system.systemBuilderArgs);
68 # Handle assertions and warnings
70 failedAssertions = map (x: x.message) (filter (x: !x.assertion) config.assertions);
72 baseSystemAssertWarn = if failedAssertions != []
73 then throw "\nFailed assertions:\n${concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}"
74 else showWarnings config.warnings baseSystem;
76 # Replace runtime dependencies
77 system = let inherit (config.system.replaceDependencies) replacements cutoffPackages; in
78 if replacements == [] then
79 # Avoid IFD if possible, by sidestepping replaceDependencies if no replacements are specified.
82 (pkgs.replaceDependencies.override {
83 replaceDirectDependencies = pkgs.replaceDirectDependencies.override {
84 nix = config.nix.package;
87 drv = baseSystemAssertWarn;
88 inherit replacements cutoffPackages;
91 systemWithBuildDeps = system.overrideAttrs (o: {
92 systemBuildClosure = pkgs.closureInfo { rootPaths = [ system.drvPath ]; };
93 buildCommand = o.buildCommand + ''
94 ln -sn $systemBuildClosure $out/build-closure
103 (mkRemovedOptionModule [ "nesting" "clone" ] "Use `specialisation.«name» = { inheritParentConfig = true; configuration = { ... }; }` instead.")
104 (mkRemovedOptionModule [ "nesting" "children" ] "Use `specialisation.«name».configuration = { ... }` instead.")
105 (mkRenamedOptionModule [ "system" "forbiddenDependenciesRegex" ] [ "system" "forbiddenDependenciesRegexes" ])
106 (mkRenamedOptionModule [ "system" "replaceRuntimeDependencies" ] [ "system" "replaceDependencies" "replacements" ])
111 system.boot.loader.id = mkOption {
115 Id string of the used bootloader.
119 system.boot.loader.kernelFile = mkOption {
121 default = pkgs.stdenv.hostPlatform.linux-kernel.target;
122 defaultText = literalExpression "pkgs.stdenv.hostPlatform.linux-kernel.target";
125 Name of the kernel file to be passed to the bootloader.
129 system.boot.loader.initrdFile = mkOption {
134 Name of the initrd file to be passed to the bootloader.
139 toplevel = mkOption {
140 type = types.package;
143 This option contains the store path that typically represents a NixOS system.
145 You can read this path in a custom deployment tool for example.
151 system.copySystemConfiguration = mkOption {
155 If enabled, copies the NixOS configuration file
156 (usually {file}`/etc/nixos/configuration.nix`)
157 and symlinks it from the resulting system
158 (getting to {file}`/run/current-system/configuration.nix`).
159 Note that only this single file is copied, even if it imports others.
160 Warning: This feature cannot be used when the system is configured by a flake
164 system.systemBuilderCommands = mkOption {
169 This code will be added to the builder creating the system store path.
173 system.systemBuilderArgs = mkOption {
174 type = types.attrsOf types.unspecified;
178 `lib.mkDerivation` attributes that will be passed to the top level system builder.
182 system.forbiddenDependenciesRegexes = mkOption {
185 type = types.listOf types.str;
187 POSIX Extended Regular Expressions that match store paths that
188 should not appear in the system closure, with the exception of {option}`system.extraDependencies`, which is not checked.
192 system.extraSystemBuilderCmds = mkOption {
197 This code will be added to the builder creating the system store path.
201 system.extraDependencies = mkOption {
202 type = types.listOf types.pathInStore;
205 A list of paths that should be included in the system
206 closure but generally not visible to users.
208 This option has also been used for build-time checks, but the
209 `system.checks` option is more appropriate for that purpose as checks
210 should not leave a trace in the built system configuration.
214 system.checks = mkOption {
215 type = types.listOf types.package;
218 Packages that are added as dependencies of the system's build, usually
219 for the purpose of validating some part of the configuration.
221 Unlike `system.extraDependencies`, these store paths do not
222 become part of the built system configuration.
226 system.replaceDependencies = {
227 replacements = mkOption {
229 example = lib.literalExpression "[ ({ oldDependency = pkgs.openssl; newDependency = pkgs.callPackage /path/to/openssl { }; }) ]";
230 type = types.listOf (types.submodule (
233 (mkRenamedOptionModule [ "original" ] [ "oldDependency" ])
234 (mkRenamedOptionModule [ "replacement" ] [ "newDependency" ])
237 options.oldDependency = mkOption {
238 type = types.package;
239 description = "The original package to override.";
242 options.newDependency = mkOption {
243 type = types.package;
244 description = "The replacement package.";
248 apply = map ({ oldDependency, newDependency, ... }: {
249 inherit oldDependency newDependency;
252 List of packages to override without doing a full rebuild.
253 The original derivation and replacement derivation must have the same
254 name length, and ideally should have close-to-identical directory layout.
258 cutoffPackages = mkOption {
259 default = [ config.system.build.initialRamdisk ];
260 defaultText = literalExpression "[ config.system.build.initialRamdisk ]";
261 type = types.listOf types.package;
263 Packages to which no replacements should be applied.
264 The initrd is matched by default, because its structure renders the replacement process ineffective and prone to breakage.
269 system.name = mkOption {
272 if config.networking.hostName == ""
274 else config.networking.hostName;
275 defaultText = literalExpression ''
276 if config.networking.hostName == ""
278 else config.networking.hostName;
281 The name of the system used in the {option}`system.build.toplevel` derivation.
283 That derivation has the following name:
284 `"nixos-system-''${config.system.name}-''${config.system.nixos.label}"`
288 system.includeBuildDependencies = mkOption {
292 Whether to include the build closure of the whole system in
293 its runtime closure. This can be useful for making changes
294 fully offline, as it includes all sources, patches, and
295 intermediate outputs required to build all the derivations
296 that the system depends on.
298 Note that this includes _all_ the derivations, down from the
299 included applications to their sources, the compilers used to
300 build them, and even the bootstrap compiler used to compile
301 the compilers. This increases the size of the system and the
302 time needed to download its dependencies drastically: a
303 minimal configuration with no extra services enabled grows
304 from ~670MiB in size to 13.5GiB, and takes proportionally
315 assertion = config.system.copySystemConfiguration -> !lib.inPureEvalMode;
316 message = "system.copySystemConfiguration is not supported with flakes";
320 system.extraSystemBuilderCmds =
322 config.system.copySystemConfiguration ''
323 ln -s '${import ../../../lib/from-env.nix "NIXOS_CONFIG" <nixos-config>}' \
324 "$out/configuration.nix"
327 (config.system.forbiddenDependenciesRegexes != []) (lib.concatStringsSep "\n" (map (regex: ''
328 if [[ ${regex} != "" && -n $closureInfo ]]; then
329 if forbiddenPaths="$(grep -E -- "${regex}" $closureInfo/store-paths)"; then
330 echo -e "System closure $out contains the following disallowed paths:\n$forbiddenPaths"
334 '') config.system.forbiddenDependenciesRegexes));
336 system.systemBuilderArgs = {
338 # Legacy environment variables. These were used by the activation script,
339 # but some other script might still depend on them, although unlikely.
340 installBootLoader = config.system.build.installBootLoader;
341 localeArchive = "${config.i18n.glibcLocales}/lib/locale/locale-archive";
342 distroId = config.system.nixos.distroId;
343 perl = pkgs.perl.withPackages (p: with p; [ ConfigIniFiles FileSlurp ]);
344 # End if legacy environment variables
346 preSwitchCheck = config.system.preSwitchChecks.script;
348 # Not actually used in the builder. `passedChecks` is just here to create
349 # the build dependencies. Checks are similar to build dependencies in the
350 # sense that if they fail, the system build fails. However, checks do not
351 # produce any output of value, so they are not used by the system builder.
352 # In fact, using them runs the risk of accidentally adding unneeded paths
353 # to the system closure, which defeats the purpose of the `system.checks`
354 # option, as opposed to `system.extraDependencies`.
355 passedChecks = concatStringsSep " " config.system.checks;
357 // lib.optionalAttrs (config.system.forbiddenDependenciesRegexes != []) {
358 closureInfo = pkgs.closureInfo { rootPaths = [
359 # override to avoid infinite recursion (and to allow using extraDependencies to add forbidden dependencies)
360 (config.system.build.toplevel.overrideAttrs (_: { extraDependencies = []; closureInfo = null; }))
365 system.build.toplevel = if config.system.includeBuildDependencies then systemWithBuildDeps else system;