From 008632bc8bb4e54bfe3711978ab65ea05233d89f Mon Sep 17 00:00:00 2001 From: Jake Hamilton Date: Wed, 3 Jul 2024 00:35:21 -0700 Subject: [PATCH] feat: working transient deps --- foundation/flake.lock | 8 +- lib/src/options/default.nix | 495 ++++++------ lib/src/types/default.nix | 39 +- tidepool/flake.lock | 16 +- tidepool/src/builders/basic.nix | 8 +- tidepool/src/export.nix | 13 +- tidepool/src/lib/packages.nix | 110 ++- tidepool/src/lib/systems.nix | 1239 +++++++++++++++-------------- tidepool/src/lib/types.nix | 589 ++++++-------- tidepool/src/packages/aux/a.nix | 2 + tidepool/src/packages/aux/b.nix | 13 +- tidepool/src/packages/default.nix | 77 +- 12 files changed, 1300 insertions(+), 1309 deletions(-) diff --git a/foundation/flake.lock b/foundation/flake.lock index ba8c053..37bbbad 100644 --- a/foundation/flake.lock +++ b/foundation/flake.lock @@ -3,10 +3,10 @@ "lib": { "locked": { "dir": "lib", - "dirtyRev": "a707b0f06be6b36bcbfe88d0a9a5b9a803983a06-dirty", - "dirtyShortRev": "a707b0f-dirty", - "lastModified": 1719079124, - "narHash": "sha256-4HwA3q5f7SUBmcXX9Vz9WsA9oHBQ/GiZTwE4iSVq9s8=", + "dirtyRev": "2be3111b2c0911f40b47fe0a1fb22b5f5188cf59-dirty", + "dirtyShortRev": "2be3111-dirty", + "lastModified": 1719251485, + "narHash": "sha256-63NvfFVeTDITfNu60rmCUlaZtAeZUnvrIaOLSk9ScC8=", "type": "git", "url": "file:../?dir=lib" }, diff --git a/lib/src/options/default.nix b/lib/src/options/default.nix index 6b8ce80..fe703d8 100644 --- a/lib/src/options/default.nix +++ b/lib/src/options/default.nix @@ -4,184 +4,166 @@ lib: { ## Merge a list of option definitions into a single value. ## ## @type Location -> List Definition -> Any - default = - location: definitions: - let - values = lib.options.getDefinitionValues definitions; - first = builtins.elemAt values 0; - mergedFunctions = x: lib.options.mergeDefault location (builtins.map (f: f x) values); - mergedLists = builtins.concatLists values; - mergedAttrs = builtins.foldl' lib.attrs.merge { } values; - mergedBools = builtins.any lib.bools.or false values; - mergedStrings = lib.strings.concat values; - in - if builtins.length values == 1 then - builtins.elemAt values 0 - else if builtins.all builtins.isFunction values then - mergedFunctions - else if builtins.all builtins.isList values then - mergedLists - else if builtins.all builtins.isAttrs values then - mergedAttrs - else if builtins.all builtins.isBool values then - mergedBools - else if builtins.all lib.strings.isString values then - mergedStrings - else if builtins.all builtins.isInt values && builtins.all (x: x == first) values then - first + default = location: definitions: let + values = lib.options.getDefinitionValues definitions; + first = builtins.elemAt values 0; + mergedFunctions = x: lib.options.mergeDefault location (builtins.map (f: f x) values); + mergedLists = builtins.concatLists values; + mergedAttrs = builtins.foldl' lib.attrs.merge {} values; + mergedBools = builtins.any lib.bools.or false values; + mergedStrings = lib.strings.concat values; + in + if builtins.length values == 1 + then builtins.elemAt values 0 + else if builtins.all builtins.isFunction values + then mergedFunctions + else if builtins.all builtins.isList values + then mergedLists + else if builtins.all builtins.isAttrs values + then mergedAttrs + else if builtins.all builtins.isBool values + then mergedBools + else if builtins.all lib.strings.isString values + then mergedStrings + else if builtins.all builtins.isInt values && builtins.all (x: x == first) values + then first # TODO: Improve this error message to show the location and definitions for the option. - else - builtins.throw "Cannot merge definitions."; + else builtins.throw "Cannot merge definitions."; ## Merge multiple option definitions together. ## ## @type Location -> Type -> List Definition - definitions = - location: type: definitions: - let - identifier = lib.options.getIdentifier location; - resolve = - definition: - let - properties = builtins.addErrorContext "while evaluating definitions from `${definition.__file__}`:" ( - lib.modules.apply.properties definition.value - ); - normalize = value: { - __file__ = definition.__file__; - inherit value; - }; - in - builtins.map normalize properties; - - resolved = builtins.concatMap resolve definitions; - overridden = lib.modules.apply.overrides resolved; - - values = - if builtins.any (definition: lib.types.is "order" definition.value) overridden.values then - lib.modules.apply.order overridden.values - else - overridden.values; - - isDefined = values != [ ]; - - invalid = builtins.filter (definition: !(type.check definition.value)) values; - - merged = - if isDefined then - if builtins.all (definition: type.check definition.value) values then - type.merge location values - else - builtins.throw "A definition for `${identifier}` is not of type `${type.description}`. Definition values:${lib.options.getDefinitions invalid}" - else - builtins.throw "The option `${identifier}` is used but not defined."; - - optional = if isDefined then { value = merged; } else { }; - in - { - inherit - isDefined - values - merged - optional - ; - - raw = { - inherit values; - inherit (overridden) highestPriority; + definitions = location: type: definitions: let + identifier = lib.options.getIdentifier location; + resolve = definition: let + properties = builtins.addErrorContext "while evaluating definitions from `${definition.__file__ or ""}`:" ( + lib.modules.apply.properties definition.value + ); + normalize = value: { + __file__ = definition.__file__; + inherit value; }; + in + builtins.map normalize properties; + + resolved = builtins.concatMap resolve definitions; + overridden = lib.modules.apply.overrides resolved; + + values = + if builtins.any (definition: lib.types.is "order" definition.value) overridden.values + then lib.modules.apply.order overridden.values + else overridden.values; + + isDefined = values != []; + + invalid = builtins.filter (definition: !(type.check definition.value)) values; + + merged = + if isDefined + then + if builtins.all (definition: type.check definition.value) values + then type.merge location values + else builtins.throw "A definition for `${identifier}` is not of type `${type.description}`. Definition values:${lib.options.getDefinitions invalid}" + else builtins.throw "The option `${identifier}` is used but not defined."; + + optional = + if isDefined + then {value = merged;} + else {}; + in { + inherit + isDefined + values + merged + optional + ; + + raw = { + inherit values; + inherit (overridden) highestPriority; }; + }; ## Merge multiple option declarations together. ## ## @type Location -> List Option - declarations = - location: options: - let - merge = - result: option: - let - mergedType = result.type.mergeType option.options.type.functor; - isTypeMergeable = mergedType != null; - shared = name: option.options ? ${name} && result ? ${name}; - typeSet = lib.attrs.when ((shared "type") && isTypeMergeable) { type = mergedType; }; - files = result.declarations; - serializedFiles = builtins.concatStringsSep " and " files; - getSubModules = option.options.type.getSubModules or null; - submodules = - if getSubModules != null then - builtins.map (module: { - __file__ = option.__file__; - includes = [ module ]; - }) getSubModules - ++ result.options - else - result.options; - in - if - shared "default" - || shared "example" - || shared "description" - || shared "apply" - || (shared "type" && !isTypeMergeable) + declarations = location: options: let + merge = result: option: let + mergedType = result.type.mergeType option.options.type.functor; + isTypeMergeable = mergedType != null; + shared = name: option.options ? ${name} && result ? ${name}; + typeSet = lib.attrs.when ((shared "type") && isTypeMergeable) {type = mergedType;}; + files = result.declarations; + serializedFiles = builtins.concatStringsSep " and " files; + getSubModules = option.options.type.getSubModules or null; + submodules = + if getSubModules != null then - builtins.throw "The option `${lib.options.getIdentifier location}` in `${option.__file__}` is already declared in ${serializedFiles}" - else - option.options - // result - // { - declarations = result.declarations ++ [ option.__file__ ]; - options = submodules; - } - // typeSet; + builtins.map (module: { + __file__ = option.__file__; + includes = [module]; + }) + getSubModules + ++ result.options + else result.options; in + if + shared "default" + || shared "example" + || shared "description" + || shared "apply" + || (shared "type" && !isTypeMergeable) + then builtins.throw "The option `${lib.options.getIdentifier location}` in `${option.__file__}` is already declared in ${serializedFiles}" + else + option.options + // result + // { + declarations = result.declarations ++ [option.__file__]; + options = submodules; + } + // typeSet; + in builtins.foldl' merge { inherit location; - declarations = [ ]; - options = [ ]; - } options; + declarations = []; + options = []; + } + options; ## Merge an option, only supporting a single unique definition. ## ## @type String -> Location -> List Definition -> Any - unique = - message: location: definitions: - let - identifier = lib.options.getIdentifier location; - total = builtins.length definitions; - first = builtins.elemAt definitions 0; - in - if total == 1 then - first.value - else if total == 0 then - builtins.throw "Cannot merge unused option `${identifier}`.\n${message}" - else - builtins.throw "The option `${identifier}` is defined multiple times, but must be unique.\n${message}\nDefinitions:${lib.options.getDefinitions definitions}"; + unique = message: location: definitions: let + identifier = lib.options.getIdentifier location; + total = builtins.length definitions; + first = builtins.elemAt definitions 0; + in + if total == 1 + then first.value + else if total == 0 + then builtins.throw "Cannot merge unused option `${identifier}`.\n${message}" + else builtins.throw "The option `${identifier}` is defined multiple times, but must be unique.\n${message}\nDefinitions:${lib.options.getDefinitions definitions}"; ## Merge a single instance of an option. ## ## @type Location -> List Definition -> Any one = lib.options.merge.unique ""; - equal = - location: definitions: - let - identifier = lib.options.getIdentifier location; - first = builtins.elemAt definitions 0; - rest = builtins.tail definitions; - merge = - x: y: - if x != y then - builtins.throw "The option `${identifier}` has conflicting definitions:${lib.options.getDefinitions definitions}" - else - x; - merged = builtins.foldl' merge first rest; - in - if builtins.length definitions == 0 then - builtins.throw "Cannot merge unused option `${identifier}`." - else if builtins.length definitions == 1 then - first.value - else - merged.value; + equal = location: definitions: let + identifier = lib.options.getIdentifier location; + first = builtins.elemAt definitions 0; + rest = builtins.tail definitions; + merge = x: y: + if x != y + then builtins.throw "The option `${identifier}` has conflicting definitions:${lib.options.getDefinitions definitions}" + else x; + merged = builtins.foldl' merge first rest; + in + if builtins.length definitions == 0 + then builtins.throw "Cannot merge unused option `${identifier}`." + else if builtins.length definitions == 1 + then first.value + else merged.value; }; ## Check whether a value is an option. @@ -192,50 +174,46 @@ lib: { ## Create an option. ## ## @type { type? :: String | Null, apply? :: (a -> b) | Null, default? :: { value :: a, text :: String }, example? :: String | Null, visible? :: Bool | Null, internal? :: Bool | Null, writable? :: Bool | Null, description? :: String | Null } -> Option a - create = - settings@{ - type ? lib.types.unspecified, - apply ? null, - default ? { }, - example ? null, - visible ? null, - internal ? null, - writable ? null, - description ? null, - }: - { - __type__ = "option"; - inherit - type - apply - default - example - visible - internal - writable - description - ; - }; + create = settings @ { + type ? lib.types.unspecified, + apply ? null, + default ? {}, + example ? null, + visible ? null, + internal ? null, + writable ? null, + description ? null, + }: { + __type__ = "option"; + inherit + type + apply + default + example + visible + internal + writable + description + ; + }; ## Create a sink option. ## ## @type @alias lib.options.create - sink = - settings: - let - defaults = { - internal = true; - visible = false; - default = false; - description = "A sink option for unused definitions"; - type = lib.types.create { - name = "sink"; - check = lib.fp.const true; - merge = lib.fp.const (lib.fp.const false); - }; - apply = value: builtins.throw "Cannot read the value of a Sink option."; + sink = settings: let + defaults = { + internal = true; + visible = false; + default = false; + description = "A sink option for unused definitions"; + type = lib.types.create { + name = "sink"; + check = lib.fp.const true; + merge = lib.fp.const (lib.fp.const false); }; - in + apply = value: builtins.throw "Cannot read the value of a Sink option."; + }; + in lib.options.create (defaults // settings); ## Get the definition values from a list of options definitions. @@ -246,94 +224,93 @@ lib: { ## Convert a list of option identifiers into a single identifier. ## ## @type List String -> String - getIdentifier = - location: - let - special = [ - # lib.types.attrs.of (lib.types.submodule {}) - "" - # lib.types.list.of (submodule {}) - "*" - # lib.types.function - "" - ]; - escape = part: if builtins.elem part special then part else lib.strings.escape.nix.identifier part; - in + getIdentifier = location: let + special = [ + # lib.types.attrs.of (lib.types.submodule {}) + "" + # lib.types.list.of (submodule {}) + "*" + # lib.types.function + "" + ]; + escape = part: + if builtins.elem part special + then part + else lib.strings.escape.nix.identifier part; + in lib.strings.concatMapSep "." escape location; ## Get a string message of the definitions for an option. ## ## @type List Definition -> String - getDefinitions = - definitions: - let - serialize = - definition: - let - valueWithRecursionLimit = lib.generators.withRecursion { - limit = 10; - throw = false; - } definition.value; + getDefinitions = definitions: let + serialize = definition: let + valueWithRecursionLimit = + lib.generators.withRecursion { + limit = 10; + throw = false; + } + definition.value; - eval = builtins.tryEval (lib.generators.pretty { } valueWithRecursionLimit); + eval = builtins.tryEval (lib.generators.pretty {} valueWithRecursionLimit); - lines = lib.strings.split "\n" eval.value; - linesLength = builtins.length lines; - firstFiveLines = lib.lists.take 5 lines; + lines = lib.strings.split "\n" eval.value; + linesLength = builtins.length lines; + firstFiveLines = lib.lists.take 5 lines; - ellipsis = lib.lists.when (linesLength > 5) "..."; + ellipsis = lib.lists.when (linesLength > 5) "..."; - value = builtins.concatStringsSep "\n " (firstFiveLines ++ ellipsis); + value = builtins.concatStringsSep "\n " (firstFiveLines ++ ellipsis); - result = - if !eval.success then - "" - else if linesLength > 1 then - ":\n " + value - else - ": " + value; - in - "\n- In `${definition.__file__}`${result}"; - in + result = + if !eval.success + then "" + else if linesLength > 1 + then ":\n " + value + else ": " + value; + in "\n- In `${definition.__file__}`${result}"; + in lib.strings.concatMap serialize definitions; ## Run a set of definitions, calculating the resolved value and associated information. ## ## @type Location -> Option -> List Definition -> String & { value :: Any, highestPriority :: Int, isDefined :: Bool, files :: List String, definitions :: List Any, definitionsWithLocations :: List Definition } - run = - location: option: definitions: - let - identifier = lib.options.getIdentifier location; + run = location: option: definitions: let + identifier = lib.options.getIdentifier location; - definitionsWithDefault = - if option ? default && option.default ? value then - [ - { - __file__ = builtins.head option.declarations; - value = lib.modules.overrides.option option.default.value; - } - ] - ++ definitions - else - definitions; + definitionsWithDefault = + if option ? default && option.default ? value + then + [ + { + __file__ = builtins.head option.declarations; + value = lib.modules.overrides.option option.default.value; + } + ] + ++ definitions + else definitions; - merged = - if option.writable or null == false && builtins.length definitionsWithDefault > 1 then - let - separatedDefinitions = builtins.map ( - definition: + merged = + if option.writable or null == false && builtins.length definitionsWithDefault > 1 + then let + separatedDefinitions = + builtins.map ( + definition: definition // { - value = (lib.options.merge.definitions location option.type [ definition ]).merged; + value = (lib.options.merge.definitions location option.type [definition]).merged; } - ) definitionsWithDefault; - in - builtins.throw "The option `${identifier}` is not writable, but is set more than once:${lib.options.getDefinitions separatedDefinitions}" - else - lib.options.merge.definitions location option.type definitionsWithDefault; + ) + definitionsWithDefault; + in + builtins.throw "The option `${identifier}` is not writable, but is set more than once:${lib.options.getDefinitions separatedDefinitions}" + else lib.options.merge.definitions location option.type definitionsWithDefault; - value = if option.apply or null != null then option.apply merged.merged else merged.merged; - in + value = + if option.apply or null != null + then option.apply merged.merged + else merged.merged; + in option // { value = builtins.addErrorContext "while evaluating the option `${identifier}`:" value; diff --git a/lib/src/types/default.nix b/lib/src/types/default.nix index 94f89fa..b136f66 100644 --- a/lib/src/types/default.nix +++ b/lib/src/types/default.nix @@ -1048,7 +1048,7 @@ lib: { merge = location: definitions: let process = value: if initial.check value - then (builtins.trace "transforming...") transform value + then transform value else value; normalize = definition: definition // {value = process definition.value;}; normalized = builtins.map normalize definitions; @@ -1068,6 +1068,43 @@ lib: { }; }; + ## Create a type that allows a value which is either the final type or is transformable + ## to the final type. + ## + ## @type Attrs -> (Any -> Any) -> Attrs -> Attrs + coerceWithLocation = initial: transform: final: let + in + if initial.getSubModules != null + then builtins.throw "lib.types.coerceWithLocation's first argument may not have submodules, but got ${initial.description}" + else + lib.types.create { + name = "Coerce"; + description = "${initial.description} that is transformed to ${final.description}"; + fallback = final.fallback; + check = value: final.check value || (initial.check value && final.check (transform [] value)); + merge = location: definitions: let + process = value: + if initial.check value + then transform location value + else value; + normalize = definition: definition // {value = process definition.value;}; + normalized = builtins.map normalize definitions; + in + final.merge location normalized; + getSubOptions = final.getSubOptions; + getSubModules = final.getSubModules; + withSubModules = modules: lib.types.coerceWithLocation initial transform (final.withSubModules modules); + mergeType = x: y: null; + functor = + lib.types.functor "coerceWithLocation" + // { + wrapped = final; + }; + children = { + inherit initial final; + }; + }; + dag = { ## Create a type that allows a DAG (Directed Acyclic Graph) of a given type. ## diff --git a/tidepool/flake.lock b/tidepool/flake.lock index 31590e0..add5ace 100644 --- a/tidepool/flake.lock +++ b/tidepool/flake.lock @@ -8,10 +8,10 @@ }, "locked": { "dir": "foundation", - "dirtyRev": "a707b0f06be6b36bcbfe88d0a9a5b9a803983a06-dirty", - "dirtyShortRev": "a707b0f-dirty", - "lastModified": 1719079124, - "narHash": "sha256-hz9vVcHSvlq/W01UOh/GqPFUoH9DzCFB16n23oj7fnQ=", + "dirtyRev": "2be3111b2c0911f40b47fe0a1fb22b5f5188cf59-dirty", + "dirtyShortRev": "2be3111-dirty", + "lastModified": 1719251485, + "narHash": "sha256-9G1TPBdlQNXCZf6A66bCT9m2vhodkSF+rDtqOVuFteY=", "type": "git", "url": "file:../?dir=foundation" }, @@ -24,10 +24,10 @@ "lib": { "locked": { "dir": "lib", - "dirtyRev": "a707b0f06be6b36bcbfe88d0a9a5b9a803983a06-dirty", - "dirtyShortRev": "a707b0f-dirty", - "lastModified": 1719079124, - "narHash": "sha256-hz9vVcHSvlq/W01UOh/GqPFUoH9DzCFB16n23oj7fnQ=", + "dirtyRev": "2be3111b2c0911f40b47fe0a1fb22b5f5188cf59-dirty", + "dirtyShortRev": "2be3111-dirty", + "lastModified": 1719251485, + "narHash": "sha256-9G1TPBdlQNXCZf6A66bCT9m2vhodkSF+rDtqOVuFteY=", "type": "git", "url": "file:../?dir=lib" }, diff --git a/tidepool/src/builders/basic.nix b/tidepool/src/builders/basic.nix index 5e623d1..1a8d460 100644 --- a/tidepool/src/builders/basic.nix +++ b/tidepool/src/builders/basic.nix @@ -83,7 +83,13 @@ in { } ); in - built // {inherit (package) meta;}; + built + // { + inherit (package) meta; + extras = { + inherit package; + }; + }; }; }; } diff --git a/tidepool/src/export.nix b/tidepool/src/export.nix index d2da3e5..fc93d4e 100644 --- a/tidepool/src/export.nix +++ b/tidepool/src/export.nix @@ -1,16 +1,13 @@ # This file handles creating all of the exports for this project and is not # exported itself. -{ - lib, - config, -}: let - lib' = config.lib; +{config}: let + inherit (config) lib; in { - freeform = lib.types.any; + # freeform = lib.types.any; config = { exports = { - lib = config.lib; + inherit lib; modules = import ./modules.nix; packages = { @@ -25,7 +22,7 @@ in { # }; # })) # .config; - # foundation-gcc = config.packages.foundation.gcc; + foundation-gcc = config.packages.foundation.gcc; # foundation-binutils = config.packages.foundation.binutils; # foundation-linux-headers = config.packages.foundation.linux-headers.versions.latest.extend { # platform.host = lib.modules.overrides.force "x86_64-linux"; diff --git a/tidepool/src/lib/packages.nix b/tidepool/src/lib/packages.nix index 9592292..786e65c 100644 --- a/tidepool/src/lib/packages.nix +++ b/tidepool/src/lib/packages.nix @@ -1,8 +1,9 @@ { lib, - lib', config, -}: { +}: let + lib' = config.lib; +in { config = { lib.packages = { dependencies = { @@ -20,52 +21,85 @@ in builtins.head sorted; - resolve = package: - if package ? versions + resolve = alias: + if alias ? versions then - package.versions.${config.preferences.packages.version} - or (package.versions.${lib'.packages.getLatest package}) - else package; + alias.versions.${config.preferences.packages.version} + or (alias.versions.${lib'.packages.getLatest alias}) + else alias; - build = package: build: host: target: let - resolved = lib'.packages.resolve package; + build = alias: build: host: target: let + package = lib'.packages.resolve alias; buildDependencies = build': host': target': builtins.mapAttrs (name: dep: lib'.packages.build dep build' host' target'); - result = resolved.extend ( - {config}: { - config = { - platform = { - build = build; - host = host; - target = lib.modules.override 150 target; - }; + result = lib.modules.run { + modules = + package.__modules__ + ++ [ + lib'.types.package.children.submodule + ( + {config}: { + config = { + __modules__ = package.__modules__; + platform = { + build = lib.modules.overrides.force (lib'.systems.withBuildInfo build); + host = lib.modules.overrides.force (lib'.systems.withBuildInfo host); + target = lib.modules.overrides.force (lib'.systems.withBuildInfo target); + }; - deps = { - build = { - only = buildDependencies build build build resolved.deps.build.only; - build = buildDependencies build build target resolved.deps.build.build; - host = buildDependencies build host target resolved.deps.build.host; - target = buildDependencies build target target resolved.deps.build.target; - }; - host = { - only = buildDependencies host host host resolved.deps.host.only; - host = buildDependencies host host target resolved.deps.host.host; - target = buildDependencies host target target resolved.deps.host.target; - }; - target = { - only = buildDependencies target target target resolved.deps.target.only; - target = buildDependencies target target target resolved.deps.target.target; - }; - }; + # NOTE: This does not seem to work and instead the pre-existing deps are used. + # This causes an issue because the platforms will be wrong. + # deps = { + # build = { + # only = buildDependencies build build build package.deps.build.only; + # build = buildDependencies build build target package.deps.build.build; + # host = buildDependencies build host target package.deps.build.host; + # target = buildDependencies build target target package.deps.build.target; + # }; + # host = { + # only = buildDependencies host host host package.deps.host.only; + # host = buildDependencies host host target package.deps.host.host; + # target = buildDependencies host target target package.deps.host.target; + # }; + # target = { + # only = buildDependencies target target target package.deps.target.only; + # target = buildDependencies target target target package.deps.target.target; + # }; + # }; + }; + } + ) + ]; + }; - package = config.builder.build config; + resolved = + result.config + // { + deps = { + build = { + only = buildDependencies build build build package.deps.build.only; + build = buildDependencies build build target package.deps.build.build; + host = buildDependencies build host target package.deps.build.host; + target = buildDependencies build target target package.deps.build.target; + }; + host = { + only = buildDependencies host host host package.deps.host.only; + host = buildDependencies host host target package.deps.host.host; + target = buildDependencies host target target package.deps.host.target; + }; + target = { + only = buildDependencies target target target package.deps.target.only; + target = buildDependencies target target target package.deps.target.target; + }; }; - } - ); + }; in - result; + resolved + // { + package = resolved.builder.build resolved; + }; }; }; } diff --git a/tidepool/src/lib/systems.nix b/tidepool/src/lib/systems.nix index a1a1408..0c99f98 100644 --- a/tidepool/src/lib/systems.nix +++ b/tidepool/src/lib/systems.nix @@ -1,34 +1,34 @@ -{ lib, config }: -let +{ + lib, + config, +}: let lib' = config.lib; types = config.lib.systems.types; - setTypes = - type: - let - assign = - name: value: - assert lib.errors.trace (type.check value) - "${name} is not of type ${type.name}: ${lib.generators.pretty { } value}"; - lib.types.set type.name ({ inherit name; } // value); - in + setTypes = type: let + assign = name: value: + assert lib.errors.trace (type.check value) + "${name} is not of type ${type.name}: ${lib.generators.pretty {} value}"; + lib.types.set type.name ({inherit name;} // value); + in builtins.mapAttrs assign; - matchAnyAttrs = - patterns: - if builtins.isList patterns then + matchAnyAttrs = patterns: + if builtins.isList patterns + then value: - builtins.any ( - pattern: if builtins.isFunction pattern then pattern value else matchAnyAttrs pattern value - ) patterns - else - lib.attrs.match patterns; + builtins.any ( + pattern: + if builtins.isFunction pattern + then pattern value + else matchAnyAttrs pattern value + ) + patterns + else lib.attrs.match patterns; - getDoubles = - predicate: + getDoubles = predicate: builtins.map lib'.systems.into.double (builtins.filter predicate lib'.systems.doubles.all); -in -{ +in { config = { lib.systems = { match = builtins.mapAttrs (lib.fp.const matchAnyAttrs) lib'.systems.patterns; @@ -89,7 +89,7 @@ in UBIFS_FS_ZLIB y UBIFS_FS_DEBUG n ''; - makeFlags = [ "LOADADDR=0x8000" ]; + makeFlags = ["LOADADDR=0x8000"]; target = "uImage"; # TODO reenable once manual-config's config actually builds a .dtb and this is checked to be working #DTB = true; @@ -203,7 +203,7 @@ in KGDB_SERIAL_CONSOLE y KGDB_KDB y ''; - makeFlags = [ "LOADADDR=0x0200000" ]; + makeFlags = ["LOADADDR=0x0200000"]; target = "uImage"; DTB = true; # Beyond 3.10 }; @@ -291,7 +291,7 @@ in UBIFS_FS_ZLIB y UBIFS_FS_DEBUG n ''; - makeFlags = [ "LOADADDR=0x10800000" ]; + makeFlags = ["LOADADDR=0x10800000"]; target = "uImage"; DTB = true; }; @@ -600,52 +600,51 @@ in }; }; - mipsel-linux-gnu = { - triple = "mipsel-unknown-linux-gnu"; - } // lib'.systems.platforms.gcc_mips32r2_o32; + mipsel-linux-gnu = + { + triple = "mipsel-unknown-linux-gnu"; + } + // lib'.systems.platforms.gcc_mips32r2_o32; # This function takes a minimally-valid "platform" and returns an # attrset containing zero or more additional attrs which should be # included in the platform in order to further elaborate it. - select = - platform: - # x86 - if platform.isx86 then - lib'.systems.platforms.pc + select = platform: + # x86 + if platform.isx86 + then lib'.systems.platforms.pc # ARM - else if platform.isAarch32 then - let - version = platform.system.cpu.version or null; - in - if version == null then - lib'.systems.platforms.pc - else if lib.versions.gte "6" version then - lib'.systems.platforms.sheevaplug - else if lib.versions.gte "7" version then - lib'.systems.platforms.raspberrypi - else - lib'.systems.platforms.armv7l-hf-multiplatform - else if platform.isAarch64 then - if platform.isDarwin then - lib'.systems.platforms.apple-m1 - else - lib'.systems.platforms.aarch64-multiplatform - else if platform.isRiscV then - lib'.systems.platforms.riscv-multiplatform - else if platform.system.cpu == types.cpus.mipsel then - lib'.systems.platforms.mipsel-linux-gnu - else if platform.system.cpu == types.cpus.powerpc64le then - lib'.systems.platforms.powernv - else - { }; + else if platform.isAarch32 + then let + version = platform.system.cpu.version or null; + in + if version == null + then lib'.systems.platforms.pc + else if lib.versions.gte "6" version + then lib'.systems.platforms.sheevaplug + else if lib.versions.gte "7" version + then lib'.systems.platforms.raspberrypi + else lib'.systems.platforms.armv7l-hf-multiplatform + else if platform.isAarch64 + then + if platform.isDarwin + then lib'.systems.platforms.apple-m1 + else lib'.systems.platforms.aarch64-multiplatform + else if platform.isRiscV + then lib'.systems.platforms.riscv-multiplatform + else if platform.system.cpu == types.cpus.mipsel + then lib'.systems.platforms.mipsel-linux-gnu + else if platform.system.cpu == types.cpus.powerpc64le + then lib'.systems.platforms.powernv + else {}; }; architectures = { features = { # x86_64 Generic # Spec: https://gitlab.com/x86-psABIs/x86-64-ABI/ - default = [ ]; - x86-64 = [ ]; + default = []; + x86-64 = []; x86-64-v2 = [ "sse3" "ssse3" @@ -925,29 +924,29 @@ in "fma" ]; # other - armv5te = [ ]; - armv6 = [ ]; - armv7-a = [ ]; - armv8-a = [ ]; - mips32 = [ ]; - loongson2f = [ ]; + armv5te = []; + armv6 = []; + armv7-a = []; + armv8-a = []; + mips32 = []; + loongson2f = []; }; # a superior CPU has all the features of an inferior and is able to build and test code for it inferiors = { # x86_64 Generic - default = [ ]; - x86-64 = [ ]; - x86-64-v2 = [ "x86-64" ]; - x86-64-v3 = [ "x86-64-v2" ] ++ lib'.systems.architectures.inferiors.x86-64-v2; - x86-64-v4 = [ "x86-64-v3" ] ++ lib'.systems.architectures.inferiors.x86-64-v3; + default = []; + x86-64 = []; + x86-64-v2 = ["x86-64"]; + x86-64-v3 = ["x86-64-v2"] ++ lib'.systems.architectures.inferiors.x86-64-v2; + x86-64-v4 = ["x86-64-v3"] ++ lib'.systems.architectures.inferiors.x86-64-v3; # x86_64 Intel # https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html - nehalem = [ "x86-64-v2" ] ++ lib'.systems.architectures.inferiors.x86-64-v2; - westmere = [ "nehalem" ] ++ lib'.systems.architectures.inferiors.nehalem; - sandybridge = [ "westmere" ] ++ lib'.systems.architectures.inferiors.westmere; - ivybridge = [ "sandybridge" ] ++ lib'.systems.architectures.inferiors.sandybridge; + nehalem = ["x86-64-v2"] ++ lib'.systems.architectures.inferiors.x86-64-v2; + westmere = ["nehalem"] ++ lib'.systems.architectures.inferiors.nehalem; + sandybridge = ["westmere"] ++ lib'.systems.architectures.inferiors.westmere; + ivybridge = ["sandybridge"] ++ lib'.systems.architectures.inferiors.sandybridge; haswell = lib.unique ( [ @@ -957,8 +956,8 @@ in ++ lib'.systems.architectures.inferiors.ivybridge ++ lib'.systems.architectures.inferiors.x86-64-v3 ); - broadwell = [ "haswell" ] ++ lib'.systems.architectures.inferiors.haswell; - skylake = [ "broadwell" ] ++ lib'.systems.architectures.inferiors.broadwell; + broadwell = ["haswell"] ++ lib'.systems.architectures.inferiors.haswell; + skylake = ["broadwell"] ++ lib'.systems.architectures.inferiors.broadwell; skylake-avx512 = lib.unique ( [ @@ -968,24 +967,24 @@ in ++ lib'.systems.architectures.inferiors.skylake ++ lib'.systems.architectures.inferiors.x86-64-v4 ); - cannonlake = [ "skylake-avx512" ] ++ lib'.systems.architectures.inferiors.skylake-avx512; - icelake-client = [ "cannonlake" ] ++ lib'.systems.architectures.inferiors.cannonlake; - icelake-server = [ "icelake-client" ] ++ lib'.systems.architectures.inferiors.icelake-client; - cascadelake = [ "cannonlake" ] ++ lib'.systems.architectures.inferiors.cannonlake; - cooperlake = [ "cascadelake" ] ++ lib'.systems.architectures.inferiors.cascadelake; - tigerlake = [ "icelake-server" ] ++ lib'.systems.architectures.inferiors.icelake-server; + cannonlake = ["skylake-avx512"] ++ lib'.systems.architectures.inferiors.skylake-avx512; + icelake-client = ["cannonlake"] ++ lib'.systems.architectures.inferiors.cannonlake; + icelake-server = ["icelake-client"] ++ lib'.systems.architectures.inferiors.icelake-client; + cascadelake = ["cannonlake"] ++ lib'.systems.architectures.inferiors.cannonlake; + cooperlake = ["cascadelake"] ++ lib'.systems.architectures.inferiors.cascadelake; + tigerlake = ["icelake-server"] ++ lib'.systems.architectures.inferiors.icelake-server; # CX16 does not exist on alderlake, while it does on nearly all other intel CPUs - alderlake = [ ]; + alderlake = []; # x86_64 AMD # TODO: fill this (need testing) - btver1 = [ ]; - btver2 = [ ]; - bdver1 = [ ]; - bdver2 = [ ]; - bdver3 = [ ]; - bdver4 = [ ]; + btver1 = []; + btver2 = []; + bdver1 = []; + bdver2 = []; + bdver3 = []; + bdver4 = []; # Regarding `skylake` as inferior of `znver1`, there are reports of # successful usage by Gentoo users and Phoronix benchmarking of different # `-march` targets. @@ -1005,9 +1004,9 @@ in # https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html # https://en.wikichip.org/wiki/amd/microarchitectures/zen # https://en.wikichip.org/wiki/intel/microarchitectures/skylake - znver1 = [ "skylake" ] ++ lib'.systems.architectures.inferiors.skylake; # Includes haswell and x86-64-v3 - znver2 = [ "znver1" ] ++ lib'.systems.architectures.inferiors.znver1; - znver3 = [ "znver2" ] ++ lib'.systems.architectures.inferiors.znver2; + znver1 = ["skylake"] ++ lib'.systems.architectures.inferiors.skylake; # Includes haswell and x86-64-v3 + znver2 = ["znver1"] ++ lib'.systems.architectures.inferiors.znver1; + znver3 = ["znver2"] ++ lib'.systems.architectures.inferiors.znver2; znver4 = lib.unique ( [ "znver3" @@ -1018,36 +1017,33 @@ in ); # other - armv5te = [ ]; - armv6 = [ ]; - armv7-a = [ ]; - armv8-a = [ ]; - mips32 = [ ]; - loongson2f = [ ]; + armv5te = []; + armv6 = []; + armv7-a = []; + armv8-a = []; + mips32 = []; + loongson2f = []; }; }; validate = { - architecture = - let - isSupported = feature: x: builtins.elem feature (lib'.systems.architectures.features.${x} or [ ]); - in - { - sse3Support = isSupported "sse3"; - ssse3Support = isSupported "ssse3"; - sse4_1Support = isSupported "sse4_1"; - sse4_2Support = isSupported "sse4_2"; - sse4_aSupport = isSupported "sse4a"; - avxSupport = isSupported "avx"; - avx2Support = isSupported "avx2"; - avx512Support = isSupported "avx512"; - aesSupport = isSupported "aes"; - fmaSupport = isSupported "fma"; - fma4Support = isSupported "fma4"; - }; + architecture = let + isSupported = feature: x: builtins.elem feature (lib'.systems.architectures.features.${x} or []); + in { + sse3Support = isSupported "sse3"; + ssse3Support = isSupported "ssse3"; + sse4_1Support = isSupported "sse4_1"; + sse4_2Support = isSupported "sse4_2"; + sse4_aSupport = isSupported "sse4a"; + avxSupport = isSupported "avx"; + avx2Support = isSupported "avx2"; + avx512Support = isSupported "avx512"; + aesSupport = isSupported "aes"; + fmaSupport = isSupported "fma"; + fma4Support = isSupported "fma4"; + }; - compatible = - a: b: + compatible = a: b: lib.any lib.id [ # x86 ( @@ -1062,96 +1058,114 @@ in # XXX: Not true in some cases. Like in WSL mode. ( - b == lib'.systems.types.cpus.i686 + b + == lib'.systems.types.cpus.i686 && lib'.systems.validate.compatible a lib'.systems.types.cpus.x86_64 ) # ARMv4 ( - b == lib'.systems.types.cpus.arm + b + == lib'.systems.types.cpus.arm && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv5tel ) # ARMv5 ( - b == lib'.systems.types.cpus.armv5tel + b + == lib'.systems.types.cpus.armv5tel && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv6l ) # ARMv6 ( - b == lib'.systems.types.cpus.armv6l + b + == lib'.systems.types.cpus.armv6l && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv6m ) ( - b == lib'.systems.types.cpus.armv6m + b + == lib'.systems.types.cpus.armv6m && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv7l ) # ARMv7 ( - b == lib'.systems.types.cpus.armv7l + b + == lib'.systems.types.cpus.armv7l && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv7a ) ( - b == lib'.systems.types.cpus.armv7l + b + == lib'.systems.types.cpus.armv7l && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv7r ) ( - b == lib'.systems.types.cpus.armv7l + b + == lib'.systems.types.cpus.armv7l && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv7m ) # ARMv8 (b == lib'.systems.types.cpus.aarch64 && a == lib'.systems.types.cpus.armv8a) ( - b == lib'.systems.types.cpus.armv8a + b + == lib'.systems.types.cpus.armv8a && lib'.systems.validate.compatible a lib'.systems.types.cpus.aarch64 ) ( - b == lib'.systems.types.cpus.armv8r + b + == lib'.systems.types.cpus.armv8r && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv8a ) ( - b == lib'.systems.types.cpus.armv8m + b + == lib'.systems.types.cpus.armv8m && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv8a ) # PowerPC ( - b == lib'.systems.types.cpus.powerpc + b + == lib'.systems.types.cpus.powerpc && lib'.systems.validate.compatible a lib'.systems.types.cpus.powerpc64 ) ( - b == lib'.systems.types.cpus.powerpcle + b + == lib'.systems.types.cpus.powerpcle && lib'.systems.validate.compatible a lib'.systems.types.cpus.powerpc64le ) # MIPS ( - b == lib'.systems.types.cpus.mips + b + == lib'.systems.types.cpus.mips && lib'.systems.validate.compatible a lib'.systems.types.cpus.mips64 ) ( - b == lib'.systems.types.cpus.mipsel + b + == lib'.systems.types.cpus.mipsel && lib'.systems.validate.compatible a lib'.systems.types.cpus.mips64el ) # RISCV ( - b == lib'.systems.types.cpus.riscv32 + b + == lib'.systems.types.cpus.riscv32 && lib'.systems.validate.compatible a lib'.systems.types.cpus.riscv64 ) # SPARC ( - b == lib'.systems.types.cpus.sparc + b + == lib'.systems.types.cpus.sparc && lib'.systems.validate.compatible a lib'.systems.types.cpus.sparc64 ) # WASM ( - b == lib'.systems.types.cpus.wasm32 + b + == lib'.systems.types.cpus.wasm32 && lib'.systems.validate.compatible a lib'.systems.types.cpus.wasm64 ) @@ -1172,8 +1186,13 @@ in name = "Cpu"; description = "Instruction set architecture name and information"; merge = lib.options.merge.one; - check = - x: types.bits.check x.bits && (if 8 < x.bits then types.endian.check x.endian else !(x ? endian)); + check = x: + types.bits.check x.bits + && ( + if 8 < x.bits + then types.endian.check x.endian + else !(x ? endian) + ); }; family = lib.types.create { @@ -1192,8 +1211,7 @@ in name = "Kernel"; description = "Kernel name and information"; merge = lib.options.merge.one; - check = - value: + check = value: types.exec.check value.exec && builtins.all types.family.check (builtins.attrValues value.families); }; @@ -1214,24 +1232,34 @@ in name = "system"; description = "fully parsed representation of llvm- or nix-style platform tuple"; merge = lib.options.merge.one; - check = - { - cpu, - vendor, - kernel, - abi, - }: + check = { + cpu, + vendor, + kernel, + abi, + ... + }: types.cpu.check cpu && types.vendor.check vendor && types.kernel.check kernel && types.abi.check abi; }; + platformWithBuildInfo = lib.types.create { + name = "systemWithBuildInfo"; + description = "fully parsed representation of llvm- or nix-style platform tuple with build information"; + merge = lib.options.merge.one; + check = value: + lib.types.is "systemWithBuildInfo" value + && value ? system + && lib'.systems.types.platform.check value.system; + }; + endian = lib.types.enum (builtins.attrValues types.endians); endians = setTypes types.generic.endian { - big = { }; - little = { }; + big = {}; + little = {}; }; bits = lib.types.enum [ @@ -1245,34 +1273,34 @@ in exec = lib.types.enum (builtins.attrValues types.execs); execs = setTypes types.generic.exec { - aout = { }; # a.out - elf = { }; - macho = { }; - pe = { }; - wasm = { }; - unknown = { }; + aout = {}; # a.out + elf = {}; + macho = {}; + pe = {}; + wasm = {}; + unknown = {}; }; vendor = lib.types.enum (builtins.attrValues types.vendors); vendors = setTypes types.generic.vendor { - apple = { }; - pc = { }; - knuth = { }; + apple = {}; + pc = {}; + knuth = {}; # Actually matters, unlocking some MinGW-w64-specific options in GCC. See # bottom of https://sourceforge.net/p/mingw-w64/wiki2/Unicode%20apps/ - w64 = { }; + w64 = {}; - none = { }; - unknown = { }; + none = {}; + unknown = {}; }; family = lib.types.enum (builtins.attrValues types.families); families = setTypes types.generic.family { - bsd = { }; - darwin = { }; + bsd = {}; + darwin = {}; }; kernel = lib.types.enum (builtins.attrValues types.kernels); @@ -1314,7 +1342,7 @@ in }; linux = { exec = types.execs.elf; - families = { }; + families = {}; }; netbsd = { exec = types.execs.elf; @@ -1324,7 +1352,7 @@ in }; none = { exec = types.execs.unknown; - families = { }; + families = {}; }; openbsd = { exec = types.execs.elf; @@ -1334,31 +1362,31 @@ in }; solaris = { exec = types.execs.elf; - families = { }; + families = {}; }; wasi = { exec = types.execs.wasm; - families = { }; + families = {}; }; redox = { exec = types.execs.elf; - families = { }; + families = {}; }; windows = { exec = types.execs.pe; - families = { }; + families = {}; }; ghcjs = { exec = types.execs.unknown; - families = { }; + families = {}; }; genode = { exec = types.execs.elf; - families = { }; + families = {}; }; mmixware = { exec = types.execs.unknown; - families = { }; + families = {}; }; # aliases @@ -1651,8 +1679,8 @@ in abi = lib.types.enum (builtins.attrValues types.abis); abis = setTypes types.generic.abi { - cygnus = { }; - msvc = { }; + cygnus = {}; + msvc = {}; # Note: eabi is specific to ARM and PowerPC. # On PowerPC, this corresponds to PPCEABI. @@ -1665,9 +1693,9 @@ in }; # Other architectures should use ELF in embedded situations. - elf = { }; + elf = {}; - androideabi = { }; + androideabi = {}; android = { assertions = [ { @@ -1731,7 +1759,7 @@ in musleabihf = { float = "hard"; }; - musl = { }; + musl = {}; uclibceabi = { float = "soft"; @@ -1739,187 +1767,169 @@ in uclibceabihf = { float = "hard"; }; - uclibc = { }; + uclibc = {}; - unknown = { }; + unknown = {}; }; }; from = { - string = - value: - let - parts = lib.strings.split "-" value; - skeleton = lib'.systems.skeleton parts; - system = lib'.systems.create (lib'.systems.from.skeleton skeleton); - in + string = value: let + parts = lib.strings.split "-" value; + skeleton = lib'.systems.skeleton parts; + system = lib'.systems.create (lib'.systems.from.skeleton skeleton); + in system; - skeleton = - spec@{ - cpu, - vendor ? - assert false; - null, - kernel, - abi ? - assert false; - null, - }: - let - getCpu = name: types.cpus.${name} or (throw "Unknown CPU type: ${name}"); - getVendor = name: types.vendors.${name} or (throw "Unknown vendor: ${name}"); - getKernel = name: types.kernels.${name} or (throw "Unknown kernel: ${name}"); - getAbi = name: types.abis.${name} or (throw "Unknown ABI: ${name}"); + skeleton = spec @ { + cpu, + vendor ? assert false; null, + kernel, + abi ? assert false; null, + }: let + getCpu = name: types.cpus.${name} or (throw "Unknown CPU type: ${name}"); + getVendor = name: types.vendors.${name} or (throw "Unknown vendor: ${name}"); + getKernel = name: types.kernels.${name} or (throw "Unknown kernel: ${name}"); + getAbi = name: types.abis.${name} or (throw "Unknown ABI: ${name}"); - resolved = { - cpu = getCpu spec.cpu; + resolved = { + cpu = getCpu spec.cpu; - vendor = - if spec ? vendor then - getVendor spec.vendor - else if lib'.systems.match.isDarwin resolved then - types.vendors.apple - else if lib'.systems.match.isWindows resolved then - types.vendors.pc - else - types.vendors.unknown; + vendor = + if spec ? vendor + then getVendor spec.vendor + else if lib'.systems.match.isDarwin resolved + then types.vendors.apple + else if lib'.systems.match.isWindows resolved + then types.vendors.pc + else types.vendors.unknown; - kernel = - if lib.strings.hasPrefix "darwin" spec.kernel then - getKernel "darwin" - else if lib.strings.hasPrefix "netbsd" spec.kernel then - getKernel "netbsd" - else - getKernel spec.kernel; + kernel = + if lib.strings.hasPrefix "darwin" spec.kernel + then getKernel "darwin" + else if lib.strings.hasPrefix "netbsd" spec.kernel + then getKernel "netbsd" + else getKernel spec.kernel; - abi = - if spec ? abi then - getAbi spec.abi - else if lib'.systems.match.isLinux resolved || lib'.systems.match.isWindows resolved then - if lib'.systems.match.isAarch32 resolved then - if lib.versions.gte "6" (resolved.cpu.version) then types.abis.gnueabihf else types.abis.gnueabi - else if lib'.systems.match.isPower64 resolved && lib'.systems.match.isBigEndian resolved then - types.abis.gnuabielfv2 - else - types.abis.gnu - else - types.abis.unknown; - }; - in + abi = + if spec ? abi + then getAbi spec.abi + else if lib'.systems.match.isLinux resolved || lib'.systems.match.isWindows resolved + then + if lib'.systems.match.isAarch32 resolved + then + if lib.versions.gte "6" (resolved.cpu.version) + then types.abis.gnueabihf + else types.abis.gnueabi + else if lib'.systems.match.isPower64 resolved && lib'.systems.match.isBigEndian resolved + then types.abis.gnuabielfv2 + else types.abis.gnu + else types.abis.unknown; + }; + in resolved; }; into = { - double = - { - cpu, - kernel, - abi, - ... - }: - let - kernelName = kernel.name + builtins.toString (kernel.version or ""); - in - if abi == types.abis.cygnus then - "${cpu.name}-cygwin" - else if kernel.families ? darwin then - "${cpu.name}-darwin" - else - "${cpu.name}-${kernelName}"; + double = { + cpu, + kernel, + abi, + ... + }: let + kernelName = kernel.name + builtins.toString (kernel.version or ""); + in + if abi == types.abis.cygnus + then "${cpu.name}-cygwin" + else if kernel.families ? darwin + then "${cpu.name}-darwin" + else "${cpu.name}-${kernelName}"; - triple = - { - cpu, - vendor, - kernel, - abi, - ... - }: - let - kernelName = kernel.name + builtins.toString (kernel.version or ""); - netbsdExec = - if - (cpu.family == "arm" && cpu.bits == 32) - || (cpu.family == "sparc" && cpu.bits == 32) - || (cpu.family == "m68k" && cpu.bits == 32) - || (cpu.family == "x86" && cpu.bits == 32) - then - types.execs.aout - else - types.execs.elf; + triple = { + cpu, + vendor, + kernel, + abi, + ... + }: let + kernelName = kernel.name + builtins.toString (kernel.version or ""); + netbsdExec = + if + (cpu.family == "arm" && cpu.bits == 32) + || (cpu.family == "sparc" && cpu.bits == 32) + || (cpu.family == "m68k" && cpu.bits == 32) + || (cpu.family == "x86" && cpu.bits == 32) + then types.execs.aout + else types.execs.elf; - exec = lib.strings.when (kernel.name == "netbsd" && netbsdExec != kernel.exec) kernel.exec.name; - abi' = lib.strings.when (abi != types.abis.unknown) "-${abi.name}"; - in - "${cpu.name}-${vendor.name}-${kernelName}${exec}${abi'}"; + exec = lib.strings.when (kernel.name == "netbsd" && netbsdExec != kernel.exec) kernel.exec.name; + abi' = lib.strings.when (abi != types.abis.unknown) "-${abi.name}"; + in "${cpu.name}-${vendor.name}-${kernelName}${exec}${abi'}"; }; - create = - components: + create = components: assert types.platform.check components; - lib.types.set "system" components; + lib.types.set "system" components; - skeleton = - parts: - let - length = builtins.length parts; + skeleton = parts: let + length = builtins.length parts; - first = builtins.elemAt parts 0; - second = builtins.elemAt parts 1; - third = builtins.elemAt parts 2; - fourth = builtins.elemAt parts 3; - in - if length == 1 then - if first == "avr" then - { - cpu = first; - kernel = "none"; - abi = "unknown"; - } - else - builtins.throw "Target specification with 1 component is ambiguous." - else if length == 2 then - if second == "cygwin" then - { - cpu = first; - kernel = "windows"; - abi = "cygnus"; - } - else if second == "windows" then - { - cpu = first; - kernel = "windows"; - abi = "msvc"; - } - else if second == "elf" then - { - cpu = first; - vendor = "unkonwn"; - kernel = "none"; - abi = second; - } - else - { - cpu = first; - kernel = second; - } - else if length == 3 then + first = builtins.elemAt parts 0; + second = builtins.elemAt parts 1; + third = builtins.elemAt parts 2; + fourth = builtins.elemAt parts 3; + in + if length == 1 + then + if first == "avr" + then { + cpu = first; + kernel = "none"; + abi = "unknown"; + } + else builtins.throw "Target specification with 1 component is ambiguous." + else if length == 2 + then + if second == "cygwin" + then { + cpu = first; + kernel = "windows"; + abi = "cygnus"; + } + else if second == "windows" + then { + cpu = first; + kernel = "windows"; + abi = "msvc"; + } + else if second == "elf" + then { + cpu = first; + vendor = "unkonwn"; + kernel = "none"; + abi = second; + } + else { + cpu = first; + kernel = second; + } + else if length == 3 + then if - second == "linux" + second + == "linux" || (builtins.elem third [ "eabi" "eabihf" "elf" "gnu" ]) - then - { - cpu = first; - vendor = "unknown"; - kernel = second; - abi = third; - } + then { + cpu = first; + vendor = "unknown"; + kernel = second; + abi = third; + } else if (second == "apple") || lib.strings.hasPrefix "freebsd" third @@ -1932,23 +1942,23 @@ in "ghcjs" "mingw32" ]) - then - { - cpu = first; - vendor = second; - kernel = if third == "mingw32" then "windows" else third; - } - else - builtins.throw "Target specification with 3 components is ambiguous." - else if length == 4 then - { + then { cpu = first; vendor = second; - kernel = third; - abi = fourth; + kernel = + if third == "mingw32" + then "windows" + else third; } - else - builtins.throw "Invalid component count for creating system skeleton. Expected 1-4, but got ${builtins.toString length}."; + else builtins.throw "Target specification with 3 components is ambiguous." + else if length == 4 + then { + cpu = first; + vendor = second; + kernel = third; + abi = fourth; + } + else builtins.throw "Invalid component count for creating system skeleton. Expected 1-4, but got ${builtins.toString length}."; patterns = { isi686 = { @@ -2009,17 +2019,16 @@ in }; isArmv7 = map - ( - { arch, ... }: - { - cpu = { - inherit arch; - }; - } - ) - ( - builtins.filter (cpu: lib.strings.hasPrefix "armv7" cpu.arch or "") (builtins.attrValues types.cpus) - ); + ( + {arch, ...}: { + cpu = { + inherit arch; + }; + } + ) + ( + builtins.filter (cpu: lib.strings.hasPrefix "armv7" cpu.arch or "") (builtins.attrValues types.cpus) + ); isAarch64 = { cpu = { family = "arm"; @@ -2171,16 +2180,16 @@ in }; isILP32 = builtins.map - (a: { - abi = { - abi = a; - }; - }) - [ - "n32" - "ilp32" - "x32" - ]; + (a: { + abi = { + abi = a; + }; + }) + [ + "n32" + "ilp32" + "x32" + ]; isBigEndian = { cpu = { endian = types.endians.big; @@ -2266,10 +2275,10 @@ in }; isAndroid = [ - { abi = types.abis.android; } - { abi = types.abis.androideabi; } + {abi = types.abis.android;} + {abi = types.abis.androideabi;} ]; - isGnu = builtins.map (value: { abi = value; }) [ + isGnu = builtins.map (value: {abi = value;}) [ types.abis.gnuabi64 types.abis.gnuabin32 types.abis.gnu @@ -2278,14 +2287,14 @@ in types.abis.gnuabielfv1 types.abis.gnuabielfv2 ]; - isMusl = builtins.map (value: { abi = value; }) [ + isMusl = builtins.map (value: {abi = value;}) [ types.abis.musl types.abis.musleabi types.abis.musleabihf types.abis.muslabin32 types.abis.muslabi64 ]; - isUClibc = builtins.map (value: { abi = value; }) [ + isUClibc = builtins.map (value: {abi = value;}) [ types.abis.uclibc types.abis.uclibceabi types.abis.uclibceabihf @@ -2531,268 +2540,288 @@ in ]; }; - withBuildInfo = - args: - let - settings = if builtins.isString args then { system = args; } else args; + withBuildInfo = args: let + settings = + if builtins.isString args + then {system = args;} + else args; - resolved = - { - system = lib'.systems.from.string (if settings ? triple then settings.triple else settings.system); + resolved = + { + system = lib'.systems.from.string ( + if settings ? triple + then settings.triple + else settings.system + ); - inherit - ( - { - linux-kernel = settings.linux-kernel or { }; - gcc = settings.gcc or { }; - rustc = settings.rustc or { }; - } - // lib'.systems.platforms.select resolved - ) - linux-kernel - gcc - rustc - ; + inherit + ( + { + linux-kernel = settings.linux-kernel or {}; + gcc = settings.gcc or {}; + rustc = settings.rustc or {}; + } + // lib'.systems.platforms.select resolved + ) + linux-kernel + gcc + rustc + ; - double = lib'.systems.into.double resolved.system; - triple = lib'.systems.into.triple resolved.system; + double = lib'.systems.into.double resolved.system; + triple = lib'.systems.into.triple resolved.system; - isExecutable = - platform: - (resolved.isAndroid == platform.isAndroid) - && resolved.system.kernel == platform.system.kernel - && lib'.systems.validate.compatible resolved.system.cpu platform.system.cpu; + isExecutable = platform: + (resolved.isAndroid == platform.isAndroid) + && resolved.system.kernel == platform.system.kernel + && lib'.systems.validate.compatible resolved.system.cpu platform.system.cpu; - # The difference between `isStatic` and `hasSharedLibraries` is mainly the - # addition of the `staticMarker` (see make-derivation.nix). Some - # platforms, like embedded machines without a libc (e.g. arm-none-eabi) - # don't support dynamic linking, but don't get the `staticMarker`. - # `pkgsStatic` sets `isStatic=true`, so `pkgsStatic.hostPlatform` always - # has the `staticMarker`. - isStatic = resolved.isWasm || resolved.isRedox; + # The difference between `isStatic` and `hasSharedLibraries` is mainly the + # addition of the `staticMarker` (see make-derivation.nix). Some + # platforms, like embedded machines without a libc (e.g. arm-none-eabi) + # don't support dynamic linking, but don't get the `staticMarker`. + # `pkgsStatic` sets `isStatic=true`, so `pkgsStatic.hostPlatform` always + # has the `staticMarker`. + isStatic = resolved.isWasm || resolved.isRedox; - # It is important that hasSharedLibraries==false when the platform has no - # dynamic library loader. Various tools (including the gcc build system) - # have knowledge of which platforms are incapable of dynamic linking, and - # will still build on/for those platforms with --enable-shared, but simply - # omit any `.so` build products such as libgcc_s.so. When that happens, - # it causes hard-to-troubleshoot build failures. - hasSharedLibraries = - !resolved.isStatic - && ( - # Linux (allows multiple libcs) - resolved.isAndroid - || resolved.isGnu - || resolved.isMusl - # BSDs - || resolved.isDarwin - || resolved.isSunOS - || resolved.isOpenBSD - || resolved.isFreeBSD - || resolved.isNetBSD - # Windows - || resolved.isCygwin - || resolved.isMinGW - ); + # It is important that hasSharedLibraries==false when the platform has no + # dynamic library loader. Various tools (including the gcc build system) + # have knowledge of which platforms are incapable of dynamic linking, and + # will still build on/for those platforms with --enable-shared, but simply + # omit any `.so` build products such as libgcc_s.so. When that happens, + # it causes hard-to-troubleshoot build failures. + hasSharedLibraries = + !resolved.isStatic + && ( + # Linux (allows multiple libcs) + resolved.isAndroid + || resolved.isGnu + || resolved.isMusl + # BSDs + || resolved.isDarwin + || resolved.isSunOS + || resolved.isOpenBSD + || resolved.isFreeBSD + || resolved.isNetBSD + # Windows + || resolved.isCygwin + || resolved.isMinGW + ); - libc = - if resolved.isDarwin then - "libSystem" - else if resolved.isMinGW then - "msvcrt" - else if resolved.isWasi then - "wasilibc" - else if resolved.isRedox then - "relibc" - else if resolved.isMusl then - "musl" - else if resolved.isUClibc then - "uclibc" - else if resolved.isAndroid then - "bionic" - else if resolved.isLinux then - "glibc" - else if resolved.isFreeBSD then - "fblibc" - else if resolved.isNetBSD then - "nblibc" - else if resolved.isAvr then - "avrlibc" - else if resolved.isGhcjs then - null - else if resolved.isNone then - "newlib" - else - "native/impure"; + libc = + if resolved.isDarwin + then "libSystem" + else if resolved.isMinGW + then "msvcrt" + else if resolved.isWasi + then "wasilibc" + else if resolved.isRedox + then "relibc" + else if resolved.isMusl + then "musl" + else if resolved.isUClibc + then "uclibc" + else if resolved.isAndroid + then "bionic" + else if resolved.isLinux + then "glibc" + else if resolved.isFreeBSD + then "fblibc" + else if resolved.isNetBSD + then "nblibc" + else if resolved.isAvr + then "avrlibc" + else if resolved.isGhcjs + then null + else if resolved.isNone + then "newlib" + else "native/impure"; - linker = if resolved.isDarwin then "cctools" else "bfd"; + linker = + if resolved.isDarwin + then "cctools" + else "bfd"; - extensions = - (lib.attrs.when resolved.hasSharedLibraries { - shared = - if resolved.isDarwin then - ".dylib" - else if resolved.isWindows then - ".dll" - else - ".so"; - }) - // { - static = if resolved.isWindows then ".lib" else ".a"; + extensions = + (lib.attrs.when resolved.hasSharedLibraries { + shared = + if resolved.isDarwin + then ".dylib" + else if resolved.isWindows + then ".dll" + else ".so"; + }) + // { + static = + if resolved.isWindows + then ".lib" + else ".a"; - library = if resolved.isStatic then resolved.extensions.static else resolved.extensions.shared; + library = + if resolved.isStatic + then resolved.extensions.static + else resolved.extensions.shared; - executable = if resolved.isWindows then ".exe" else ""; - }; - - uname = { - system = - if resolved.system.kernel.name == "linux" then - "Linux" - else if resolved.system.kernel.name == "windows" then - "Windows" - else if resolved.system.kernel.name == "darwin" then - "Darwin" - else if resolved.system.kernel.name == "netbsd" then - "NetBSD" - else if resolved.system.kernel.name == "freebsd" then - "FreeBSD" - else if resolved.system.kernel.name == "openbsd" then - "OpenBSD" - else if resolved.system.kernel.name == "wasi" then - "Wasi" - else if resolved.system.kernel.name == "redox" then - "Redox" - else if resolved.system.kernel.name == "redox" then - "Genode" - else - null; - - processor = - if resolved.isPower64 then - "ppc64${lib.strings.when resolved.isLittleEndian "le"}" - else if resolved.isPower then - "ppc${lib.strings.when resolved.isLittleEndian "le"}" - else if resolved.isMips64 then - "mips64" - else - resolved.system.cpu.name; - - release = null; + executable = + if resolved.isWindows + then ".exe" + else ""; }; - useAndroidPrebuilt = false; - useiOSPrebuilt = false; + uname = { + system = + if resolved.system.kernel.name == "linux" + then "Linux" + else if resolved.system.kernel.name == "windows" + then "Windows" + else if resolved.system.kernel.name == "darwin" + then "Darwin" + else if resolved.system.kernel.name == "netbsd" + then "NetBSD" + else if resolved.system.kernel.name == "freebsd" + then "FreeBSD" + else if resolved.system.kernel.name == "openbsd" + then "OpenBSD" + else if resolved.system.kernel.name == "wasi" + then "Wasi" + else if resolved.system.kernel.name == "redox" + then "Redox" + else if resolved.system.kernel.name == "redox" + then "Genode" + else null; - linux.arch = - if resolved.isAarch32 then - "arm" - else if resolved.isAarch64 then - "arm64" - else if resolved.isx86_32 then - "i386" - else if resolved.isx86_64 then - "x86_64" - # linux kernel does not distinguish microblaze/microblazeel - else if resolved.isMicroBlaze then - "microblaze" - else if resolved.isMips32 then - "mips" - else if resolved.isMips64 then - "mips" # linux kernel does not distinguish mips32/mips64 - else if resolved.isPower then - "powerpc" - else if resolved.isRiscV then - "riscv" - else if resolved.isS390 then - "s390" - else if resolved.isLoongArch64 then - "loongarch" - else - resolved.system.cpu.name; + processor = + if resolved.isPower64 + then "ppc64${lib.strings.when resolved.isLittleEndian "le"}" + else if resolved.isPower + then "ppc${lib.strings.when resolved.isLittleEndian "le"}" + else if resolved.isMips64 + then "mips64" + else resolved.system.cpu.name; - uboot.arch = - if resolved.isx86_32 then - "x86" # not i386 - else if resolved.isMips64 then - "mips64" # uboot *does* distinguish between mips32/mips64 - else - resolved.linux.arch; # other cases appear to agree with linuxArch + release = null; + }; - qemu.arch = - if resolved.isAarch32 then - "arm" - else if resolved.isS390 && !resolved.isS390x then - null - else if resolved.isx86_64 then - "x86_64" - else if resolved.isx86 then - "i386" - else if resolved.isMips64n32 then - "mipsn32${lib.strings.when resolved.isLittleEndian "el"}" - else if resolved.isMips64 then - "mips64${lib.strings.when resolved.isLittleEndian "el"}" - else - resolved.uname.processor; + useAndroidPrebuilt = false; + useiOSPrebuilt = false; - efi.arch = - if resolved.isx86_32 then - "ia32" - else if resolved.isx86_64 then - "x64" - else if resolved.isAarch32 then - "arm" - else if resolved.isAarch64 then - "aa64" - else - resolved.system.cpu.name; + linux.arch = + if resolved.isAarch32 + then "arm" + else if resolved.isAarch64 + then "arm64" + else if resolved.isx86_32 + then "i386" + else if resolved.isx86_64 + then "x86_64" + # linux kernel does not distinguish microblaze/microblazeel + else if resolved.isMicroBlaze + then "microblaze" + else if resolved.isMips32 + then "mips" + else if resolved.isMips64 + then "mips" # linux kernel does not distinguish mips32/mips64 + else if resolved.isPower + then "powerpc" + else if resolved.isRiscV + then "riscv" + else if resolved.isS390 + then "s390" + else if resolved.isLoongArch64 + then "loongarch" + else resolved.system.cpu.name; - darwin = { - arch = - if resolved.system.cpu.name == "armv7a" then - "armv7" - else if resolved.system.cpu.name == "aarch64" then - "arm64" - else - resolved.system.cpu.name; + uboot.arch = + if resolved.isx86_32 + then "x86" # not i386 + else if resolved.isMips64 + then "mips64" # uboot *does* distinguish between mips32/mips64 + else resolved.linux.arch; # other cases appear to agree with linuxArch - platform = - if resolved.isMacOS then - "macos" - else if resolved.isiOS then - "ios" - else - null; + qemu.arch = + if resolved.isAarch32 + then "arm" + else if resolved.isS390 && !resolved.isS390x + then null + else if resolved.isx86_64 + then "x86_64" + else if resolved.isx86 + then "i386" + else if resolved.isMips64n32 + then "mipsn32${lib.strings.when resolved.isLittleEndian "el"}" + else if resolved.isMips64 + then "mips64${lib.strings.when resolved.isLittleEndian "el"}" + else resolved.uname.processor; - sdk = { - version = resolved.darwinSdkVersion or (if resolved.isAarch64 then "11.0" else "10.12"); + efi.arch = + if resolved.isx86_32 + then "ia32" + else if resolved.isx86_64 + then "x64" + else if resolved.isAarch32 + then "arm" + else if resolved.isAarch64 + then "aa64" + else resolved.system.cpu.name; - min = resolved.darwin.sdk.version; + darwin = { + arch = + if resolved.system.cpu.name == "armv7a" + then "armv7" + else if resolved.system.cpu.name == "aarch64" + then "arm64" + else resolved.system.cpu.name; - variable = - if resolved.isMacOS then - "MACOSX_DEPLOYMENT_TARGET" - else if resolved.isiOS then - "IPHONEOS_DEPLOYMENT_TARGET" - else - null; - }; + platform = + if resolved.isMacOS + then "macos" + else if resolved.isiOS + then "ios" + else null; + + sdk = { + version = + resolved.darwinSdkVersion + or ( + if resolved.isAarch64 + then "11.0" + else "10.12" + ); + + min = resolved.darwin.sdk.version; + + variable = + if resolved.isMacOS + then "MACOSX_DEPLOYMENT_TARGET" + else if resolved.isiOS + then "IPHONEOS_DEPLOYMENT_TARGET" + else null; }; - } - // builtins.mapAttrs (name: match: match resolved.system) lib'.systems.match - // builtins.mapAttrs ( - name: validate: validate (resolved.gcc.arch or "default") - ) lib'.systems.validate.architecture - // (builtins.removeAttrs settings [ "system" ]); + }; + } + // builtins.mapAttrs (name: match: match resolved.system) lib'.systems.match + // builtins.mapAttrs ( + name: validate: validate (resolved.gcc.arch or "default") + ) + lib'.systems.validate.architecture + // (builtins.removeAttrs settings ["system"]); - assertions = builtins.foldl' ( - result: { assertion, message }: if assertion resolved then result else builtins.throw message - ) true (resolved.system.abi.assertions or [ ]); - in + assertions = + builtins.foldl' ( + result: { + assertion, + message, + }: + if assertion resolved + then result + else builtins.throw message + ) + true (resolved.system.abi.assertions or []); + in assert resolved.useAndroidPrebuilt -> resolved.isAndroid; assert assertions; # And finally, return the generated system info. - resolved; + lib.types.set "systemWithBuildInfo" resolved; }; }; } diff --git a/tidepool/src/lib/types.nix b/tidepool/src/lib/types.nix index 78cdd72..c0068ef 100644 --- a/tidepool/src/lib/types.nix +++ b/tidepool/src/lib/types.nix @@ -1,8 +1,11 @@ { lib, - lib', config, -}: { +}: let + inherit (config) preferences builders; + + lib' = config.lib; +in { config = { lib.types = { license = let @@ -52,6 +55,12 @@ in lib.types.either type (lib.types.list.of type); + platform = + lib.types.coerce + lib.types.string + lib'.systems.withBuildInfo + lib'.systems.types.platformWithBuildInfo; + builder = lib.types.submodule { freeform = lib.types.any; @@ -63,385 +72,287 @@ }; }; - packages = lib.types.attrs.of (lib'.types.alias); + packages = lib.types.attrs.of (lib.types.attrs.of lib'.types.alias); - alias = lib.types.attrs.of ( - lib.types.submodule { - options = { - versions = lib.options.create { - description = "All available package versions."; - type = lib.types.attrs.of lib'.types.package.base; - }; + dependencies = let + initial = + (lib.types.attrs.lazy lib.types.any) + // { + check = value: + lib.types.attrs.any.check value + && value ? versions; }; - } - ); + in + lib.types.attrs.of (lib.types.coerce initial lib'.packages.resolve lib'.types.package); - dependencies = lib.types.attrs.of ( - lib.types.nullish (lib'.types.package.resolved) - ); + alias = lib.types.submodule { + options = { + stable = lib.options.create { + description = "The stable version of the package."; + type = lib.types.nullish lib'.types.package; + }; - package = { - resolved = let - initial = - lib.types.raw - // { - check = value: - !(value ? __merged__) - && lib.types.raw.check - value; - }; + latest = lib.options.create { + description = "The latest version of the package."; + type = lib'.types.package; + }; - transform = value: let - package = lib'.packages.resolve value; - packageSubmodule = package.extend (args: { - options.__export__ = lib.options.create { - type = lib.types.raw; - default.value = { - inherit (args) options config; - }; - }; + versions = lib.options.create { + description = "Available versions of the package."; + type = lib.types.attrs.of lib'.types.package; + default.value = {}; + }; + }; + }; - config.__export__ = { - inherit (args) options config; - }; - }); - type = lib'.types.package.base.withSubModules (lib'.types.package.base.getSubModules - ++ [ - (args: { - options.__export__ = lib.options.create { - type = lib.types.raw; - default.value = { - inherit (args) options config; - }; - }; + package = let + normalize = value: + if builtins.isFunction value || builtins.isList value + then value + else if value ? __modules__ + then value.__modules__ + else { + config = value; + }; - config.__export__ = { - inherit (args) options config; - }; - }) - ]); - typeSubmodule = lib.modules.run { - modules = type.getSubModules; - args = type.functor.payload.args; - }; - - getOptions = export: let - process = path: option: - if builtins.isAttrs option - then - if lib.types.is "option" option - then [ - { - inherit path; - option = option; - } - ] - else - builtins.concatLists ( - lib.attrs.mapToList - (name: value: process (path ++ [name]) value) - option - ) - else []; - in - process [] export.options; - - packageOptions = getOptions packageSubmodule.__export__; - typeOptions = getOptions typeSubmodule.config.__export__; - - customOptions = - builtins.filter - ( - packageOption: - builtins.all (typeOption: packageOption.path != typeOption.path) typeOptions - ) - packageOptions; - - packageOptionsIds = builtins.map (option: builtins.concatStringsSep "." option.path) packageOptions; - typeOptionsIds = builtins.map (option: builtins.concatStringsSep "." option.path) typeOptions; - customOptionsIds = builtins.map (option: builtins.concatStringsSep "." option.path) customOptions; - - resolvedOptions = - builtins.foldl' ( - resolved: option: let - first = builtins.head option.path; - generated = lib.attrs.set option.path option.option; - in - if first == "__export__" || first == "__module__" || first == "__merged__" - then resolved - else lib.attrs.mergeRecursive resolved generated - ) {} - customOptions; + initial = lib.types.create { + name = "PackageConfig"; + description = "configuration for a package"; + check = value: builtins.isFunction value || builtins.isAttrs value || builtins.isList value; + merge = location: definitions: let + normalized = + builtins.map + (definition: lib.lists.from.any (normalize definition.value)) + definitions; in - # (builtins.trace (builtins.deepSeq packageOptionsIds packageOptionsIds)) - # (builtins.trace (builtins.deepSeq typeOptionsIds typeOptionsIds)) - # (builtins.trace (builtins.deepSeq customOptionsIds customOptionsIds)) - # (builtins.trace packageSubmodule.__export__.config) - (args: { - __file__ = packageSubmodule.__export__.config.__file__ or "virtual:tidepool/src/lib/types.nix"; + builtins.concatLists + normalized; + }; - options = - resolvedOptions - // { - __merged__ = lib.options.create { - type = lib.types.bool; - default.value = true; - }; - }; + transform = location: value: let + modules = + lib.lists.from.any (normalize value); - config = - builtins.removeAttrs package ["extend" "package" "platform"] - // { - platform = { - build = lib.modules.overrides.default package.platform.build.triple; - host = lib.modules.overrides.default package.platform.host.triple; - target = lib.modules.overrides.default package.platform.target.triple; - }; - }; - # // { - # builder = - # (builtins.trace "builder") - # (builtins.trace (args.config ? builder)) - # lib.modules.alias - # packageSubmodule.__export__.options.builder; - # }; - }); + result = lib.modules.run { + prefix = location; + modules = + modules + ++ [submodule {config.__modules__ = modules;}]; + }; in - lib.types.coerce initial transform lib'.types.package.base; + result.config; - base = lib.types.submodule ( - { - config, - meta, - }: { - options = { - extend = lib.options.create { - description = "Extend the package's submodules with additional configuration."; - type = lib.types.function lib.types.raw; - default.value = value: let - result = meta.extend { - modules = - if builtins.isAttrs value - then [{config = value;}] - else lib.lists.from.any value; - }; - in - result.config; - }; + final = lib.types.attrs.any; - name = lib.options.create { - description = "The name of the package."; - type = lib.types.string; - default = { - text = "\${config.pname}-\${config.version}"; - value = - if config.pname != null && config.version != null - then "${config.pname}-${config.version}" - else ""; - }; - }; + submodule = {config}: { + options = { + __modules__ = lib.options.create { + description = "User specified modules for the package definition."; + type = lib.types.list.of (initial + // { + merge = lib.options.merge.one; + }); + # writable = false; + internal = true; + default.value = []; + }; - pname = lib.options.create { - description = "The program name for the package"; + meta = { + description = lib.options.create { + description = "The description for the package."; type = lib.types.nullish lib.types.string; default.value = null; }; - version = lib.options.create { - description = "The version for the package."; - type = lib.types.nullish lib.types.version; + homepage = lib.options.create { + description = "The homepage for the package."; + type = lib.types.nullish lib.types.string; default.value = null; }; - meta = { - description = lib.options.create { - description = "The description for the package."; - type = lib.types.nullish lib.types.string; - default.value = null; - }; - - homepage = lib.options.create { - description = "The homepage for the package."; - type = lib.types.nullish lib.types.string; - default.value = null; - }; - - license = lib.options.create { - description = "The license for the package."; - type = lib.types.nullish lib'.types.license; - default.value = null; - }; - - free = lib.options.create { - description = "Whether the package is free."; - type = lib.types.bool; - default.value = true; - }; - - insecure = lib.options.create { - description = "Whether the package is insecure."; - type = lib.types.bool; - default.value = false; - }; - - broken = lib.options.create { - description = "Whether the package is broken."; - type = lib.types.bool; - default.value = false; - }; - - main = lib.options.create { - description = "The main entry point for the package."; - type = lib.types.nullish lib.types.string; - default.value = null; - }; - - platforms = lib.options.create { - description = "The platforms the package supports."; - type = lib.types.list.of lib.types.string; - default.value = []; - }; + license = lib.options.create { + description = "The license for the package."; + type = lib.types.nullish lib'.types.license; + default.value = null; }; - platform = { + free = lib.options.create { + description = "Whether the package is free."; + type = lib.types.bool; + default.value = true; + }; + + insecure = lib.options.create { + description = "Whether the package is insecure."; + type = lib.types.bool; + default.value = false; + }; + + broken = lib.options.create { + description = "Whether the package is broken."; + type = lib.types.bool; + default.value = false; + }; + + main = lib.options.create { + description = "The main entry point for the package."; + type = lib.types.nullish lib.types.string; + default.value = null; + }; + + platforms = lib.options.create { + description = "The platforms the package supports."; + type = lib.types.list.of lib.types.string; + default.value = []; + }; + }; + + platform = { + build = lib.options.create { + description = "The build platform for the package."; + type = lib'.types.platform; + default.value = lib'.systems.withBuildInfo "x86_64-linux"; + }; + + host = lib.options.create { + description = "The host platform for the package."; + type = lib'.types.platform; + default.value = lib'.systems.withBuildInfo "x86_64-linux"; + }; + + target = lib.options.create { + description = "The target platform for the package."; + type = lib'.types.platform; + default.value = lib'.systems.withBuildInfo "x86_64-linux"; + }; + }; + + name = lib.options.create { + description = "The name of the package."; + type = lib.types.string; + default = { + text = "\${config.pname}-\${config.version}"; + value = + if config.pname != null && config.version != null + then "${config.pname}-${config.version}" + else ""; + }; + }; + + pname = lib.options.create { + description = "The program name for the package"; + type = lib.types.nullish lib.types.string; + default.value = null; + }; + + version = lib.options.create { + description = "The version for the package."; + type = lib.types.nullish lib.types.version; + default.value = null; + }; + + builder = lib.options.create { + description = "The builder for the package."; + type = lib'.types.builder; + }; + + phases = lib.options.create { + description = "The phases for the package."; + type = lib.types.dag.of lib.types.string; + default.value = {}; + }; + + env = lib.options.create { + description = "The environment for the package."; + type = lib.types.attrs.of lib.types.string; + default.value = {}; + }; + + package = lib.options.create { + description = "The built derivation."; + type = lib.types.derivation; + default.value = config.builder.build config; + }; + + deps = { + build = { + only = lib.options.create { + description = "Dependencies which are only used in the build environment."; + type = lib'.types.dependencies; + default.value = {}; + }; + build = lib.options.create { - description = "The build platform for the package."; - type = lib.types.string; - default.value = "x86_64-linux"; - apply = raw: let - system = lib'.systems.from.string raw; - x = lib'.systems.withBuildInfo raw; - in - x; + description = "Dependencies which are created in the build environment and are executed in the build environment."; + type = lib'.types.dependencies; + default.value = {}; }; host = lib.options.create { - description = "The host platform for the package."; - type = lib.types.string; - default.value = "x86_64-linux"; - # apply = raw: let - # system = lib'.systems.from.string raw; - # in { - # inherit raw system; - - # double = lib'.systems.into.double system; - # triple = lib'.systems.into.triple system; - # }; - apply = raw: let - system = lib'.systems.from.string raw; - x = lib'.systems.withBuildInfo raw; - in - x; + description = "Dependencies which are created in the build environment and are executed in the host environment."; + type = lib'.types.dependencies; + default.value = {}; }; target = lib.options.create { - description = "The target platform for the package."; - type = lib.types.string; - default.value = "x86_64-linux"; - # apply = raw: let - # system = lib'.systems.from.string raw; - # in { - # inherit raw system; - - # double = lib'.systems.into.double system; - # triple = lib'.systems.into.triple system; - # }; - apply = raw: let - system = lib'.systems.from.string raw; - x = lib'.systems.withBuildInfo raw; - in - x; + description = "Dependencies which are created in the build environment and are executed in the target environment."; + type = lib'.types.dependencies; + default.value = {}; }; }; - phases = lib.options.create { - description = "The phases for the package."; - type = lib.types.dag.of (lib.types.either lib.types.string (lib.types.function lib.types.string)); - default.value = {}; - }; - - env = lib.options.create { - description = "The environment for the package."; - type = lib.types.attrs.of lib.types.string; - default.value = {}; - }; - - builder = lib.options.create { - description = "The builder for the package."; - type = lib'.types.builder; - }; - - deps = { - build = { - only = lib.options.create { - description = "Dependencies which are only used in the build environment."; - type = lib'.types.dependencies; - default.value = {}; - }; - - build = lib.options.create { - description = "Dependencies which are created in the build environment and are executed in the build environment."; - type = lib'.types.dependencies; - default.value = {}; - }; - - host = lib.options.create { - description = "Dependencies which are created in the build environment and are executed in the host environment."; - type = lib'.types.dependencies; - default.value = {}; - }; - - target = lib.options.create { - description = "Dependencies which are created in the build environment and are executed in the target environment."; - type = lib'.types.dependencies; - default.value = {}; - }; + host = { + only = lib.options.create { + description = "Dependencies which are only used in the host environment."; + type = lib'.types.dependencies; + default.value = {}; }; - host = { - only = lib.options.create { - description = "Dependencies which are only used in the host environment."; - type = lib'.types.dependencies; - default.value = {}; - }; - - host = lib.options.create { - description = "Dependencies which are executed in the host environment."; - type = lib'.types.dependencies; - default.value = {}; - }; - - target = lib.options.create { - description = "Dependencies which are executed in the host environment which produces code for the target environment."; - type = lib'.types.dependencies; - default.value = {}; - }; + host = lib.options.create { + description = "Dependencies which are executed in the host environment."; + type = lib'.types.dependencies; + default.value = {}; }; - target = { - only = lib.options.create { - description = "Dependencies which are only used in the target environment."; - type = lib'.types.dependencies; - default.value = {}; - }; - - target = lib.options.create { - description = "Dependencies which are executed in the target environment."; - type = lib'.types.dependencies; - default.value = {}; - }; + target = lib.options.create { + description = "Dependencies which are executed in the host environment which produces code for the target environment."; + type = lib'.types.dependencies; + default.value = {}; }; }; - package = lib.options.create { - description = "The built derivation."; - type = lib.types.derivation; - default.value = config.builder.build config; + target = { + only = lib.options.create { + description = "Dependencies which are only used in the target environment."; + type = lib'.types.dependencies; + default.value = {}; + }; + + target = lib.options.create { + description = "Dependencies which are executed in the target environment."; + type = lib'.types.dependencies; + default.value = {}; + }; }; }; - } - ); - }; + }; + }; + + type = + (lib.types.coerceWithLocation initial transform final) + // { + name = "Package"; + description = "a package definition"; + }; + in + type + // { + children = + type.children + // { + inherit submodule; + }; + }; }; }; } diff --git a/tidepool/src/packages/aux/a.nix b/tidepool/src/packages/aux/a.nix index 97417ff..7d8b849 100644 --- a/tidepool/src/packages/aux/a.nix +++ b/tidepool/src/packages/aux/a.nix @@ -12,6 +12,8 @@ in { platforms = ["i686-linux"]; }; + name = "${config.pname}-${config.version}"; + pname = "a"; version = "1.0.0"; diff --git a/tidepool/src/packages/aux/b.nix b/tidepool/src/packages/aux/b.nix index 64b3e40..b9c1148 100644 --- a/tidepool/src/packages/aux/b.nix +++ b/tidepool/src/packages/aux/b.nix @@ -1,15 +1,12 @@ -{ - lib', - config, -}: let - inherit (config) builders packages; +{config}: let + inherit (config) lib builders packages; in { config.packages.aux.b = { versions = { "latest" = {config}: { options = { - custom = lib'.options.create { - type = lib'.types.bool; + custom = lib.options.create { + type = lib.types.bool; }; }; @@ -18,6 +15,8 @@ in { platforms = ["i686-linux"]; }; + name = "${config.pname}-${config.version}"; + custom = true; pname = "b"; diff --git a/tidepool/src/packages/default.nix b/tidepool/src/packages/default.nix index a0ccb9b..2e688d9 100644 --- a/tidepool/src/packages/default.nix +++ b/tidepool/src/packages/default.nix @@ -1,9 +1,7 @@ -{ - lib, - lib', - config, -}: let - doubles = lib'.systems.doubles.all; +{config}: let + inherit (config) lib; + + doubles = lib.systems.doubles.all; packages = builtins.removeAttrs config.packages ["cross"]; in { @@ -17,13 +15,13 @@ in { packages = lib.options.create { description = "The package set."; type = lib.types.submodule { - freeform = lib.types.attrs.of (lib.types.submodule {freeform = lib'.types.alias;}); + freeform = lib.types.packages; options.cross = lib.attrs.generate doubles ( system: lib.options.create { description = "The cross-compiled package set for the ${system} target."; - type = lib'.types.packages; + type = lib.types.packages; default = {}; } ); @@ -49,38 +47,39 @@ in { builtins.mapAttrs ( name: alias: let setHost = package: - if package != {} - then - (package.extend ( - {config}: { - config = { - platform = { - host = lib.modules.overrides.force system; - target = lib.modules.overrides.default system; - }; + package; + # if package != {} + # then + # (package.extend ( + # {config}: { + # config = { + # platform = { + # host = lib.modules.overrides.force system; + # target = lib.modules.overrides.default system; + # }; - deps = { - build = { - only = setHost package.deps.build.only; - build = setHost package.deps.build.build; - host = setHost package.deps.build.host; - target = setHost package.deps.build.target; - }; - host = { - only = setHost package.deps.host.only; - host = setHost package.deps.host.host; - target = setHost package.deps.host.target; - }; - target = { - only = setHost package.deps.target.only; - target = setHost package.deps.target.target; - }; - }; - }; - } - )) - .config - else package; + # deps = { + # build = { + # only = setHost package.deps.build.only; + # build = setHost package.deps.build.build; + # host = setHost package.deps.build.host; + # target = setHost package.deps.build.target; + # }; + # host = { + # only = setHost package.deps.host.only; + # host = setHost package.deps.host.host; + # target = setHost package.deps.host.target; + # }; + # target = { + # only = setHost package.deps.target.only; + # target = setHost package.deps.target.target; + # }; + # }; + # }; + # } + # )) + # .config + # else package; updated = alias