143 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
			
		
		
	
	
			143 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
<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;
 | 
						||
  services.xserver.displayManager.sddm.enable = true;
 | 
						||
  services.xserver.desktopManager.plasma5.enable = true;
 | 
						||
}
 | 
						||
</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>
 | 
						||
$ nix-repl '<nixpkgs/nixos>'
 | 
						||
 | 
						||
nix-repl> config.networking.hostName
 | 
						||
"mandark"
 | 
						||
 | 
						||
nix-repl> map (x: x.hostName) config.services.httpd.virtualHosts
 | 
						||
[ "example.org" "example.gov" ]
 | 
						||
</screen>
 | 
						||
 | 
						||
</para>
 | 
						||
 | 
						||
</section>
 |