NixOS:config argument: Difference between revisions

From NixOS Wiki
imported>Makefu
No edit summary
Raf (talk | contribs)
m changed instances of pkgs.lib to more commonly available lib
 
(4 intermediate revisions by 3 users not shown)
Line 5: Line 5:
The following code is used to support the explanation.
The following code is used to support the explanation.


<pre>
<syntaxhighlight lang="nix">
{config, pkgs, ...}:
{config, pkgs, lib ...}:


{
{
   options = {
   options = {
     foo = pkgs.lib.mkOption {
     foo = lib.mkOption {
       description = "...";
       description = "...";
     };
     };
Line 19: Line 19:
   };
   };
}
}
</pre>
</syntaxhighlight>


This snippet of code is a module which declare the option "<code>foo</code>" and define the option "<code>bar</code>".  The option "<code>bar</code>" is defined with the value <code>config.foo</code>.  This attribute <code>foo</code> of the <code>config</code> argument, is the result of the [[NixOS:Declaration#Evaluation|evaluation]] of the definitions and the declarations of the option "<code>foo</code>".  Definitions of the option "<code>foo</code>" may exists in other module used by the system.
This snippet of code is a module which declare the option "<code>foo</code>" and define the option "<code>bar</code>".  The option "<code>bar</code>" is defined with the value <code>config.foo</code>.  This attribute <code>foo</code> of the <code>config</code> argument, is the result of the [[NixOS:Declaration#Evaluation|evaluation]] of the definitions and the declarations of the option "<code>foo</code>".  Definitions of the option "<code>foo</code>" may exists in other module used by the system.
Line 29: Line 29:
The process of module computation is highly recursive and may cause trouble when you want to add control flow statements.  A common mistake is to use "<code>if</code>" or "<code>assert</code>" statements in the computation of a module.
The process of module computation is highly recursive and may cause trouble when you want to add control flow statements.  A common mistake is to use "<code>if</code>" or "<code>assert</code>" statements in the computation of a module.


<pre>
<syntaxhighlight lang="nix">
{config, pkgs, ...}:
{config, pkgs, lib, ...}:


{
{
   options = {
   options = {
     foo = pkgs.lib.mkOption {
     foo = lib.mkOption {
       default = false;
       default = false;
       type = with pkgs.lib.types; bool;
       type = with lib.types; bool;
       description = "enable foo";
       description = "foo boolean option";
     };
     };
   };
   };
Line 47: Line 47:
       {};
       {};
}
}
</pre>
</syntaxhighlight>


The previous module cause an infinite recursion:
The previous module cause an infinite recursion:
Line 58: Line 58:
To avoid such infinite recursion, [[NixOS:Properties|properties]] have been introduced, thus the previous code should be rewritten in:
To avoid such infinite recursion, [[NixOS:Properties|properties]] have been introduced, thus the previous code should be rewritten in:


<pre>
<syntaxhighlight lang="nix">
{config, pkgs, ...}:
{config, pkgs, lib, ...}:


{
{
   options = {
   options = {
     foo = pkgs.lib.mkOption {
     foo = lib.mkOption {
       default = false;
       default = false;
       type = with pkgs.lib.types; bool;
       type = with lib.types; bool;
       description = "enable foo";
       description = "foo boolean";
     };
     };
   };
   };


   config = pkgs.lib.mkIf config.foo {
   config = lib.mkIf config.foo {
     bar = 42;
     bar = 42;
   };
   };
}
}
</pre>
</syntaxhighlight>


== Common Pattern ==
== Common Pattern ==
Line 80: Line 80:
Often, the module declare options embedded inside an attribute set.  To access these options, we add an attribute <code>cfg</code> as a shortcut notation.
Often, the module declare options embedded inside an attribute set.  To access these options, we add an attribute <code>cfg</code> as a shortcut notation.


<pre>
<syntaxhighlight lang="nix">
{config, pkgs, ...}:
{config, pkgs, lib, ...}:


let
let
Line 89: Line 89:
in
in


with pkgs.lib; {
with lib; {
   options = {
   options = {
     foo.bar.baz = {
     foo.bar.baz = {
Line 103: Line 103:
   };
   };
}
}
</pre>
</syntaxhighlight>


[[Category:Discussion]]
[[Category:Reference]]
[[Category:Pages_with_syntax_highlighting_errors]]
[[Category:NixOS]]

Latest revision as of 03:20, 4 April 2024

This argument gives access to the entire configuration of the system. It is computed from option declarations and option definitions defined inside all modules used for the system.

Simple Case

The following code is used to support the explanation.

{config, pkgs, lib ...}:

{
  options = {
    foo = lib.mkOption {
      description = "...";
    };
  };

  config = {
    bar = config.foo;
  };
}

This snippet of code is a module which declare the option "foo" and define the option "bar". The option "bar" is defined with the value config.foo. This attribute foo of the config argument, is the result of the evaluation of the definitions and the declarations of the option "foo". Definitions of the option "foo" may exists in other module used by the system.

Adding additional modules to the system may change the value of config.foo and may change the behavior of the previous module.

Conditional Statements

The process of module computation is highly recursive and may cause trouble when you want to add control flow statements. A common mistake is to use "if" or "assert" statements in the computation of a module.

{config, pkgs, lib, ...}:

{
  options = {
    foo = lib.mkOption {
      default = false;
      type = with lib.types; bool;
      description = "foo boolean option";
    };
  };

  config =
    if config.foo then
      { bar = 42; }
    else
      {};
}

The previous module cause an infinite recursion:

  • The config attribute is evaluated. This evaluation needs the result of the if statement.
  • The if statement is evaluated. This evaluation needs the result of the condition.
  • The condition (config.foo) is evaluated. This evaluation needs the result of the config argument.
  • The config argument is evaluated. This evaluation needs the result of merging of all modules.
  • The merge function of the modules is evaluated. This evaluation needs the evaluation of each module config attribute.

To avoid such infinite recursion, properties have been introduced, thus the previous code should be rewritten in:

{config, pkgs, lib, ...}:

{
  options = {
    foo = lib.mkOption {
      default = false;
      type = with lib.types; bool;
      description = "foo boolean";
    };
  };

  config = lib.mkIf config.foo {
    bar = 42;
  };
}

Common Pattern

Often, the module declare options embedded inside an attribute set. To access these options, we add an attribute cfg as a shortcut notation.

{config, pkgs, lib, ...}:

let
  cfg = config.foo.bar.baz;

  # ...
in

with lib; {
  options = {
    foo.bar.baz = {
      enable = mkOption { /* ... */ };
      option1 = mkOption { /* ... */ };
      option2 = mkOption { /* ... */ };
      option3 = mkOption { /* ... */ }; 
    };
  };

  config = mkIf cfg.enable {
    # ...
  };
}