at 24.05-pre 55 kB view raw
1{ lib }: 2 3let 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 ; 51 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 )); 64 65 /* See https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules 66 or file://./../doc/module-system/module-system.chapter.md 67 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; 95 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; 108 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"; 118 119 key = _file; 120 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`. 143 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. 151 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` 159 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. 163 164 For this reason, callers of the module system can provide `specialArgs` 165 which are available during import resolution. 166 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 ``` 179 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 }; 185 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 }; 192 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. 202 203 If this is `null`, definitions without an option 204 will throw an error unless {option}`_module.check` is 205 turned off. 206 ''; 207 }; 208 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 }; 218 219 config = { 220 _module.args = { 221 inherit extendModules; 222 moduleType = type; 223 }; 224 _module.specialArgs = specialArgs; 225 }; 226 }; 227 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); 235 236 options = merged.matchedOptions; 237 238 config = 239 let 240 241 # For definitions that have an associated option 242 declaredConfig = mapAttrsRecursiveCond (v: ! isOption v) (_: v: v.value) options; 243 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; 253 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; 259 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} 285 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} 291 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; 298 299 checked = builtins.seq checkUnmatched; 300 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 }); 312 313 type = lib.types.submoduleWith { 314 inherit modules specialArgs class; 315 }; 316 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; 326 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 332 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); 353 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; 364 365 /* 366 Collects all modules recursively into the form 367 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); 406 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 419 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 427 428 else if m?key 429 then 430 m.key 431 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}."; 435 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 }); 442 443 in modulesPath: initialModules: args: 444 filterModules modulesPath (collectStructuredModules unknownModule "" initialModules args); 445 446 /* Wrap a module with a default location for reporting errors. */ 447 setDefaultModuleLocation = file: m: 448 { _file = file; imports = [ m ]; }; 449 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 }; 485 486 applyModuleArgsIfFunction = key: f: args@{ config, options, lib, ... }: 487 if isFunction f then applyModuleArgs key f args else f; 488 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); 508 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); 514 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. 520 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); 539 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); 562 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}'! 575 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; 583 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); 610 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 }; 626 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; 673 674 matchedOptions = mapAttrs (n: v: v.matchedOptions) resultsByName; 675 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; 684 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 }; 700 701 throwDeclarationTypeError = loc: actualTag: file: 702 let 703 name = lib.strings.escapeNixIdentifier (lib.lists.last loc); 704 path = showOption loc; 705 depth = length loc; 706 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 ''; 718 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); 726 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). 733 734 'loc' is the list of attribute names where the option is located. 735 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; 775 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; 784 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'; 797 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; 801 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}"; 805 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 }; 816 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; 825 826 # Process mkOverride properties. 827 defs'' = filterOverrides' defs'; 828 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; 840 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."; 851 852 isDefined = defsFinal != []; 853 854 optionalValue = 855 if isDefined then { value = mergedValue; } 856 else {}; 857 }; 858 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, 863 864 mkMerge [ { boot = set1; } (mkIf cond { boot = set2; services = set3; }) ] 865 866 is transformed into 867 868 [ { boot = set1; } { boot = mkIf cond set2; services = mkIf cond set3; } ]. 869 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 ]; 883 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 889 890 mkMerge [ 1 (mkIf true 2) (mkIf true (mkIf false 3)) ] 891 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 ]; 907 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, 912 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 ] 918 919 yields 920 921 [ { file = "/1"; value = "a"; } 922 { file = "/4"; value = "d"; } 923 ] 924 925 Note that "z" has the default priority 100. 926 */ 927 filterOverrides = defs: (filterOverrides' defs).values; 928 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 }; 938 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'; 951 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 = []; }; 959 960 961 /* 962 Merge an option's definitions in a way that preserves the priority of the 963 individual attributes in the option value. 964 965 This does not account for all option semantics, such as readOnly. 966 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; 994 995 /* Properties. */ 996 997 mkIf = condition: content: 998 { _type = "if"; 999 inherit condition content; 1000 }; 1001 1002 mkAssert = assertion: message: content: 1003 mkIf 1004 (if assertion then true else throw "\nFailed assertion: ${message}") 1005 content; 1006 1007 mkMerge = contents: 1008 { _type = "merge"; 1009 inherit contents; 1010 }; 1011 1012 mkOverride = priority: content: 1013 { _type = "override"; 1014 inherit priority content; 1015 }; 1016 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’ 1023 1024 defaultPriority = lib.warnIf (lib.isInOldestRelease 2305) "lib.modules.defaultPriority is deprecated, please use lib.modules.defaultOverridePriority instead." defaultOverridePriority; 1025 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; 1027 1028 mkOrder = priority: content: 1029 { _type = "order"; 1030 inherit priority content; 1031 }; 1032 1033 mkBefore = mkOrder 500; 1034 defaultOrderPriority = 1000; 1035 mkAfter = mkOrder 1500; 1036 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)); 1059 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)); 1069 1070 mkAliasIfDef = option: 1071 mkIf (isOption option && option.isDefined); 1072 1073 /* Compatibility. */ 1074 fixMergeModules = modules: args: evalModules { inherit modules args; check = false; }; 1075 1076 1077 /* Return a module that causes a warning to be shown if the 1078 specified option is defined. For example, 1079 1080 mkRemovedOptionModule [ "boot" "loader" "grub" "bootDevice" ] "<replacement instructions>" 1081 1082 causes a assertion if the user defines boot.loader.grub.bootDevice. 1083 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 }; 1104 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, 1109 1110 mkRenamedOptionModule [ "boot" "copyKernels" ] [ "boot" "loader" "grub" "copyKernels" ] 1111 1112 forwards any definitions of boot.copyKernels to 1113 boot.loader.grub.copyKernels while printing a warning. 1114 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 }; 1124 1125 mkRenamedOptionModuleWith = { 1126 /* Old option path as list of strings. */ 1127 from, 1128 /* New option path as list of strings. */ 1129 to, 1130 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, 1136 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 }; 1144 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. 1150 1151 "mergeFn" takes the module "config" as a parameter and must return a value 1152 of "to" option type. 1153 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") 1164 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 1169 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); 1181 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 }; 1196 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. 1203 1204 "mergeFn" takes the module "config" as a parameter and must return a value of 1205 "to" option type. 1206 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") 1213 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 1216 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; 1222 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 }; 1230 1231 /* Transitional version of mkAliasOptionModule that uses MD docs. 1232 1233 This function is no longer necessary and merely an alias of `mkAliasOptionModule`. 1234 */ 1235 mkAliasOptionModuleMD = mkAliasOptionModule; 1236 1237 /* mkDerivedConfig : Option a -> (a -> Definition b) -> Definition b 1238 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")`. 1243 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); 1256 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 }; 1283 1284 /* Use this function to import a JSON file as NixOS configuration. 1285 1286 modules.importJSON :: path -> attrs 1287 */ 1288 importJSON = file: { 1289 _file = file; 1290 config = lib.importJSON file; 1291 }; 1292 1293 /* Use this function to import a TOML file as NixOS configuration. 1294 1295 modules.importTOML :: path -> attrs 1296 */ 1297 importTOML = file: { 1298 _file = file; 1299 config = lib.importTOML file; 1300 }; 1301 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 }; 1316 1317in 1318private // 1319{ 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; 1365}