jql: 7.0.6 -> 7.0.7
[NixPkgs.git] / lib / modules.nix
blob4acbce39e94d1946a2331561f70487657935362d
1 { lib }:
3 let
4   inherit (lib)
5     all
6     any
7     attrByPath
8     attrNames
9     catAttrs
10     concatLists
11     concatMap
12     concatStringsSep
13     elem
14     filter
15     foldl'
16     getAttrFromPath
17     head
18     id
19     imap1
20     isAttrs
21     isBool
22     isFunction
23     isList
24     isString
25     length
26     mapAttrs
27     mapAttrsToList
28     mapAttrsRecursiveCond
29     min
30     optional
31     optionalAttrs
32     optionalString
33     recursiveUpdate
34     reverseList sort
35     setAttrByPath
36     types
37     warnIf
38     zipAttrsWith
39     ;
40   inherit (lib.options)
41     isOption
42     mkOption
43     showDefs
44     showFiles
45     showOption
46     unknownModule
47     ;
48   inherit (lib.strings)
49     isConvertibleWithToString
50     ;
52   showDeclPrefix = loc: decl: prefix:
53     " - option(s) with prefix `${showOption (loc ++ [prefix])}' in module `${decl._file}'";
54   showRawDecls = loc: decls:
55     concatStringsSep "\n"
56       (sort (a: b: a < b)
57         (concatMap
58           (decl: map
59             (showDeclPrefix loc decl)
60             (attrNames decl.options)
61           )
62           decls
63       ));
65   /* See https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules
66      or file://./../doc/module-system/module-system.chapter.md
68      !!! Please think twice before adding to this argument list! The more
69      that is specified here instead of in the modules themselves the harder
70      it is to transparently move a set of modules to be a submodule of another
71      config (as the proper arguments need to be replicated at each call to
72      evalModules) and the less declarative the module set is. */
73   evalModules = evalModulesArgs@
74                 { modules
75                 , prefix ? []
76                 , # This should only be used for special arguments that need to be evaluated
77                   # when resolving module structure (like in imports). For everything else,
78                   # there's _module.args. If specialArgs.modulesPath is defined it will be
79                   # used as the base path for disabledModules.
80                   specialArgs ? {}
81                 , # `class`:
82                   # A nominal type for modules. When set and non-null, this adds a check to
83                   # make sure that only compatible modules are imported.
84                   # This would be remove in the future, Prefer _module.args option instead.
85                   class ? null
86                 , args ? {}
87                 , # This would be remove in the future, Prefer _module.check option instead.
88                   check ? true
89                 }:
90     let
91       withWarnings = x:
92         lib.warnIf (evalModulesArgs?args) "The args argument to evalModules is deprecated. Please set config._module.args instead."
93         lib.warnIf (evalModulesArgs?check) "The check argument to evalModules is deprecated. Please set config._module.check instead."
94         x;
96       legacyModules =
97         optional (evalModulesArgs?args) {
98           config = {
99             _module.args = args;
100           };
101         }
102         ++ optional (evalModulesArgs?check) {
103           config = {
104             _module.check = mkDefault check;
105           };
106         };
107       regularModules = modules ++ legacyModules;
109       # This internal module declare internal options under the `_module'
110       # attribute.  These options are fragile, as they are used by the
111       # module system to change the interpretation of modules.
112       #
113       # When extended with extendModules or moduleType, a fresh instance of
114       # this module is used, to avoid conflicts and allow chaining of
115       # extendModules.
116       internalModule = rec {
117         _file = "lib/modules.nix";
119         key = _file;
121         options = {
122           _module.args = mkOption {
123             # Because things like `mkIf` are entirely useless for
124             # `_module.args` (because there's no way modules can check which
125             # arguments were passed), we'll use `lazyAttrsOf` which drops
126             # support for that, in turn it's lazy in its values. This means e.g.
127             # a `_module.args.pkgs = import (fetchTarball { ... }) {}` won't
128             # start a download when `pkgs` wasn't evaluated.
129             type = types.lazyAttrsOf types.raw;
130             # Only render documentation once at the root of the option tree,
131             # not for all individual submodules.
132             # Allow merging option decls to make this internal regardless.
133             ${if prefix == []
134               then null  # unset => visible
135               else "internal"} = true;
136             # TODO: Change the type of this option to a submodule with a
137             # freeformType, so that individual arguments can be documented
138             # separately
139             description = lib.mdDoc ''
140               Additional arguments passed to each module in addition to ones
141               like `lib`, `config`,
142               and `pkgs`, `modulesPath`.
144               This option is also available to all submodules. Submodules do not
145               inherit args from their parent module, nor do they provide args to
146               their parent module or sibling submodules. The sole exception to
147               this is the argument `name` which is provided by
148               parent modules to a submodule and contains the attribute name
149               the submodule is bound to, or a unique generated name if it is
150               not bound to an attribute.
152               Some arguments are already passed by default, of which the
153               following *cannot* be changed with this option:
154               - {var}`lib`: The nixpkgs library.
155               - {var}`config`: The results of all options after merging the values from all modules together.
156               - {var}`options`: The options declared in all modules.
157               - {var}`specialArgs`: The `specialArgs` argument passed to `evalModules`.
158               - All attributes of {var}`specialArgs`
160                 Whereas option values can generally depend on other option values
161                 thanks to laziness, this does not apply to `imports`, which
162                 must be computed statically before anything else.
164                 For this reason, callers of the module system can provide `specialArgs`
165                 which are available during import resolution.
167                 For NixOS, `specialArgs` includes
168                 {var}`modulesPath`, which allows you to import
169                 extra modules from the nixpkgs package tree without having to
170                 somehow make the module aware of the location of the
171                 `nixpkgs` or NixOS directories.
172                 ```
173                 { modulesPath, ... }: {
174                   imports = [
175                     (modulesPath + "/profiles/minimal.nix")
176                   ];
177                 }
178                 ```
180               For NixOS, the default value for this option includes at least this argument:
181               - {var}`pkgs`: The nixpkgs package set according to
182                 the {option}`nixpkgs.pkgs` option.
183             '';
184           };
186           _module.check = mkOption {
187             type = types.bool;
188             internal = true;
189             default = true;
190             description = lib.mdDoc "Whether to check whether all option definitions have matching declarations.";
191           };
193           _module.freeformType = mkOption {
194             type = types.nullOr types.optionType;
195             internal = true;
196             default = null;
197             description = lib.mdDoc ''
198               If set, merge all definitions that don't have an associated option
199               together using this type. The result then gets combined with the
200               values of all declared options to produce the final `
201               config` value.
203               If this is `null`, definitions without an option
204               will throw an error unless {option}`_module.check` is
205               turned off.
206             '';
207           };
209           _module.specialArgs = mkOption {
210             readOnly = true;
211             internal = true;
212             description = lib.mdDoc ''
213               Externally provided module arguments that can't be modified from
214               within a configuration, but can be used in module imports.
215             '';
216           };
217         };
219         config = {
220           _module.args = {
221             inherit extendModules;
222             moduleType = type;
223           };
224           _module.specialArgs = specialArgs;
225         };
226       };
228       merged =
229         let collected = collectModules
230           class
231           (specialArgs.modulesPath or "")
232           (regularModules ++ [ internalModule ])
233           ({ inherit lib options config specialArgs; } // specialArgs);
234         in mergeModules prefix (reverseList collected);
236       options = merged.matchedOptions;
238       config =
239         let
241           # For definitions that have an associated option
242           declaredConfig = mapAttrsRecursiveCond (v: ! isOption v) (_: v: v.value) options;
244           # If freeformType is set, this is for definitions that don't have an associated option
245           freeformConfig =
246             let
247               defs = map (def: {
248                 file = def.file;
249                 value = setAttrByPath def.prefix def.value;
250               }) merged.unmatchedDefns;
251             in if defs == [] then {}
252             else declaredConfig._module.freeformType.merge prefix defs;
254         in if declaredConfig._module.freeformType == null then declaredConfig
255           # Because all definitions that had an associated option ended in
256           # declaredConfig, freeformConfig can only contain the non-option
257           # paths, meaning recursiveUpdate will never override any value
258           else recursiveUpdate freeformConfig declaredConfig;
260       checkUnmatched =
261         if config._module.check && config._module.freeformType == null && merged.unmatchedDefns != [] then
262           let
263             firstDef = head merged.unmatchedDefns;
264             baseMsg =
265               let
266                 optText = showOption (prefix ++ firstDef.prefix);
267                 defText =
268                   builtins.addErrorContext
269                     "while evaluating the error message for definitions for `${optText}', which is an option that does not exist"
270                     (builtins.addErrorContext
271                       "while evaluating a definition from `${firstDef.file}'"
272                       ( showDefs [ firstDef ])
273                     );
274               in
275                 "The option `${optText}' does not exist. Definition values:${defText}";
276           in
277             if attrNames options == [ "_module" ]
278               then
279                 let
280                   optionName = showOption prefix;
281                 in
282                   if optionName == ""
283                     then throw ''
284                       ${baseMsg}
286                       It seems as if you're trying to declare an option by placing it into `config' rather than `options'!
287                     ''
288                   else
289                     throw ''
290                       ${baseMsg}
292                       However there are no options defined in `${showOption prefix}'. Are you sure you've
293                       declared your options properly? This can happen if you e.g. declared your options in `types.submodule'
294                       under `config' rather than `options'.
295                     ''
296             else throw baseMsg
297         else null;
299       checked = builtins.seq checkUnmatched;
301       extendModules = extendArgs@{
302         modules ? [],
303         specialArgs ? {},
304         prefix ? [],
305         }:
306           evalModules (evalModulesArgs // {
307             inherit class;
308             modules = regularModules ++ modules;
309             specialArgs = evalModulesArgs.specialArgs or {} // specialArgs;
310             prefix = extendArgs.prefix or evalModulesArgs.prefix or [];
311           });
313       type = lib.types.submoduleWith {
314         inherit modules specialArgs class;
315       };
317       result = withWarnings {
318         _type = "configuration";
319         options = checked options;
320         config = checked (removeAttrs config [ "_module" ]);
321         _module = checked (config._module);
322         inherit extendModules type;
323         class = class;
324       };
325     in result;
327   # collectModules :: (class: String) -> (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ]
328   #
329   # Collects all modules recursively through `import` statements, filtering out
330   # all modules in disabledModules.
331   collectModules = class: let
333       # Like unifyModuleSyntax, but also imports paths and calls functions if necessary
334       loadModule = args: fallbackFile: fallbackKey: m:
335         if isFunction m then
336           unifyModuleSyntax fallbackFile fallbackKey (applyModuleArgs fallbackKey m args)
337         else if isAttrs m then
338           if m._type or "module" == "module" then
339             unifyModuleSyntax fallbackFile fallbackKey m
340           else if m._type == "if" || m._type == "override" then
341             loadModule args fallbackFile fallbackKey { config = m; }
342           else
343             throw (
344               "Could not load a value as a module, because it is of type ${lib.strings.escapeNixString m._type}"
345               + lib.optionalString (fallbackFile != unknownModule) ", in file ${toString fallbackFile}."
346               + lib.optionalString (m._type == "configuration") " If you do intend to import this configuration, please only import the modules that make up the configuration. You may have to create a `let` binding, file or attribute to give yourself access to the relevant modules.\nWhile loading a configuration into the module system is a very sensible idea, it can not be done cleanly in practice."
347                # Extended explanation: That's because a finalized configuration is more than just a set of modules. For instance, it has its own `specialArgs` that, by the nature of `specialArgs` can't be loaded through `imports` or the the `modules` argument. So instead, we have to ask you to extract the relevant modules and use those instead. This way, we keep the module system comparatively simple, and hopefully avoid a bad surprise down the line.
348             )
349         else if isList m then
350           let defs = [{ file = fallbackFile; value = m; }]; in
351           throw "Module imports can't be nested lists. Perhaps you meant to remove one level of lists? Definitions: ${showDefs defs}"
352         else unifyModuleSyntax (toString m) (toString m) (applyModuleArgsIfFunction (toString m) (import m) args);
354       checkModule =
355         if class != null
356         then
357           m:
358             if m._class != null -> m._class == class
359             then m
360             else
361               throw "The module ${m._file or m.key} was imported into ${class} instead of ${m._class}."
362         else
363           m: m;
365       /*
366       Collects all modules recursively into the form
368         {
369           disabled = [ <list of disabled modules> ];
370           # All modules of the main module list
371           modules = [
372             {
373               key = <key1>;
374               module = <module for key1>;
375               # All modules imported by the module for key1
376               modules = [
377                 {
378                   key = <key1-1>;
379                   module = <module for key1-1>;
380                   # All modules imported by the module for key1-1
381                   modules = [ ... ];
382                 }
383                 ...
384               ];
385             }
386             ...
387           ];
388         }
389       */
390       collectStructuredModules =
391         let
392           collectResults = modules: {
393             disabled = concatLists (catAttrs "disabled" modules);
394             inherit modules;
395           };
396         in parentFile: parentKey: initialModules: args: collectResults (imap1 (n: x:
397           let
398             module = checkModule (loadModule args parentFile "${parentKey}:anon-${toString n}" x);
399             collectedImports = collectStructuredModules module._file module.key module.imports args;
400           in {
401             key = module.key;
402             module = module;
403             modules = collectedImports.modules;
404             disabled = (if module.disabledModules != [] then [{ file = module._file; disabled = module.disabledModules; }] else []) ++ collectedImports.disabled;
405           }) initialModules);
407       # filterModules :: String -> { disabled, modules } -> [ Module ]
408       #
409       # Filters a structure as emitted by collectStructuredModules by removing all disabled
410       # modules recursively. It returns the final list of unique-by-key modules
411       filterModules = modulesPath: { disabled, modules }:
412         let
413           moduleKey = file: m:
414             if isString m
415             then
416               if builtins.substring 0 1 m == "/"
417               then m
418               else toString modulesPath + "/" + m
420             else if isConvertibleWithToString m
421             then
422               if m?key && m.key != toString m
423               then
424                 throw "Module `${file}` contains a disabledModules item that is an attribute set that can be converted to a string (${toString m}) but also has a `.key` attribute (${m.key}) with a different value. This makes it ambiguous which module should be disabled."
425               else
426                 toString m
428             else if m?key
429             then
430               m.key
432             else if isAttrs m
433             then throw "Module `${file}` contains a disabledModules item that is an attribute set, presumably a module, that does not have a `key` attribute. This means that the module system doesn't have any means to identify the module that should be disabled. Make sure that you've put the correct value in disabledModules: a string path relative to modulesPath, a path value, or an attribute set with a `key` attribute."
434             else throw "Each disabledModules item must be a path, string, or a attribute set with a key attribute, or a value supported by toString. However, one of the disabledModules items in `${toString file}` is none of that, but is of type ${builtins.typeOf m}.";
436           disabledKeys = concatMap ({ file, disabled }: map (moduleKey file) disabled) disabled;
437           keyFilter = filter (attrs: ! elem attrs.key disabledKeys);
438         in map (attrs: attrs.module) (builtins.genericClosure {
439           startSet = keyFilter modules;
440           operator = attrs: keyFilter attrs.modules;
441         });
443     in modulesPath: initialModules: args:
444       filterModules modulesPath (collectStructuredModules unknownModule "" initialModules args);
446   /* Wrap a module with a default location for reporting errors. */
447   setDefaultModuleLocation = file: m:
448     { _file = file; imports = [ m ]; };
450   /* Massage a module into canonical form, that is, a set consisting
451      of â€˜options’, â€˜config’ and â€˜imports’ attributes. */
452   unifyModuleSyntax = file: key: m:
453     let
454       addMeta = config: if m ? meta
455         then mkMerge [ config { meta = m.meta; } ]
456         else config;
457       addFreeformType = config: if m ? freeformType
458         then mkMerge [ config { _module.freeformType = m.freeformType; } ]
459         else config;
460     in
461     if m ? config || m ? options then
462       let badAttrs = removeAttrs m ["_class" "_file" "key" "disabledModules" "imports" "options" "config" "meta" "freeformType"]; in
463       if badAttrs != {} then
464         throw "Module `${key}' has an unsupported attribute `${head (attrNames badAttrs)}'. This is caused by introducing a top-level `config' or `options' attribute. Add configuration attributes immediately on the top level instead, or move all of them (namely: ${toString (attrNames badAttrs)}) into the explicit `config' attribute."
465       else
466         { _file = toString m._file or file;
467           _class = m._class or null;
468           key = toString m.key or key;
469           disabledModules = m.disabledModules or [];
470           imports = m.imports or [];
471           options = m.options or {};
472           config = addFreeformType (addMeta (m.config or {}));
473         }
474     else
475       # shorthand syntax
476       lib.throwIfNot (isAttrs m) "module ${file} (${key}) does not look like a module."
477       { _file = toString m._file or file;
478         _class = m._class or null;
479         key = toString m.key or key;
480         disabledModules = m.disabledModules or [];
481         imports = m.require or [] ++ m.imports or [];
482         options = {};
483         config = addFreeformType (removeAttrs m ["_class" "_file" "key" "disabledModules" "require" "imports" "freeformType"]);
484       };
486   applyModuleArgsIfFunction = key: f: args@{ config, options, lib, ... }:
487     if isFunction f then applyModuleArgs key f args else f;
489   applyModuleArgs = key: f: args@{ config, options, lib, ... }:
490     let
491       # Module arguments are resolved in a strict manner when attribute set
492       # deconstruction is used.  As the arguments are now defined with the
493       # config._module.args option, the strictness used on the attribute
494       # set argument would cause an infinite loop, if the result of the
495       # option is given as argument.
496       #
497       # To work-around the strictness issue on the deconstruction of the
498       # attributes set argument, we create a new attribute set which is
499       # constructed to satisfy the expected set of attributes.  Thus calling
500       # a module will resolve strictly the attributes used as argument but
501       # not their values.  The values are forwarding the result of the
502       # evaluation of the option.
503       context = name: ''while evaluating the module argument `${name}' in "${key}":'';
504       extraArgs = builtins.mapAttrs (name: _:
505         builtins.addErrorContext (context name)
506           (args.${name} or config._module.args.${name})
507       ) (lib.functionArgs f);
509       # Note: we append in the opposite order such that we can add an error
510       # context on the explicit arguments of "args" too. This update
511       # operator is used to make the "args@{ ... }: with args.lib;" notation
512       # works.
513     in f (args // extraArgs);
515   /* Merge a list of modules.  This will recurse over the option
516      declarations in all modules, combining them into a single set.
517      At the same time, for each option declaration, it will merge the
518      corresponding option definitions in all machines, returning them
519      in the â€˜value’ attribute of each option.
521      This returns a set like
522        {
523          # A recursive set of options along with their final values
524          matchedOptions = {
525            foo = { _type = "option"; value = "option value of foo"; ... };
526            bar.baz = { _type = "option"; value = "option value of bar.baz"; ... };
527            ...
528          };
529          # A list of definitions that weren't matched by any option
530          unmatchedDefns = [
531            { file = "file.nix"; prefix = [ "qux" ]; value = "qux"; }
532            ...
533          ];
534        }
535   */
536   mergeModules = prefix: modules:
537     mergeModules' prefix modules
538       (concatMap (m: map (config: { file = m._file; inherit config; }) (pushDownProperties m.config)) modules);
540   mergeModules' = prefix: modules: configs:
541     let
542       # an attrset 'name' => list of submodules that declare â€˜name’.
543       declsByName =
544         zipAttrsWith
545           (n: concatLists)
546           (map
547             (module: let subtree = module.options; in
548               if !(builtins.isAttrs subtree) then
549                 throw ''
550                   An option declaration for `${builtins.concatStringsSep "." prefix}' has type
551                   `${builtins.typeOf subtree}' rather than an attribute set.
552                   Did you mean to define this outside of `options'?
553                 ''
554               else
555                 mapAttrs
556                   (n: option:
557                     [{ inherit (module) _file; pos = builtins.unsafeGetAttrPos n subtree; options = option; }]
558                   )
559                   subtree
560               )
561             modules);
563       # The root of any module definition must be an attrset.
564       checkedConfigs =
565         assert
566           lib.all
567             (c:
568               # TODO: I have my doubts that this error would occur when option definitions are not matched.
569               #       The implementation of this check used to be tied to a superficially similar check for
570               #       options, so maybe that's why this is here.
571               isAttrs c.config || throw ''
572                 In module `${c.file}', you're trying to define a value of type `${builtins.typeOf c.config}'
573                 rather than an attribute set for the option
574                 `${builtins.concatStringsSep "." prefix}'!
576                 This usually happens if `${builtins.concatStringsSep "." prefix}' has option
577                 definitions inside that are not matched. Please check how to properly define
578                 this option by e.g. referring to `man 5 configuration.nix'!
579               ''
580             )
581             configs;
582         configs;
584       # an attrset 'name' => list of submodules that define â€˜name’.
585       pushedDownDefinitionsByName =
586         zipAttrsWith
587           (n: concatLists)
588           (map
589             (module:
590               mapAttrs
591                 (n: value:
592                   map (config: { inherit (module) file; inherit config; }) (pushDownProperties value)
593                 )
594               module.config
595             )
596             checkedConfigs);
597       # extract the definitions for each loc
598       rawDefinitionsByName =
599         zipAttrsWith
600           (n: concatLists)
601           (map
602             (module:
603               mapAttrs
604                 (n: value:
605                   [{ inherit (module) file; inherit value; }]
606                 )
607                 module.config
608             )
609             checkedConfigs);
611       # Convert an option tree decl to a submodule option decl
612       optionTreeToOption = decl:
613         if isOption decl.options
614         then decl
615         else decl // {
616             options = mkOption {
617               type = types.submoduleWith {
618                 modules = [ { options = decl.options; } ];
619                 # `null` is not intended for use by modules. It is an internal
620                 # value that means "whatever the user has declared elsewhere".
621                 # This might become obsolete with https://github.com/NixOS/nixpkgs/issues/162398
622                 shorthandOnlyDefinesConfig = null;
623               };
624             };
625           };
627       resultsByName = mapAttrs (name: decls:
628         # We're descending into attribute â€˜name’.
629         let
630           loc = prefix ++ [name];
631           defns = pushedDownDefinitionsByName.${name} or [];
632           defns' = rawDefinitionsByName.${name} or [];
633           optionDecls = filter
634             (m: m.options?_type
635                 && (m.options._type == "option"
636                     || throwDeclarationTypeError loc m.options._type m._file
637                 )
638             )
639             decls;
640         in
641           if length optionDecls == length decls then
642             let opt = fixupOptionType loc (mergeOptionDecls loc decls);
643             in {
644               matchedOptions = evalOptionValue loc opt defns';
645               unmatchedDefns = [];
646             }
647           else if optionDecls != [] then
648               if all (x: x.options.type.name or null == "submodule") optionDecls
649               # Raw options can only be merged into submodules. Merging into
650               # attrsets might be nice, but ambiguous. Suppose we have
651               # attrset as a `attrsOf submodule`. User declares option
652               # attrset.foo.bar, this could mean:
653               #  a. option `bar` is only available in `attrset.foo`
654               #  b. option `foo.bar` is available in all `attrset.*`
655               #  c. reject and require "<name>" as a reminder that it behaves like (b).
656               #  d. magically combine (a) and (c).
657               # All of the above are merely syntax sugar though.
658               then
659                 let opt = fixupOptionType loc (mergeOptionDecls loc (map optionTreeToOption decls));
660                 in {
661                   matchedOptions = evalOptionValue loc opt defns';
662                   unmatchedDefns = [];
663                 }
664               else
665                 let
666                   nonOptions = filter (m: !isOption m.options) decls;
667                 in
668                 throw "The option `${showOption loc}' in module `${(lib.head optionDecls)._file}' would be a parent of the following options, but its type `${(lib.head optionDecls).options.type.description or "<no description>"}' does not support nested options.\n${
669                   showRawDecls loc nonOptions
670                 }"
671           else
672             mergeModules' loc decls defns) declsByName;
674       matchedOptions = mapAttrs (n: v: v.matchedOptions) resultsByName;
676       # an attrset 'name' => list of unmatched definitions for 'name'
677       unmatchedDefnsByName =
678         # Propagate all unmatched definitions from nested option sets
679         mapAttrs (n: v: v.unmatchedDefns) resultsByName
680         # Plus the definitions for the current prefix that don't have a matching option
681         // removeAttrs rawDefinitionsByName (attrNames matchedOptions);
682     in {
683       inherit matchedOptions;
685       # Transforms unmatchedDefnsByName into a list of definitions
686       unmatchedDefns =
687         if configs == []
688         then
689           # When no config values exist, there can be no unmatched config, so
690           # we short circuit and avoid evaluating more _options_ than necessary.
691           []
692         else
693           concatLists (mapAttrsToList (name: defs:
694             map (def: def // {
695               # Set this so we know when the definition first left unmatched territory
696               prefix = [name] ++ (def.prefix or []);
697             }) defs
698           ) unmatchedDefnsByName);
699     };
701   throwDeclarationTypeError = loc: actualTag: file:
702     let
703       name = lib.strings.escapeNixIdentifier (lib.lists.last loc);
704       path = showOption loc;
705       depth = length loc;
707       paragraphs = [
708         "In module ${file}: expected an option declaration at option path `${path}` but got an attribute set with type ${actualTag}"
709       ] ++ optional (actualTag == "option-type") ''
710           When declaring an option, you must wrap the type in a `mkOption` call. It should look somewhat like:
711               ${comment}
712               ${name} = lib.mkOption {
713                 description = ...;
714                 type = <the type you wrote for ${name}>;
715                 ...
716               };
717         '';
719       # Ideally we'd know the exact syntax they used, but short of that,
720       # we can only reliably repeat the last. However, we repeat the
721       # full path in a non-misleading way here, in case they overlook
722       # the start of the message. Examples attract attention.
723       comment = optionalString (depth > 1) "\n    # ${showOption loc}";
724     in
725     throw (concatStringsSep "\n\n" paragraphs);
727   /* Merge multiple option declarations into a single declaration.  In
728      general, there should be only one declaration of each option.
729      The exception is the â€˜options’ attribute, which specifies
730      sub-options.  These can be specified multiple times to allow one
731      module to add sub-options to an option declared somewhere else
732      (e.g. multiple modules define sub-options for â€˜fileSystems’).
734      'loc' is the list of attribute names where the option is located.
736      'opts' is a list of modules.  Each module has an options attribute which
737      correspond to the definition of 'loc' in 'opt.file'. */
738   mergeOptionDecls =
739    loc: opts:
740     foldl' (res: opt:
741       let t  = res.type;
742           t' = opt.options.type;
743           mergedType = t.typeMerge t'.functor;
744           typesMergeable = mergedType != null;
745           typeSet = if (bothHave "type") && typesMergeable
746                        then { type = mergedType; }
747                        else {};
748           bothHave = k: opt.options ? ${k} && res ? ${k};
749       in
750       if bothHave "default" ||
751          bothHave "example" ||
752          bothHave "description" ||
753          bothHave "apply" ||
754          (bothHave "type" && (! typesMergeable))
755       then
756         throw "The option `${showOption loc}' in `${opt._file}' is already declared in ${showFiles res.declarations}."
757       else
758         let
759           getSubModules = opt.options.type.getSubModules or null;
760           submodules =
761             if getSubModules != null then map (setDefaultModuleLocation opt._file) getSubModules ++ res.options
762             else res.options;
763         in opt.options // res //
764           { declarations = res.declarations ++ [opt._file];
765             # In the case of modules that are generated dynamically, we won't
766             # have exact declaration lines; fall back to just the file being
767             # evaluated.
768             declarationPositions = res.declarationPositions
769               ++ (if opt.pos != null
770                 then [opt.pos]
771                 else [{ file = opt._file; line = null; column = null; }]);
772             options = submodules;
773           } // typeSet
774     ) { inherit loc; declarations = []; declarationPositions = []; options = []; } opts;
776   /* Merge all the definitions of an option to produce the final
777      config value. */
778   evalOptionValue = loc: opt: defs:
779     let
780       # Add in the default value for this option, if any.
781       defs' =
782           (optional (opt ? default)
783             { file = head opt.declarations; value = mkOptionDefault opt.default; }) ++ defs;
785       # Handle properties, check types, and merge everything together.
786       res =
787         if opt.readOnly or false && length defs' > 1 then
788           let
789             # For a better error message, evaluate all readOnly definitions as
790             # if they were the only definition.
791             separateDefs = map (def: def // {
792               value = (mergeDefinitions loc opt.type [ def ]).mergedValue;
793             }) defs';
794           in throw "The option `${showOption loc}' is read-only, but it's set multiple times. Definition values:${showDefs separateDefs}"
795         else
796           mergeDefinitions loc opt.type defs';
798       # Apply the 'apply' function to the merged value. This allows options to
799       # yield a value computed from the definitions
800       value = if opt ? apply then opt.apply res.mergedValue else res.mergedValue;
802       warnDeprecation =
803         warnIf (opt.type.deprecationMessage != null)
804           "The type `types.${opt.type.name}' of option `${showOption loc}' defined in ${showFiles opt.declarations} is deprecated. ${opt.type.deprecationMessage}";
806     in warnDeprecation opt //
807       { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
808         inherit (res.defsFinal') highestPrio;
809         definitions = map (def: def.value) res.defsFinal;
810         files = map (def: def.file) res.defsFinal;
811         definitionsWithLocations = res.defsFinal;
812         inherit (res) isDefined;
813         # This allows options to be correctly displayed using `${options.path.to.it}`
814         __toString = _: showOption loc;
815       };
817   # Merge definitions of a value of a given type.
818   mergeDefinitions = loc: type: defs: rec {
819     defsFinal' =
820       let
821         # Process mkMerge and mkIf properties.
822         defs' = concatMap (m:
823           map (value: { inherit (m) file; inherit value; }) (builtins.addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))
824         ) defs;
826         # Process mkOverride properties.
827         defs'' = filterOverrides' defs';
829         # Sort mkOrder properties.
830         defs''' =
831           # Avoid sorting if we don't have to.
832           if any (def: def.value._type or "" == "order") defs''.values
833           then sortProperties defs''.values
834           else defs''.values;
835       in {
836         values = defs''';
837         inherit (defs'') highestPrio;
838       };
839     defsFinal = defsFinal'.values;
841     # Type-check the remaining definitions, and merge them. Or throw if no definitions.
842     mergedValue =
843       if isDefined then
844         if all (def: type.check def.value) defsFinal then type.merge loc defsFinal
845         else let allInvalid = filter (def: ! type.check def.value) defsFinal;
846         in throw "A definition for option `${showOption loc}' is not of type `${type.description}'. Definition values:${showDefs allInvalid}"
847       else
848         # (nixos-option detects this specific error message and gives it special
849         # handling.  If changed here, please change it there too.)
850         throw "The option `${showOption loc}' is used but not defined.";
852     isDefined = defsFinal != [];
854     optionalValue =
855       if isDefined then { value = mergedValue; }
856       else {};
857   };
859   /* Given a config set, expand mkMerge properties, and push down the
860      other properties into the children.  The result is a list of
861      config sets that do not have properties at top-level.  For
862      example,
864        mkMerge [ { boot = set1; } (mkIf cond { boot = set2; services = set3; }) ]
866      is transformed into
868        [ { boot = set1; } { boot = mkIf cond set2; services = mkIf cond set3; } ].
870      This transform is the critical step that allows mkIf conditions
871      to refer to the full configuration without creating an infinite
872      recursion.
873   */
874   pushDownProperties = cfg:
875     if cfg._type or "" == "merge" then
876       concatMap pushDownProperties cfg.contents
877     else if cfg._type or "" == "if" then
878       map (mapAttrs (n: v: mkIf cfg.condition v)) (pushDownProperties cfg.content)
879     else if cfg._type or "" == "override" then
880       map (mapAttrs (n: v: mkOverride cfg.priority v)) (pushDownProperties cfg.content)
881     else # FIXME: handle mkOrder?
882       [ cfg ];
884   /* Given a config value, expand mkMerge properties, and discharge
885      any mkIf conditions.  That is, this is the place where mkIf
886      conditions are actually evaluated.  The result is a list of
887      config values.  For example, â€˜mkIf false x’ yields â€˜[]’,
888      â€˜mkIf true x’ yields â€˜[x]’, and
890        mkMerge [ 1 (mkIf true 2) (mkIf true (mkIf false 3)) ]
892      yields â€˜[ 1 2 ]’.
893   */
894   dischargeProperties = def:
895     if def._type or "" == "merge" then
896       concatMap dischargeProperties def.contents
897     else if def._type or "" == "if" then
898       if isBool def.condition then
899         if def.condition then
900           dischargeProperties def.content
901         else
902           [ ]
903       else
904         throw "‘mkIf’ called with a non-Boolean condition"
905     else
906       [ def ];
908   /* Given a list of config values, process the mkOverride properties,
909      that is, return the values that have the highest (that is,
910      numerically lowest) priority, and strip the mkOverride
911      properties.  For example,
913        [ { file = "/1"; value = mkOverride 10 "a"; }
914          { file = "/2"; value = mkOverride 20 "b"; }
915          { file = "/3"; value = "z"; }
916          { file = "/4"; value = mkOverride 10 "d"; }
917        ]
919      yields
921        [ { file = "/1"; value = "a"; }
922          { file = "/4"; value = "d"; }
923        ]
925      Note that "z" has the default priority 100.
926   */
927   filterOverrides = defs: (filterOverrides' defs).values;
929   filterOverrides' = defs:
930     let
931       getPrio = def: if def.value._type or "" == "override" then def.value.priority else defaultOverridePriority;
932       highestPrio = foldl' (prio: def: min (getPrio def) prio) 9999 defs;
933       strip = def: if def.value._type or "" == "override" then def // { value = def.value.content; } else def;
934     in {
935       values = concatMap (def: if getPrio def == highestPrio then [(strip def)] else []) defs;
936       inherit highestPrio;
937     };
939   /* Sort a list of properties.  The sort priority of a property is
940      defaultOrderPriority by default, but can be overridden by wrapping the property
941      using mkOrder. */
942   sortProperties = defs:
943     let
944       strip = def:
945         if def.value._type or "" == "order"
946         then def // { value = def.value.content; inherit (def.value) priority; }
947         else def;
948       defs' = map strip defs;
949       compare = a: b: (a.priority or defaultOrderPriority) < (b.priority or defaultOrderPriority);
950     in sort compare defs';
952   # This calls substSubModules, whose entire purpose is only to ensure that
953   # option declarations in submodules have accurate position information.
954   # TODO: Merge this into mergeOptionDecls
955   fixupOptionType = loc: opt:
956     if opt.type.getSubModules or null == null
957     then opt // { type = opt.type or types.unspecified; }
958     else opt // { type = opt.type.substSubModules opt.options; options = []; };
961   /*
962     Merge an option's definitions in a way that preserves the priority of the
963     individual attributes in the option value.
965     This does not account for all option semantics, such as readOnly.
967     Type:
968       option -> attrsOf { highestPrio, value }
969   */
970   mergeAttrDefinitionsWithPrio = opt:
971         let
972             defsByAttr =
973               lib.zipAttrs (
974                 lib.concatLists (
975                   lib.concatMap
976                     ({ value, ... }@def:
977                       map
978                         (lib.mapAttrsToList (k: value: { ${k} = def // { inherit value; }; }))
979                         (pushDownProperties value)
980                     )
981                     opt.definitionsWithLocations
982                 )
983               );
984         in
985           assert opt.type.name == "attrsOf" || opt.type.name == "lazyAttrsOf";
986           lib.mapAttrs
987                 (k: v:
988                   let merging = lib.mergeDefinitions (opt.loc ++ [k]) opt.type.nestedTypes.elemType v;
989                   in {
990                     value = merging.mergedValue;
991                     inherit (merging.defsFinal') highestPrio;
992                   })
993                 defsByAttr;
995   /* Properties. */
997   mkIf = condition: content:
998     { _type = "if";
999       inherit condition content;
1000     };
1002   mkAssert = assertion: message: content:
1003     mkIf
1004       (if assertion then true else throw "\nFailed assertion: ${message}")
1005       content;
1007   mkMerge = contents:
1008     { _type = "merge";
1009       inherit contents;
1010     };
1012   mkOverride = priority: content:
1013     { _type = "override";
1014       inherit priority content;
1015     };
1017   mkOptionDefault = mkOverride 1500; # priority of option defaults
1018   mkDefault = mkOverride 1000; # used in config sections of non-user modules to set a default
1019   defaultOverridePriority = 100;
1020   mkImageMediaOverride = mkOverride 60; # image media profiles can be derived by inclusion into host config, hence needing to override host config, but do allow user to mkForce
1021   mkForce = mkOverride 50;
1022   mkVMOverride = mkOverride 10; # used by â€˜nixos-rebuild build-vm’
1024   defaultPriority = lib.warnIf (lib.isInOldestRelease 2305) "lib.modules.defaultPriority is deprecated, please use lib.modules.defaultOverridePriority instead." defaultOverridePriority;
1026   mkFixStrictness = lib.warn "lib.mkFixStrictness has no effect and will be removed. It returns its argument unmodified, so you can just remove any calls." id;
1028   mkOrder = priority: content:
1029     { _type = "order";
1030       inherit priority content;
1031     };
1033   mkBefore = mkOrder 500;
1034   defaultOrderPriority = 1000;
1035   mkAfter = mkOrder 1500;
1037   # Convenient property used to transfer all definitions and their
1038   # properties from one option to another. This property is useful for
1039   # renaming options, and also for including properties from another module
1040   # system, including sub-modules.
1041   #
1042   #   { config, options, ... }:
1043   #
1044   #   {
1045   #     # 'bar' might not always be defined in the current module-set.
1046   #     config.foo.enable = mkAliasDefinitions (options.bar.enable or {});
1047   #
1048   #     # 'barbaz' has to be defined in the current module-set.
1049   #     config.foobar.paths = mkAliasDefinitions options.barbaz.paths;
1050   #   }
1051   #
1052   # Note, this is different than taking the value of the option and using it
1053   # as a definition, as the new definition will not keep the mkOverride /
1054   # mkDefault properties of the previous option.
1055   #
1056   mkAliasDefinitions = mkAliasAndWrapDefinitions id;
1057   mkAliasAndWrapDefinitions = wrap: option:
1058     mkAliasIfDef option (wrap (mkMerge option.definitions));
1060   # Similar to mkAliasAndWrapDefinitions but copies over the priority from the
1061   # option as well.
1062   #
1063   # If a priority is not set, it assumes a priority of defaultOverridePriority.
1064   mkAliasAndWrapDefsWithPriority = wrap: option:
1065     let
1066       prio = option.highestPrio or defaultOverridePriority;
1067       defsWithPrio = map (mkOverride prio) option.definitions;
1068     in mkAliasIfDef option (wrap (mkMerge defsWithPrio));
1070   mkAliasIfDef = option:
1071     mkIf (isOption option && option.isDefined);
1073   /* Compatibility. */
1074   fixMergeModules = modules: args: evalModules { inherit modules args; check = false; };
1077   /* Return a module that causes a warning to be shown if the
1078      specified option is defined. For example,
1080        mkRemovedOptionModule [ "boot" "loader" "grub" "bootDevice" ] "<replacement instructions>"
1082      causes a assertion if the user defines boot.loader.grub.bootDevice.
1084      replacementInstructions is a string that provides instructions on
1085      how to achieve the same functionality without the removed option,
1086      or alternatively a reasoning why the functionality is not needed.
1087      replacementInstructions SHOULD be provided!
1088   */
1089   mkRemovedOptionModule = optionName: replacementInstructions:
1090     { options, ... }:
1091     { options = setAttrByPath optionName (mkOption {
1092         visible = false;
1093         apply = x: throw "The option `${showOption optionName}' can no longer be used since it's been removed. ${replacementInstructions}";
1094       });
1095       config.assertions =
1096         let opt = getAttrFromPath optionName options; in [{
1097           assertion = !opt.isDefined;
1098           message = ''
1099             The option definition `${showOption optionName}' in ${showFiles opt.files} no longer has any effect; please remove it.
1100             ${replacementInstructions}
1101           '';
1102         }];
1103     };
1105   /* Return a module that causes a warning to be shown if the
1106      specified "from" option is defined; the defined value is however
1107      forwarded to the "to" option. This can be used to rename options
1108      while providing backward compatibility. For example,
1110        mkRenamedOptionModule [ "boot" "copyKernels" ] [ "boot" "loader" "grub" "copyKernels" ]
1112      forwards any definitions of boot.copyKernels to
1113      boot.loader.grub.copyKernels while printing a warning.
1115      This also copies over the priority from the aliased option to the
1116      non-aliased option.
1117   */
1118   mkRenamedOptionModule = from: to: doRename {
1119     inherit from to;
1120     visible = false;
1121     warn = true;
1122     use = builtins.trace "Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'.";
1123   };
1125   mkRenamedOptionModuleWith = {
1126     /* Old option path as list of strings. */
1127     from,
1128     /* New option path as list of strings. */
1129     to,
1131     /*
1132       Release number of the first release that contains the rename, ignoring backports.
1133       Set it to the upcoming release, matching the nixpkgs/.version file.
1134     */
1135     sinceRelease,
1137   }: doRename {
1138     inherit from to;
1139     visible = false;
1140     warn = lib.isInOldestRelease sinceRelease;
1141     use = lib.warnIf (lib.isInOldestRelease sinceRelease)
1142       "Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'.";
1143   };
1145   /* Return a module that causes a warning to be shown if any of the "from"
1146      option is defined; the defined values can be used in the "mergeFn" to set
1147      the "to" value.
1148      This function can be used to merge multiple options into one that has a
1149      different type.
1151      "mergeFn" takes the module "config" as a parameter and must return a value
1152      of "to" option type.
1154        mkMergedOptionModule
1155          [ [ "a" "b" "c" ]
1156            [ "d" "e" "f" ] ]
1157          [ "x" "y" "z" ]
1158          (config:
1159            let value = p: getAttrFromPath p config;
1160            in
1161            if      (value [ "a" "b" "c" ]) == true then "foo"
1162            else if (value [ "d" "e" "f" ]) == true then "bar"
1163            else "baz")
1165      - options.a.b.c is a removed boolean option
1166      - options.d.e.f is a removed boolean option
1167      - options.x.y.z is a new str option that combines a.b.c and d.e.f
1168        functionality
1170      This show a warning if any a.b.c or d.e.f is set, and set the value of
1171      x.y.z to the result of the merge function
1172   */
1173   mkMergedOptionModule = from: to: mergeFn:
1174     { config, options, ... }:
1175     {
1176       options = foldl' recursiveUpdate {} (map (path: setAttrByPath path (mkOption {
1177         visible = false;
1178         # To use the value in mergeFn without triggering errors
1179         default = "_mkMergedOptionModule";
1180       })) from);
1182       config = {
1183         warnings = filter (x: x != "") (map (f:
1184           let val = getAttrFromPath f config;
1185               opt = getAttrFromPath f options;
1186           in
1187           optionalString
1188             (val != "_mkMergedOptionModule")
1189             "The option `${showOption f}' defined in ${showFiles opt.files} has been changed to `${showOption to}' that has a different type. Please read `${showOption to}' documentation and update your configuration accordingly."
1190         ) from);
1191       } // setAttrByPath to (mkMerge
1192              (optional
1193                (any (f: (getAttrFromPath f config) != "_mkMergedOptionModule") from)
1194                (mergeFn config)));
1195     };
1197   /* Single "from" version of mkMergedOptionModule.
1198      Return a module that causes a warning to be shown if the "from" option is
1199      defined; the defined value can be used in the "mergeFn" to set the "to"
1200      value.
1201      This function can be used to change an option into another that has a
1202      different type.
1204      "mergeFn" takes the module "config" as a parameter and must return a value of
1205      "to" option type.
1207        mkChangedOptionModule [ "a" "b" "c" ] [ "x" "y" "z" ]
1208          (config:
1209            let value = getAttrFromPath [ "a" "b" "c" ] config;
1210            in
1211            if   value > 100 then "high"
1212            else "normal")
1214      - options.a.b.c is a removed int option
1215      - options.x.y.z is a new str option that supersedes a.b.c
1217      This show a warning if a.b.c is set, and set the value of x.y.z to the
1218      result of the change function
1219   */
1220   mkChangedOptionModule = from: to: changeFn:
1221     mkMergedOptionModule [ from ] to changeFn;
1223   /* Like â€˜mkRenamedOptionModule’, but doesn't show a warning. */
1224   mkAliasOptionModule = from: to: doRename {
1225     inherit from to;
1226     visible = true;
1227     warn = false;
1228     use = id;
1229   };
1231   /* Transitional version of mkAliasOptionModule that uses MD docs.
1233      This function is no longer necessary and merely an alias of `mkAliasOptionModule`.
1234   */
1235   mkAliasOptionModuleMD = mkAliasOptionModule;
1237   /* mkDerivedConfig : Option a -> (a -> Definition b) -> Definition b
1239     Create config definitions with the same priority as the definition of another option.
1240     This should be used for option definitions where one option sets the value of another as a convenience.
1241     For instance a config file could be set with a `text` or `source` option, where text translates to a `source`
1242     value using `mkDerivedConfig options.text (pkgs.writeText "filename.conf")`.
1244     It takes care of setting the right priority using `mkOverride`.
1245   */
1246   # TODO: make the module system error message include information about `opt` in
1247   # error messages about conflicts. E.g. introduce a variation of `mkOverride` which
1248   # adds extra location context to the definition object. This will allow context to be added
1249   # to all messages that report option locations "this value was derived from <full option name>
1250   # which was defined in <locations>". It can provide a trace of options that contributed
1251   # to definitions.
1252   mkDerivedConfig = opt: f:
1253     mkOverride
1254       (opt.highestPrio or defaultOverridePriority)
1255       (f opt.value);
1257   doRename = { from, to, visible, warn, use, withPriority ? true }:
1258     { config, options, ... }:
1259     let
1260       fromOpt = getAttrFromPath from options;
1261       toOf = attrByPath to
1262         (abort "Renaming error: option `${showOption to}' does not exist.");
1263       toType = let opt = attrByPath to {} options; in opt.type or (types.submodule {});
1264     in
1265     {
1266       options = setAttrByPath from (mkOption {
1267         inherit visible;
1268         description = "Alias of {option}`${showOption to}`.";
1269         apply = x: use (toOf config);
1270       } // optionalAttrs (toType != null) {
1271         type = toType;
1272       });
1273       config = mkMerge [
1274         (optionalAttrs (options ? warnings) {
1275           warnings = optional (warn && fromOpt.isDefined)
1276             "The option `${showOption from}' defined in ${showFiles fromOpt.files} has been renamed to `${showOption to}'.";
1277         })
1278         (if withPriority
1279           then mkAliasAndWrapDefsWithPriority (setAttrByPath to) fromOpt
1280           else mkAliasAndWrapDefinitions (setAttrByPath to) fromOpt)
1281       ];
1282     };
1284   /* Use this function to import a JSON file as NixOS configuration.
1286      modules.importJSON :: path -> attrs
1287   */
1288   importJSON = file: {
1289     _file = file;
1290     config = lib.importJSON file;
1291   };
1293   /* Use this function to import a TOML file as NixOS configuration.
1295      modules.importTOML :: path -> attrs
1296   */
1297   importTOML = file: {
1298     _file = file;
1299     config = lib.importTOML file;
1300   };
1302   private = lib.mapAttrs
1303     (k: lib.warn "External use of `lib.modules.${k}` is deprecated. If your use case isn't covered by non-deprecated functions, we'd like to know more and perhaps support your use case well, instead of providing access to these low level functions. In this case please open an issue in https://github.com/nixos/nixpkgs/issues/.")
1304     {
1305       inherit
1306         applyModuleArgsIfFunction
1307         dischargeProperties
1308         evalOptionValue
1309         mergeModules
1310         mergeModules'
1311         pushDownProperties
1312         unifyModuleSyntax
1313         ;
1314       collectModules = collectModules null;
1315     };
1318 private //
1320   # NOTE: not all of these functions are necessarily public interfaces; some
1321   #       are just needed by types.nix, but are not meant to be consumed
1322   #       externally.
1323   inherit
1324     defaultOrderPriority
1325     defaultOverridePriority
1326     defaultPriority
1327     doRename
1328     evalModules
1329     filterOverrides
1330     filterOverrides'
1331     fixMergeModules
1332     fixupOptionType  # should be private?
1333     importJSON
1334     importTOML
1335     mergeDefinitions
1336     mergeAttrDefinitionsWithPrio
1337     mergeOptionDecls  # should be private?
1338     mkAfter
1339     mkAliasAndWrapDefinitions
1340     mkAliasAndWrapDefsWithPriority
1341     mkAliasDefinitions
1342     mkAliasIfDef
1343     mkAliasOptionModule
1344     mkAliasOptionModuleMD
1345     mkAssert
1346     mkBefore
1347     mkChangedOptionModule
1348     mkDefault
1349     mkDerivedConfig
1350     mkFixStrictness
1351     mkForce
1352     mkIf
1353     mkImageMediaOverride
1354     mkMerge
1355     mkMergedOptionModule
1356     mkOptionDefault
1357     mkOrder
1358     mkOverride
1359     mkRemovedOptionModule
1360     mkRenamedOptionModule
1361     mkRenamedOptionModuleWith
1362     mkVMOverride
1363     setDefaultModuleLocation
1364     sortProperties;