144 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
		
		
			
		
	
	
			144 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.kdm.enable = true;
							 | 
						|||
| 
								 | 
							
								  services.xserver.desktopManager.kde4.enable = true;
							 | 
						|||
| 
								 | 
							
								  environment.systemPackages = [ pkgs.kde4.kscreensaver ];
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								</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 '<nixos>'
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								nix-repl> config.networking.hostName
							 | 
						|||
| 
								 | 
							
								"mandark"
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								nix-repl> map (x: x.hostName) config.services.httpd.virtualHosts
							 | 
						|||
| 
								 | 
							
								[ "example.org" "example.gov" ]
							 | 
						|||
| 
								 | 
							
								</screen>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								</para>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								</section>
							 |