147 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			5.5 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 ];
 | ||
|   <xref linkend="opt-services.httpd.enable"/> = true;
 | ||
|   <xref linkend="opt-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, ... }:
 | ||
| 
 | ||
| { <xref linkend="opt-services.xserver.enable"/> = true;
 | ||
|   <xref linkend="opt-services.xserver.displayManager.sddm.enable"/> = true;
 | ||
|   <xref linkend="opt-services.xserver.desktopManager.plasma5.enable"/> = true;
 | ||
|   <xref linkend="opt-environment.systemPackages"/> = [ pkgs.vim ];
 | ||
| }
 | ||
| </programlisting>
 | ||
|   Note that both <filename>configuration.nix</filename> and
 | ||
|   <filename>kde.nix</filename> define the option
 | ||
|   <xref linkend="opt-environment.systemPackages"/>. When multiple modules
 | ||
|   define an option, NixOS will try to <emphasis>merge</emphasis> the
 | ||
|   definitions. In the case of <xref linkend="opt-environment.systemPackages"/>,
 | ||
|   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>
 | ||
| <xref linkend="opt-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 <xref linkend="opt-services.httpd.adminAddr"/>,
 | ||
|   <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>
 | ||
| <xref linkend="opt-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 xml:id="footnote-nix-is-lazy">
 | ||
|    <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
 | ||
|   <xref linkend="opt-environment.systemPackages"/> only if
 | ||
|   <xref linkend="opt-services.xserver.enable"/> is set to
 | ||
|   <literal>true</literal> somewhere else:
 | ||
| <programlisting>
 | ||
| { config, pkgs, ... }:
 | ||
| 
 | ||
| { <xref linkend="opt-environment.systemPackages"/> =
 | ||
|     if config.<xref linkend="opt-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>
 | ||
| <prompt>$ </prompt>nixos-option <xref linkend="opt-services.xserver.enable"/>
 | ||
| true
 | ||
| 
 | ||
| <prompt>$ </prompt>nixos-option <xref linkend="opt-boot.kernelModules"/>
 | ||
| [ "tun" "ipv6" "loop" <replaceable>...</replaceable> ]
 | ||
| </screen>
 | ||
|   Interactive exploration of the configuration is possible using <command>nix
 | ||
|   repl</command>, a read-eval-print loop for Nix expressions. A typical use:
 | ||
| <screen>
 | ||
| <prompt>$ </prompt>nix repl '<nixpkgs/nixos>'
 | ||
| 
 | ||
| <prompt>nix-repl> </prompt>config.<xref linkend="opt-networking.hostName"/>
 | ||
| "mandark"
 | ||
| 
 | ||
| <prompt>nix-repl> </prompt>map (x: x.hostName) config.<xref linkend="opt-services.httpd.virtualHosts"/>
 | ||
| [ "example.org" "example.gov" ]
 | ||
| </screen>
 | ||
|  </para>
 | ||
| 
 | ||
|  <para>
 | ||
|   While abstracting your configuration, you may find it useful to generate
 | ||
|   modules using code, instead of writing files. The example below would have
 | ||
|   the same effect as importing a file which sets those options.
 | ||
| <programlisting>
 | ||
| { config, pkgs, ... }:
 | ||
| 
 | ||
| let netConfig = hostName: {
 | ||
|   networking.hostName = hostName;
 | ||
|   networking.useDHCP = false;
 | ||
| };
 | ||
| 
 | ||
| in
 | ||
| 
 | ||
| { imports = [ (netConfig "nixos.localdomain") ]; }
 | ||
| </programlisting>
 | ||
|  </para>
 | ||
| </section>
 | 
