2014-08-24 18:18:18 +01:00
|
|
|
|
<section xmlns="http://docbook.org/ns/docbook"
|
|
|
|
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
|
|
|
xmlns:xi="http://www.w3.org/2001/XInclude"
|
|
|
|
|
version="5.0"
|
|
|
|
|
xml:id="sec-modularity">
|
|
|
|
|
|
|
|
|
|
<title>Modularity</title>
|
|
|
|
|
|
|
|
|
|
<para>The NixOS configuration mechanism is modular. If your
|
|
|
|
|
<filename>configuration.nix</filename> becomes too big, you can split
|
|
|
|
|
it into multiple files. Likewise, if you have multiple NixOS
|
|
|
|
|
configurations (e.g. for different computers) with some commonality,
|
|
|
|
|
you can move the common configuration into a shared file.</para>
|
|
|
|
|
|
|
|
|
|
<para>Modules have exactly the same syntax as
|
|
|
|
|
<filename>configuration.nix</filename>. In fact,
|
|
|
|
|
<filename>configuration.nix</filename> is itself a module. You can
|
|
|
|
|
use other modules by including them from
|
|
|
|
|
<filename>configuration.nix</filename>, e.g.:
|
|
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
|
{ config, pkgs, ... }:
|
|
|
|
|
|
|
|
|
|
{ imports = [ ./vpn.nix ./kde.nix ];
|
|
|
|
|
services.httpd.enable = true;
|
|
|
|
|
environment.systemPackages = [ pkgs.emacs ];
|
|
|
|
|
<replaceable>...</replaceable>
|
|
|
|
|
}
|
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
|
|
Here, we include two modules from the same directory,
|
|
|
|
|
<filename>vpn.nix</filename> and <filename>kde.nix</filename>. The
|
|
|
|
|
latter might look like this:
|
|
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
|
{ config, pkgs, ... }:
|
|
|
|
|
|
|
|
|
|
{ services.xserver.enable = true;
|
2017-02-10 02:25:03 +00:00
|
|
|
|
services.xserver.displayManager.sddm.enable = true;
|
|
|
|
|
services.xserver.desktopManager.kde5.enable = true;
|
2014-08-24 18:18:18 +01:00
|
|
|
|
}
|
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
|
|
Note that both <filename>configuration.nix</filename> and
|
|
|
|
|
<filename>kde.nix</filename> define the option
|
|
|
|
|
<option>environment.systemPackages</option>. When multiple modules
|
|
|
|
|
define an option, NixOS will try to <emphasis>merge</emphasis> the
|
|
|
|
|
definitions. In the case of
|
|
|
|
|
<option>environment.systemPackages</option>, that’s easy: the lists of
|
|
|
|
|
packages can simply be concatenated. The value in
|
|
|
|
|
<filename>configuration.nix</filename> is merged last, so for
|
|
|
|
|
list-type options, it will appear at the end of the merged list. If
|
|
|
|
|
you want it to appear first, you can use <varname>mkBefore</varname>:
|
|
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
|
boot.kernelModules = mkBefore [ "kvm-intel" ];
|
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
|
|
This causes the <literal>kvm-intel</literal> kernel module to be
|
|
|
|
|
loaded before any other kernel modules.</para>
|
|
|
|
|
|
|
|
|
|
<para>For other types of options, a merge may not be possible. For
|
|
|
|
|
instance, if two modules define
|
|
|
|
|
<option>services.httpd.adminAddr</option>,
|
|
|
|
|
<command>nixos-rebuild</command> will give an error:
|
|
|
|
|
|
|
|
|
|
<screen>
|
|
|
|
|
The unique option `services.httpd.adminAddr' is defined multiple times, in `/etc/nixos/httpd.nix' and `/etc/nixos/configuration.nix'.
|
|
|
|
|
</screen>
|
|
|
|
|
|
|
|
|
|
When that happens, it’s possible to force one definition take
|
|
|
|
|
precedence over the others:
|
|
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
|
services.httpd.adminAddr = pkgs.lib.mkForce "bob@example.org";
|
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>When using multiple modules, you may need to access
|
|
|
|
|
configuration values defined in other modules. This is what the
|
|
|
|
|
<varname>config</varname> function argument is for: it contains the
|
|
|
|
|
complete, merged system configuration. That is,
|
|
|
|
|
<varname>config</varname> is the result of combining the
|
|
|
|
|
configurations returned by every module<footnote><para>If you’re
|
|
|
|
|
wondering how it’s possible that the (indirect)
|
|
|
|
|
<emphasis>result</emphasis> of a function is passed as an
|
|
|
|
|
<emphasis>input</emphasis> to that same function: that’s because Nix
|
|
|
|
|
is a “lazy” language — it only computes values when they are needed.
|
|
|
|
|
This works as long as no individual configuration value depends on
|
|
|
|
|
itself.</para></footnote>. For example, here is a module that adds
|
|
|
|
|
some packages to <option>environment.systemPackages</option> only if
|
|
|
|
|
<option>services.xserver.enable</option> is set to
|
|
|
|
|
<literal>true</literal> somewhere else:
|
|
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
|
{ config, pkgs, ... }:
|
|
|
|
|
|
|
|
|
|
{ environment.systemPackages =
|
|
|
|
|
if config.services.xserver.enable then
|
|
|
|
|
[ pkgs.firefox
|
|
|
|
|
pkgs.thunderbird
|
|
|
|
|
]
|
|
|
|
|
else
|
|
|
|
|
[ ];
|
|
|
|
|
}
|
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>With multiple modules, it may not be obvious what the final
|
|
|
|
|
value of a configuration option is. The command
|
|
|
|
|
<option>nixos-option</option> allows you to find out:
|
|
|
|
|
|
|
|
|
|
<screen>
|
|
|
|
|
$ nixos-option services.xserver.enable
|
|
|
|
|
true
|
|
|
|
|
|
|
|
|
|
$ nixos-option boot.kernelModules
|
|
|
|
|
[ "tun" "ipv6" "loop" <replaceable>...</replaceable> ]
|
|
|
|
|
</screen>
|
|
|
|
|
|
|
|
|
|
Interactive exploration of the configuration is possible using
|
|
|
|
|
<command
|
|
|
|
|
xlink:href="https://github.com/edolstra/nix-repl">nix-repl</command>,
|
|
|
|
|
a read-eval-print loop for Nix expressions. It’s not installed by
|
|
|
|
|
default; run <literal>nix-env -i nix-repl</literal> to get it. A
|
|
|
|
|
typical use:
|
|
|
|
|
|
|
|
|
|
<screen>
|
2016-12-11 18:51:18 +00:00
|
|
|
|
$ nix-repl '<nixpkgs/nixos>'
|
2014-08-24 18:18:18 +01:00
|
|
|
|
|
|
|
|
|
nix-repl> config.networking.hostName
|
|
|
|
|
"mandark"
|
|
|
|
|
|
|
|
|
|
nix-repl> map (x: x.hostName) config.services.httpd.virtualHosts
|
|
|
|
|
[ "example.org" "example.gov" ]
|
|
|
|
|
</screen>
|
|
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
</section>
|