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.kde5.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>
 | 
