1{ lib, config, ... }:
2
3with lib;
4let
5 mergeFalseByDefault =
6 locs: defs:
7 if defs == [ ] then
8 abort "This case should never happen."
9 else if any (x: x == false) (getValues defs) then
10 false
11 else
12 true;
13
14 kernelItem = types.submodule {
15 options = {
16 tristate = mkOption {
17 type = types.enum [
18 "y"
19 "m"
20 "n"
21 null
22 ];
23 default = null;
24 internal = true;
25 visible = true;
26 description = ''
27 Use this field for tristate kernel options expecting a "y" or "m" or "n".
28 '';
29 };
30
31 freeform = mkOption {
32 type = types.nullOr types.str // {
33 merge = mergeEqualOption;
34 };
35 default = null;
36 example = ''MMC_BLOCK_MINORS.freeform = "32";'';
37 description = ''
38 Freeform description of a kernel configuration item value.
39 '';
40 };
41
42 optional = mkOption {
43 type = types.bool // {
44 merge = mergeFalseByDefault;
45 };
46 default = false;
47 description = ''
48 Whether option should generate a failure when unused.
49 Upon merging values, mandatory wins over optional.
50 '';
51 };
52 };
53 };
54
55 mkValue =
56 with lib;
57 val:
58 let
59 isNumber =
60 c:
61 elem c [
62 "0"
63 "1"
64 "2"
65 "3"
66 "4"
67 "5"
68 "6"
69 "7"
70 "8"
71 "9"
72 ];
73
74 in
75 if (val == "") then
76 "\"\""
77 else if val == "y" || val == "m" || val == "n" then
78 val
79 else if all isNumber (stringToCharacters val) then
80 val
81 else if substring 0 2 val == "0x" then
82 val
83 else
84 val; # FIXME: fix quoting one day
85
86 # generate nix intermediate kernel config file of the form
87 #
88 # VIRTIO_MMIO m
89 # VIRTIO_BLK y
90 # VIRTIO_CONSOLE n
91 # NET_9P_VIRTIO? y
92 #
93 # Borrowed from copumpkin https://github.com/NixOS/nixpkgs/pull/12158
94 # returns a string, expr should be an attribute set
95 # Use mkValuePreprocess to preprocess option values, aka mark 'modules' as 'yes' or vice-versa
96 # use the identity if you don't want to override the configured values
97 generateNixKConf =
98 exprs:
99 let
100 mkConfigLine =
101 key: item:
102 let
103 val = if item.freeform != null then item.freeform else item.tristate;
104 in
105 optionalString (val != null) (
106 if (item.optional) then "${key}? ${mkValue val}\n" else "${key} ${mkValue val}\n"
107 );
108
109 mkConf = cfg: concatStrings (mapAttrsToList mkConfigLine cfg);
110 in
111 mkConf exprs;
112
113in
114{
115
116 options = {
117
118 intermediateNixConfig = mkOption {
119 readOnly = true;
120 type = types.lines;
121 example = ''
122 USB? y
123 DEBUG n
124 '';
125 description = ''
126 The result of converting the structured kernel configuration in settings
127 to an intermediate string that can be parsed by generate-config.pl to
128 answer the kernel `make defconfig`.
129 '';
130 };
131
132 settings = mkOption {
133 type = types.attrsOf kernelItem;
134 example = literalExpression ''
135 with lib.kernel; {
136 "9P_NET" = yes;
137 USB = option yes;
138 MMC_BLOCK_MINORS = freeform "32";
139 }'';
140 description = ''
141 Structured kernel configuration.
142 '';
143 };
144 };
145
146 config = {
147 intermediateNixConfig = generateNixKConf config.settings;
148 };
149}