200 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
			
		
		
	
	
			200 lines
		
	
	
		
			6.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-option-declarations">
 | ||
|  <title>Option Declarations</title>
 | ||
| 
 | ||
|  <para>
 | ||
|   An option declaration specifies the name, type and description of a NixOS
 | ||
|   configuration option. It is invalid to define an option that hasn’t been
 | ||
|   declared in any module. An option declaration generally looks like this:
 | ||
| <programlisting>
 | ||
| options = {
 | ||
|   <replaceable>name</replaceable> = mkOption {
 | ||
|     type = <replaceable>type specification</replaceable>;
 | ||
|     default = <replaceable>default value</replaceable>;
 | ||
|     example = <replaceable>example value</replaceable>;
 | ||
|     description = "<replaceable>Description for use in the NixOS manual.</replaceable>";
 | ||
|   };
 | ||
| };
 | ||
| </programlisting>
 | ||
|   The attribute names within the <replaceable>name</replaceable> attribute path
 | ||
|   must be camel cased in general but should, as an exception, match the
 | ||
|   <link
 | ||
| xlink:href="https://nixos.org/nixpkgs/manual/#sec-package-naming">
 | ||
|   package attribute name</link> when referencing a Nixpkgs package. For
 | ||
|   example, the option <varname>services.nix-serve.bindAddress</varname>
 | ||
|   references the <varname>nix-serve</varname> Nixpkgs package.
 | ||
|  </para>
 | ||
| 
 | ||
|  <para>
 | ||
|   The function <varname>mkOption</varname> accepts the following arguments.
 | ||
|   <variablelist>
 | ||
|    <varlistentry>
 | ||
|     <term>
 | ||
|      <varname>type</varname>
 | ||
|     </term>
 | ||
|     <listitem>
 | ||
|      <para>
 | ||
|       The type of the option (see <xref linkend='sec-option-types' />). It may
 | ||
|       be omitted, but that’s not advisable since it may lead to errors that
 | ||
|       are hard to diagnose.
 | ||
|      </para>
 | ||
|     </listitem>
 | ||
|    </varlistentry>
 | ||
|    <varlistentry>
 | ||
|     <term>
 | ||
|      <varname>default</varname>
 | ||
|     </term>
 | ||
|     <listitem>
 | ||
|      <para>
 | ||
|       The default value used if no value is defined by any module. A default is
 | ||
|       not required; but if a default is not given, then users of the module
 | ||
|       will have to define the value of the option, otherwise an error will be
 | ||
|       thrown.
 | ||
|      </para>
 | ||
|     </listitem>
 | ||
|    </varlistentry>
 | ||
|    <varlistentry>
 | ||
|     <term>
 | ||
|      <varname>example</varname>
 | ||
|     </term>
 | ||
|     <listitem>
 | ||
|      <para>
 | ||
|       An example value that will be shown in the NixOS manual.
 | ||
|      </para>
 | ||
|     </listitem>
 | ||
|    </varlistentry>
 | ||
|    <varlistentry>
 | ||
|     <term>
 | ||
|      <varname>description</varname>
 | ||
|     </term>
 | ||
|     <listitem>
 | ||
|      <para>
 | ||
|       A textual description of the option, in DocBook format, that will be
 | ||
|       included in the NixOS manual.
 | ||
|      </para>
 | ||
|     </listitem>
 | ||
|    </varlistentry>
 | ||
|   </variablelist>
 | ||
|  </para>
 | ||
| 
 | ||
|  <section xml:id="sec-option-declarations-eot">
 | ||
|   <title>Extensible Option Types</title>
 | ||
| 
 | ||
|   <para>
 | ||
|    Extensible option types is a feature that allow to extend certain types
 | ||
|    declaration through multiple module files. This feature only work with a
 | ||
|    restricted set of types, namely <literal>enum</literal> and
 | ||
|    <literal>submodules</literal> and any composed forms of them.
 | ||
|   </para>
 | ||
| 
 | ||
|   <para>
 | ||
|    Extensible option types can be used for <literal>enum</literal> options that
 | ||
|    affects multiple modules, or as an alternative to related
 | ||
|    <literal>enable</literal> options.
 | ||
|   </para>
 | ||
| 
 | ||
|   <para>
 | ||
|    As an example, we will take the case of display managers. There is a central
 | ||
|    display manager module for generic display manager options and a module file
 | ||
|    per display manager backend (slim, sddm, gdm ...).
 | ||
|   </para>
 | ||
| 
 | ||
|   <para>
 | ||
|    There are two approach to this module structure:
 | ||
|    <itemizedlist>
 | ||
|     <listitem>
 | ||
|      <para>
 | ||
|       Managing the display managers independently by adding an enable option to
 | ||
|       every display manager module backend. (NixOS)
 | ||
|      </para>
 | ||
|     </listitem>
 | ||
|     <listitem>
 | ||
|      <para>
 | ||
|       Managing the display managers in the central module by adding an option
 | ||
|       to select which display manager backend to use.
 | ||
|      </para>
 | ||
|     </listitem>
 | ||
|    </itemizedlist>
 | ||
|   </para>
 | ||
| 
 | ||
|   <para>
 | ||
|    Both approaches have problems.
 | ||
|   </para>
 | ||
| 
 | ||
|   <para>
 | ||
|    Making backends independent can quickly become hard to manage. For display
 | ||
|    managers, there can be only one enabled at a time, but the type system can
 | ||
|    not enforce this restriction as there is no relation between each backend
 | ||
|    <literal>enable</literal> option. As a result, this restriction has to be
 | ||
|    done explicitely by adding assertions in each display manager backend
 | ||
|    module.
 | ||
|   </para>
 | ||
| 
 | ||
|   <para>
 | ||
|    On the other hand, managing the display managers backends in the central
 | ||
|    module will require to change the central module option every time a new
 | ||
|    backend is added or removed.
 | ||
|   </para>
 | ||
| 
 | ||
|   <para>
 | ||
|    By using extensible option types, it is possible to create a placeholder
 | ||
|    option in the central module
 | ||
|    (<xref linkend='ex-option-declaration-eot-service'
 | ||
|       />), and to extend
 | ||
|    it in each backend module
 | ||
|    (<xref
 | ||
|       linkend='ex-option-declaration-eot-backend-slim' />,
 | ||
|    <xref
 | ||
|       linkend='ex-option-declaration-eot-backend-sddm' />).
 | ||
|   </para>
 | ||
| 
 | ||
|   <para>
 | ||
|    As a result, <literal>displayManager.enable</literal> option values can be
 | ||
|    added without changing the main service module file and the type system
 | ||
|    automatically enforce that there can only be a single display manager
 | ||
|    enabled.
 | ||
|   </para>
 | ||
| 
 | ||
|   <example xml:id='ex-option-declaration-eot-service'>
 | ||
|    <title>Extensible type placeholder in the service module</title>
 | ||
| <screen>
 | ||
| services.xserver.displayManager.enable = mkOption {
 | ||
|   description = "Display manager to use";
 | ||
|   type = with types; nullOr (enum [ ]);
 | ||
| };</screen>
 | ||
|   </example>
 | ||
| 
 | ||
|   <example xml:id='ex-option-declaration-eot-backend-slim'>
 | ||
|    <title>Extending <literal>services.xserver.displayManager.enable</literal> in the <literal>slim</literal> module</title>
 | ||
| <screen>
 | ||
| services.xserver.displayManager.enable = mkOption {
 | ||
|   type = with types; nullOr (enum [ "slim" ]);
 | ||
| };</screen>
 | ||
|   </example>
 | ||
| 
 | ||
|   <example xml:id='ex-option-declaration-eot-backend-sddm'>
 | ||
|    <title>Extending <literal>services.xserver.displayManager.enable</literal> in the <literal>sddm</literal> module</title>
 | ||
| <screen>
 | ||
| services.xserver.displayManager.enable = mkOption {
 | ||
|   type = with types; nullOr (enum [ "sddm" ]);
 | ||
| };</screen>
 | ||
|   </example>
 | ||
| 
 | ||
|   <para>
 | ||
|    The placeholder declaration is a standard <literal>mkOption</literal>
 | ||
|    declaration, but it is important that extensible option declarations only
 | ||
|    use the <literal>type</literal> argument.
 | ||
|   </para>
 | ||
| 
 | ||
|   <para>
 | ||
|    Extensible option types work with any of the composed variants of
 | ||
|    <literal>enum</literal> such as <literal>with types; nullOr (enum [ "foo"
 | ||
|    "bar" ])</literal> or <literal>with types; listOf (enum [ "foo" "bar"
 | ||
|    ])</literal>.
 | ||
|   </para>
 | ||
|  </section>
 | ||
| </section>
 | 
