diff --git a/lib/src/options/default.nix b/lib/src/options/default.nix index fe703d8..4406583 100644 --- a/lib/src/options/default.nix +++ b/lib/src/options/default.nix @@ -4,166 +4,184 @@ 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__ or ""}`:" ( - lib.modules.apply.properties definition.value - ); - normalize = value: { - __file__ = definition.__file__; - inherit value; - }; + 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 - builtins.map normalize properties; + { + inherit + isDefined + values + merged + optional + ; - 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; + 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 + 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) then - builtins.map (module: { - __file__ = option.__file__; - includes = [module]; - }) - getSubModules - ++ result.options - else result.options; + 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 - 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. @@ -174,46 +192,50 @@ 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); + 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."; }; - apply = value: builtins.throw "Cannot read the value of a Sink option."; - }; - in + in lib.options.create (defaults // settings); ## Get the definition values from a list of options definitions. @@ -224,93 +246,94 @@ 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 b136f66..bcc9c4a 100644 --- a/lib/src/types/default.nix +++ b/lib/src/types/default.nix @@ -10,7 +10,7 @@ lib: { ## Assign a type to an attribute set. ## ## @type String -> Attrs -> Attrs - set = name: value: value // {__type__ = name;}; + set = name: value: value // { __type__ = name; }; ## Create a default functor for a type. This handles merging of type values ## by referencing wrapped and payload values. See the types implemented below @@ -28,56 +28,61 @@ lib: { ## Merge two types. ## ## @type Attrs -> Attrs -> Attrs - merge = f: g: let - wrapped = f.wrapped.mergeType g.wrapped.functor; - payload = f.merge f.payload g.payload; - in - if f.name != g.name - then null - else if f.wrapped == null && g.wrapped == null && f.payload == null && g.payload == null - then f.type - else if f.wrapped != null && g.wrapped != null && wrapped != null - then f.type wrapped - else if f.payload != null && g.payload != null && payload != null - then f.type payload - else null; + merge = + f: g: + let + wrapped = f.wrapped.mergeType g.wrapped.functor; + payload = f.merge f.payload g.payload; + in + if f.name != g.name then + null + else if f.wrapped == null && g.wrapped == null && f.payload == null && g.payload == null then + f.type + else if f.wrapped != null && g.wrapped != null && wrapped != null then + f.type wrapped + else if f.payload != null && g.payload != null && payload != null then + f.type payload + else + null; ## Create a new type. ## ## @type Attrs -> Attrs - create = settings @ { - name, - description ? name, - fallback ? {}, - check ? lib.fp.const true, - merge ? lib.options.merge.default, - functor ? lib.types.functor name, - mergeType ? lib.types.merge functor, - getSubOptions ? lib.fp.const {}, - getSubModules ? null, - withSubModules ? lib.fp.const null, - children ? {}, - }: { - __type__ = "type"; - inherit - name - description - fallback - check - merge - functor - mergeType - getSubOptions - getSubModules - withSubModules - children - ; - }; + create = + settings@{ + name, + description ? name, + fallback ? { }, + check ? lib.fp.const true, + merge ? lib.options.merge.default, + functor ? lib.types.functor name, + mergeType ? lib.types.merge functor, + getSubOptions ? lib.fp.const { }, + getSubModules ? null, + withSubModules ? lib.fp.const null, + children ? { }, + }: + { + __type__ = "type"; + inherit + name + description + fallback + check + merge + functor + mergeType + getSubOptions + getSubModules + withSubModules + children + ; + }; ## Add a check to a type. ## ## @type Attrs -> (Any -> Bool) -> Attrs - withCheck = type: check: type // {check = value: type.check value && check value;}; + withCheck = type: check: type // { check = value: type.check value && check value; }; ## A type that allows any value and will only use a single definition. ## @@ -97,58 +102,63 @@ lib: { name = "Any"; description = "any"; check = lib.fp.const true; - merge = location: definitions: let - identifier = lib.options.getIdentifier location; - first = builtins.elemAt definitions 0; + merge = + location: definitions: + let + identifier = lib.options.getIdentifier location; + first = builtins.elemAt definitions 0; - files = builtins.map lib.modules.getFiles definitions; - serializedFiles = builtins.concatStringsSep " and " files; + files = builtins.map lib.modules.getFiles definitions; + serializedFiles = builtins.concatStringsSep " and " files; - getType = value: - if builtins.isAttrs value && lib.strings.validate.stringifiable value - then "StringifiableAttrs" - else builtins.typeOf value; + getType = + value: + if builtins.isAttrs value && lib.strings.validate.stringifiable value then + "StringifiableAttrs" + else + builtins.typeOf value; - commonType = - builtins.foldl' ( + commonType = builtins.foldl' ( type: definition: - if getType definition.value != type - then builtins.throw "The option `${identifier}` has conflicting definitions in ${files}" - else type - ) (getType first.value) - definitions; + if getType definition.value != type then + builtins.throw "The option `${identifier}` has conflicting definitions in ${files}" + else + type + ) (getType first.value) definitions; - mergeStringifiableAttrs = lib.options.merge.one; + mergeStringifiableAttrs = lib.options.merge.one; - mergeSet = (lib.types.attrs.of lib.types.any).merge; + mergeSet = (lib.types.attrs.of lib.types.any).merge; - mergeList = - if builtins.length definitions > 1 - then builtins.throw "The option `${identifier}` has conflicting definitions in ${files}" - else (lib.types.list.of lib.types.any).merge; + mergeList = + if builtins.length definitions > 1 then + builtins.throw "The option `${identifier}` has conflicting definitions in ${files}" + else + (lib.types.list.of lib.types.any).merge; - mergeLambda = location: definitions: x: let - resolvedLocation = location ++ [""]; - resolvedDefinitions = - builtins.map (definition: { - __file__ = definition.__file__; - value = definition.value x; - }) - definitions; + mergeLambda = + location: definitions: x: + let + resolvedLocation = location ++ [ "" ]; + resolvedDefinitions = builtins.map (definition: { + __file__ = definition.__file__; + value = definition.value x; + }) definitions; + in + lib.types.any.merge resolvedLocation resolvedDefinitions; + + merge = + if commonType == "set" then + mergeSet + else if commonType == "list" then + mergeList + else if commonType == "StringifiableAttrs" then + mergeStringifiableAttrs + else if commonType == "lambda" then + mergeLambda + else + lib.options.merge.equal; in - lib.types.any.merge resolvedLocation resolvedDefinitions; - - merge = - if commonType == "set" - then mergeSet - else if commonType == "list" - then mergeList - else if commonType == "StringifiableAttrs" - then mergeStringifiableAttrs - else if commonType == "lambda" - then mergeLambda - else lib.options.merge.equal; - in merge location definitions; }; @@ -182,103 +192,106 @@ lib: { merge = lib.options.merge.equal; }; - ints = let - description = start: end: "${builtins.toString start} and ${builtins.toString end} (inclusive)"; - ## Create a type that allows an integer value between a given range. - ## - ## @type Int -> Int -> Attrs - between = start: end: - assert lib.errors.trace ( - start <= end - ) "lib.types.ints.between start must be less than or equal to end"; + ints = + let + description = start: end: "${builtins.toString start} and ${builtins.toString end} (inclusive)"; + ## Create a type that allows an integer value between a given range. + ## + ## @type Int -> Int -> Attrs + between = + start: end: + assert lib.errors.trace ( + start <= end + ) "lib.types.ints.between start must be less than or equal to end"; lib.types.withCheck lib.types.int (value: value >= start && value <= end) // { name = "IntBetween"; description = "integer between ${description start end}"; }; - ## Create a type that allows an integer value between a given range with a specific - ## number of bits. - ## - ## @type Int -> Int -> Attrs - sign = bits: range: let - start = 0 - (range / 2); - end = range / 2 - 1; - in - between start end - // { - name = "IntSigned${builtins.toString bits}"; - description = "${builtins.toString bits} bit signed integer between ${description start end}"; - }; + ## Create a type that allows an integer value between a given range with a specific + ## number of bits. + ## + ## @type Int -> Int -> Attrs + sign = + bits: range: + let + start = 0 - (range / 2); + end = range / 2 - 1; + in + between start end + // { + name = "IntSigned${builtins.toString bits}"; + description = "${builtins.toString bits} bit signed integer between ${description start end}"; + }; - ## Create a type that allows an unsigned integer value between a given range with a specific - ## number of bits. - ## - ## @type Int -> Int -> Attrs - unsign = bits: range: let - start = 0; - end = range - 1; + ## Create a type that allows an unsigned integer value between a given range with a specific + ## number of bits. + ## + ## @type Int -> Int -> Attrs + unsign = + bits: range: + let + start = 0; + end = range - 1; + in + between start end + // { + name = "IntUnsigned${builtins.toString bits}"; + description = "${builtins.toString bits} bit unsigned integer between ${description start end}"; + }; in - between start end - // { - name = "IntUnsigned${builtins.toString bits}"; - description = "${builtins.toString bits} bit unsigned integer between ${description start end}"; - }; - in { - inherit between; + { + inherit between; - ## A type that allows a positive integer value. - ## - ## @type Attrs - positive = - lib.types.withCheck lib.types.int (value: value > 0) - // { + ## A type that allows a positive integer value. + ## + ## @type Attrs + positive = lib.types.withCheck lib.types.int (value: value > 0) // { name = "IntPositive"; description = "positive integer"; }; - ## A type that allows a positive integer value or zero. - ## - ## @type Attrs - unsigned = - lib.types.withCheck lib.types.int (value: value >= 0) - // { + ## A type that allows a positive integer value or zero. + ## + ## @type Attrs + unsigned = lib.types.withCheck lib.types.int (value: value >= 0) // { name = "IntUnsigned"; description = "unsigned integer"; }; - ## A type that allows an 8bit unsigned integer. - ## - ## @type Attrs - u8 = unsign 8 256; + ## A type that allows an 8bit unsigned integer. + ## + ## @type Attrs + u8 = unsign 8 256; - ## A type that allows a 16bit unsigned integer. - ## - ## @type Attrs - u16 = unsign 16 65536; + ## A type that allows a 16bit unsigned integer. + ## + ## @type Attrs + u16 = unsign 16 65536; - ## A type that allows a 32bit unsigned integer. - ## - ## @type Attrs - u32 = unsign 32 4294967296; + ## A type that allows a 32bit unsigned integer. + ## + ## @type Attrs + u32 = unsign 32 4294967296; - # u64 = unsign 64 18446744073709551616; + # u64 = unsign 64 18446744073709551616; - ## A type that allows an 8bit signed integer. - ## - ## @type Attrs - s8 = sign 8 256; + ## A type that allows an 8bit signed integer. + ## + ## @type Attrs + s8 = sign 8 256; - ## A type that allows a 16bit signed integer. - ## - ## @type Attrs - s16 = sign 16 65536; + ## A type that allows a 16bit signed integer. + ## + ## @type Attrs + s16 = sign 16 65536; - ## A type that allows a 32bit signed integer. - ## - ## @type Attrs - s32 = sign 32 4294967296; - }; + ## A type that allows a 32bit signed integer. + ## + ## @type Attrs + s32 = sign 32 4294967296; + }; ## A type that allows a floating point value. The merged definitions must all be ## the same. @@ -296,43 +309,42 @@ lib: { ## @type Attrs number = lib.types.either lib.types.int lib.types.float; - numbers = let - description = start: end: "${builtins.toString start} and ${builtins.toString end} (inclusive)"; - ## Create a type that allows a number value between a given range. - ## - ## @type Int -> Int -> Attrs - between = start: end: - assert lib.errors.trace ( - start <= end - ) "lib.types.numbers.between start must be less than or equal to end"; + numbers = + let + description = start: end: "${builtins.toString start} and ${builtins.toString end} (inclusive)"; + ## Create a type that allows a number value between a given range. + ## + ## @type Int -> Int -> Attrs + between = + start: end: + assert lib.errors.trace ( + start <= end + ) "lib.types.numbers.between start must be less than or equal to end"; lib.types.withCheck lib.types.number (value: value >= start && value <= end) // { name = "NumberBetween"; description = "numbereger between ${description start end}"; }; - in { - inherit between; + in + { + inherit between; - ## A type that allows a positive number value. - ## - ## @type Attrs - positive = - lib.types.withCheck lib.types.int (value: value > 0) - // { + ## A type that allows a positive number value. + ## + ## @type Attrs + positive = lib.types.withCheck lib.types.int (value: value > 0) // { name = "NumberPositive"; description = "positive number"; }; - ## A type that allows a positive number value or zero. - ## - ## @type Attrs - positiveOrZero = - lib.types.withCheck lib.types.int (value: value >= 0) - // { + ## A type that allows a positive number value or zero. + ## + ## @type Attrs + positiveOrZero = lib.types.withCheck lib.types.int (value: value >= 0) // { name = "NumberPositiveOrZero"; description = "number that is zero or greater"; }; - }; + }; ## A type that allows a port value. This values an unsigned 16bit integer. ## @@ -345,9 +357,11 @@ lib: { version = lib.types.create { name = "Version"; description = "version"; - check = value: let - parts = builtins.splitVersion value; - in + check = + value: + let + parts = builtins.splitVersion value; + in builtins.isString value && builtins.length parts > 0; merge = lib.options.merge.equal; }; @@ -379,7 +393,8 @@ lib: { ## definitions must all be the same. ## ## @type String -> Attrs - matching = pattern: + matching = + pattern: lib.types.create { name = "StringMatching ${pattern}"; description = "string matching the pattern ${pattern}"; @@ -391,34 +406,33 @@ lib: { ## definitions must all be the same. ## ## @type String -> Attrs - concat = separator: + concat = + separator: lib.types.create { name = "StringConcat"; description = - if separator == "" - then "concatenated string" - else "string concatenated with ${builtins.toJSON separator}"; + if separator == "" then + "concatenated string" + else + "string concatenated with ${builtins.toJSON separator}"; check = value: lib.types.string.check value; - merge = location: definitions: + merge = + location: definitions: builtins.concatStringsSep separator (lib.options.getDefinitionValues definitions); - functor = - lib.types.functor "strings.concat" - // { - payload = separator; - merge = x: y: - if x == y - then x - else null; - }; + functor = lib.types.functor "strings.concat" // { + payload = separator; + merge = x: y: if x == y then x else null; + }; }; ## A type that allows a string value that is a single line with an optional new line ## at the end. ## ## @type Attrs - line = let - matcher = lib.types.strings.matching "[^\n\r]*\n?"; - in + line = + let + matcher = lib.types.strings.matching "[^\n\r]*\n?"; + in lib.types.create { name = "StringLine"; description = "single line string with an optional new line at the end"; @@ -441,44 +455,47 @@ lib: { name = "Attrs"; description = "attribute set"; fallback = { - value = {}; + value = { }; }; check = builtins.isAttrs; - merge = location: definitions: - builtins.foldl' (result: definition: result // definition.value) {} definitions; + merge = + location: definitions: + builtins.foldl' (result: definition: result // definition.value) { } definitions; }; ## Create a type that allows an attribute set containing a specific type of value. ## ## @type Attrs -> Attrs - of = type: + of = + type: lib.types.create { name = "AttrsOf"; description = "AttrsOf (${type.name})"; fallback = { - value = {}; + value = { }; }; check = builtins.isAttrs; - merge = location: definitions: let - normalize = definition: - builtins.mapAttrs (name: value: { - __file__ = definition.__file__; - value = value; - }) - definition.value; - normalized = builtins.map normalize definitions; - zipper = name: definitions: (lib.options.merge.definitions (location ++ [name]) type definitions).optional; - filtered = lib.attrs.filter (name: value: value ? value) (builtins.zipAttrsWith zipper normalized); - in + merge = + location: definitions: + let + normalize = + definition: + builtins.mapAttrs (name: value: { + __file__ = definition.__file__; + value = value; + }) definition.value; + normalized = builtins.map normalize definitions; + zipper = + name: definitions: (lib.options.merge.definitions (location ++ [ name ]) type definitions).optional; + filtered = lib.attrs.filter (name: value: value ? value) (builtins.zipAttrsWith zipper normalized); + in builtins.mapAttrs (name: value: value.value) filtered; - getSubOptions = prefix: type.getSubOptions (prefix ++ [""]); + getSubOptions = prefix: type.getSubOptions (prefix ++ [ "" ]); getSubModules = type.getSubModules; withSubModules = modules: lib.types.attrs.of (type.withSubModules modules); - functor = - lib.types.functor "attrs.of" - // { - wrapped = type; - }; + functor = lib.types.functor "attrs.of" // { + wrapped = type; + }; children = { element = type; }; @@ -489,36 +506,39 @@ lib: { ## not support certain properties like `lib.modules.when`. ## ## @type Attrs -> Attrs - lazy = type: + lazy = + type: lib.types.create { name = "LazyAttrsOf"; description = "LazyAttrsOf (${type.name})"; fallback = { - value = {}; + value = { }; }; check = builtins.isAttrs; - merge = location: definitions: let - normalize = definition: - builtins.mapAttrs (name: value: { - __file__ = definition.__file__; - value = value; - }) - definition.value; - normalized = builtins.map normalize definitions; - zipper = name: definitions: let - merged = lib.options.merge.definitions (location ++ [name]) type definitions; + merge = + location: definitions: + let + normalize = + definition: + builtins.mapAttrs (name: value: { + __file__ = definition.__file__; + value = value; + }) definition.value; + normalized = builtins.map normalize definitions; + zipper = + name: definitions: + let + merged = lib.options.merge.definitions (location ++ [ name ]) type definitions; + in + merged.optional.value or type.fallback.value or merged.merged; in - merged.optional.value or type.fallback.value or merged.merged; - in builtins.zipAttrsWith zipper normalized; - getSubOptions = prefix: type.getSubOptions (prefix ++ [""]); + getSubOptions = prefix: type.getSubOptions (prefix ++ [ "" ]); getSubModules = type.getSubModules; withSubModules = modules: lib.types.attrs.lazy (type.withSubModules modules); - functor = - lib.types.functor "attrs.lazy" - // { - wrapped = type; - }; + functor = lib.types.functor "attrs.lazy" // { + wrapped = type; + }; children = { element = type; }; @@ -532,12 +552,15 @@ lib: { name = "Derivation"; description = "derivation"; check = value: lib.packages.isDerivation value || lib.paths.validate.store value; - merge = location: definitions: let - merged = lib.options.merge.one location definitions; - in - if builtins.isPath merged || (builtins.isString merged && !(builtins.hasContext merged)) - then lib.paths.into.drv merged - else merged; + merge = + location: definitions: + let + merged = lib.options.merge.one location definitions; + in + if builtins.isPath merged || (builtins.isString merged && !(builtins.hasContext merged)) then + lib.paths.into.drv merged + else + merged; }; derivations = { @@ -545,11 +568,9 @@ lib: { ## `shellPath` attribute. ## ## @type Attrs - shell = - lib.types.derivation - // { - check = value: lib.packages.isDerivation && builtins.hasAttr "shellPath" value; - }; + shell = lib.types.derivation // { + check = value: lib.packages.isDerivation && builtins.hasAttr "shellPath" value; + }; }; ## A type that allows a path value. The merged definitions must all be the same. @@ -558,7 +579,8 @@ lib: { path = lib.types.create { name = "Path"; description = "path"; - check = value: + check = + value: lib.strings.validate.stringifiable value && builtins.substring 0 1 (builtins.toString value) == "/"; merge = lib.options.merge.equal; }; @@ -572,22 +594,25 @@ lib: { ## Create a type that allows a list containing a specific type of value. ## ## @type Attrs -> Attrs - of = type: + of = + type: lib.types.create { name = "ListOf"; description = "ListOf (${type.name})"; fallback = { - value = []; + value = [ ]; }; check = builtins.isList; - merge = location: definitions: let - result = - lib.lists.mapWithIndex1 ( + merge = + location: definitions: + let + result = lib.lists.mapWithIndex1 ( i: definition: - lib.lists.mapWithIndex1 ( - j: value: let - resolved = - lib.options.merge.definitions (location ++ ["[definition ${builtins.toString i}-entry ${j}]"]) + lib.lists.mapWithIndex1 ( + j: value: + let + resolved = + lib.options.merge.definitions (location ++ [ "[definition ${builtins.toString i}-entry ${j}]" ]) type [ { @@ -595,25 +620,21 @@ lib: { value = value; } ]; - in - resolved.optional - ) - definition.value - ) - definitions; - merged = builtins.concatLists result; - filtered = builtins.filter (definition: definition ? value) merged; - values = lib.options.getDefinitionValues filtered; - in + in + resolved.optional + ) definition.value + ) definitions; + merged = builtins.concatLists result; + filtered = builtins.filter (definition: definition ? value) merged; + values = lib.options.getDefinitionValues filtered; + in values; - getSubOptions = prefix: type.getSubOptions (prefix ++ ["*"]); + getSubOptions = prefix: type.getSubOptions (prefix ++ [ "*" ]); getSubModules = type.getSubModules; withSubModules = modules: lib.types.list.of (type.withSubModules modules); - functor = - lib.types.functor "list.of" - // { - wrapped = type; - }; + functor = lib.types.functor "list.of" // { + wrapped = type; + }; children = { element = type; }; @@ -622,18 +643,20 @@ lib: { ## A type that allows a non-empty list containing a specific type of value. ## ## @type Attrs -> Attrs - required = type: - lib.types.withCheck (lib.types.list.of type) (value: value != []) + required = + type: + lib.types.withCheck (lib.types.list.of type) (value: value != [ ]) // { description = "non-empty list of ${type.description}"; - fallback = {}; + fallback = { }; }; }; ## Create a type that must be a unique value. ## ## @type String -> Attrs -> Attrs - unique = message: type: + unique = + message: type: lib.types.create { name = "Unique"; description = type.description; @@ -643,11 +666,9 @@ lib: { getSubOptions = type.getSubOptions; getSubModules = type.getSubModules; withSubModules = modules: lib.types.unique message (type.withSubModules modules); - functor = - lib.types.functor "unique" - // { - wrapped = type; - }; + functor = lib.types.functor "unique" // { + wrapped = type; + }; children = { element = type; }; @@ -657,7 +678,8 @@ lib: { ## does not merge the definitions. ## ## @type Attrs -> Attrs - single = type: + single = + type: lib.types.create { name = "Single"; description = type.description; @@ -667,11 +689,9 @@ lib: { getSubOptions = type.getSubOptions; getSubModules = type.getSubModules; withSubModules = modules: lib.types.single (type.withSubModules modules); - functor = - lib.types.functor "unique" - // { - wrapped = type; - }; + functor = lib.types.functor "unique" // { + wrapped = type; + }; children = { element = type; }; @@ -680,7 +700,8 @@ lib: { ## Create a type that may be either a given type or null. ## ## @type Attrs -> Attrs - nullish = type: + nullish = + type: lib.types.create { name = "Nullish"; description = "null or ${type.description}"; @@ -688,25 +709,26 @@ lib: { value = null; }; check = value: value == null || type.check value; - merge = location: definitions: let - identifier = lib.options.getIdentifier location; - files = builtins.map lib.modules.getFiles definitions; - serializedFiles = builtins.concatStringsSep " and " files; - totalNulls = lib.lists.count (definition: definition == null) definitions; - in - if totalNulls == builtins.length definitions - then null - else if totalNulls != 0 - then builtins.throw "The option `${identifier}` is defined as both null and not null in ${serializedFiles}" - else type.merge location definitions; + merge = + location: definitions: + let + identifier = lib.options.getIdentifier location; + files = builtins.map lib.modules.getFiles definitions; + serializedFiles = builtins.concatStringsSep " and " files; + totalNulls = lib.lists.count (definition: definition == null) definitions; + in + if totalNulls == builtins.length definitions then + null + else if totalNulls != 0 then + builtins.throw "The option `${identifier}` is defined as both null and not null in ${serializedFiles}" + else + type.merge location definitions; getSubOptions = type.getSubOptions; getSubModules = type.getSubModules; withSubModules = modules: lib.types.nullish (type.withSubModules modules); - functor = - lib.types.functor "nullish" - // { - wrapped = type; - }; + functor = lib.types.functor "nullish" // { + wrapped = type; + }; children = { element = type; }; @@ -715,28 +737,29 @@ lib: { ## Create a type that allows a function which returns a given type. ## ## @type Attrs -> Attrs - function = type: + function = + type: lib.types.create { name = "Function"; description = "function that returns ${type.description}"; check = builtins.isFunction; - merge = location: definitions: args: let - normalize = definition: { - __file__ = definition.__file__; - value = definition.value args; - }; - normalized = builtins.map normalize definitions; - merged = lib.options.merge.definitions (location ++ [""]) type normalized; - in + merge = + location: definitions: args: + let + normalize = definition: { + __file__ = definition.__file__; + value = definition.value args; + }; + normalized = builtins.map normalize definitions; + merged = lib.options.merge.definitions (location ++ [ "" ]) type normalized; + in merged.merged; - getSubOptions = prefix: type.getSubOptions (prefix ++ [""]); + getSubOptions = prefix: type.getSubOptions (prefix ++ [ "" ]); getSubModules = type.getSubModules; withSubModules = modules: lib.types.function (type.withSubModules modules); - functor = - lib.types.functor "function" - // { - wrapped = type; - }; + functor = lib.types.functor "function" // { + wrapped = type; + }; children = { element = type; }; @@ -745,7 +768,7 @@ lib: { ## Create a submodule from a list of modules (or a module directly). ## ## @type (Module | (List Module)) -> Attrs - submodule = modules: lib.types.submodules.of {modules = lib.lists.from.any modules;}; + submodule = modules: lib.types.submodules.of { modules = lib.lists.from.any modules; }; submodules = { ## Create a type from a list of submodules. This is particularly useful for use @@ -753,85 +776,85 @@ lib: { ## dynamic types. ## ## @type { modules :: List Module, args? :: Attrs, description? :: String | Null, shorthand? :: Bool } -> Attrs - of = settings @ { - modules, - args ? {}, - description ? null, - shorthand ? true, - }: let - getModules = builtins.map ( - definition: - if shorthand && builtins.isAttrs definition.value - then let - # TODO: Figure out if we can apply additional attributes to the generated module. - # Currently this causes issues to do with redefined options. - rest = builtins.removeAttrs (lib.attrs.filter ( + of = + settings@{ + modules, + args ? { }, + description ? null, + shorthand ? true, + }: + let + getModules = builtins.map ( + definition: + if shorthand && builtins.isAttrs definition.value then + let + # TODO: Figure out if we can apply additional attributes to the generated module. + # Currently this causes issues to do with redefined options. + rest = builtins.removeAttrs (lib.attrs.filter ( name: value: builtins.elem name lib.modules.VALID_KEYS - ) - definition.value) ["freeform"]; - in - if definition.value ? config - then + ) definition.value) [ "freeform" ]; + in + if definition.value ? config then rest // { __file__ = definition.__file__; config = definition.value.config; } - else let - config = builtins.removeAttrs definition.value lib.modules.VALID_KEYS; - in + else + let + config = builtins.removeAttrs definition.value lib.modules.VALID_KEYS; + in rest // { __file__ = definition.__file__; config = config; } - else { - __file__ = definition.__file__; - includes = [definition.value]; - } - ); + else + { + __file__ = definition.__file__; + includes = [ definition.value ]; + } + ); - base = lib.modules.run { - inherit args; + base = lib.modules.run { + inherit args; - modules = - [ - {config.__module__.args.dynamic.name = lib.modules.overrides.default "";} - ] - ++ modules; - }; + modules = [ + { config.__module__.args.dynamic.name = lib.modules.overrides.default ""; } + ] ++ modules; + }; - freeform = base.__module__.freeform; - name = "Submodule"; - in + freeform = base.__module__.freeform; + name = "Submodule"; + in lib.types.create { inherit name; - description = - if description != null - then description - else freeform.description or name; + description = if description != null then description else freeform.description or name; fallback = { - value = {}; + value = { }; }; check = value: builtins.isAttrs value || builtins.isFunction value || lib.types.path.check value; - merge = location: definitions: let - result = base.extend { - prefix = location; - modules = - [ - {config.__module__.args.dynamic.name = lib.lists.last location;} - ] - ++ getModules definitions; - }; - in + merge = + location: definitions: + let + result = base.extend { + prefix = location; + modules = [ + { config.__module__.args.dynamic.name = lib.lists.last location; } + ] ++ getModules definitions; + }; + in result.config; - getSubOptions = prefix: let - result = base.extend {inherit prefix;}; - in + getSubOptions = + prefix: + let + result = base.extend { inherit prefix; }; + in result.options - // lib.attrs.when (freeform != null) {__freeformOptions__ = freeform.getSubOptions prefix;}; + // lib.attrs.when (freeform != null) { __freeformOptions__ = freeform.getSubOptions prefix; }; getSubModules = modules; - withSubModules = modules: + withSubModules = + modules: lib.types.submodules.of { inherit args @@ -840,39 +863,40 @@ lib: { shorthand ; }; - children = lib.attrs.when (freeform != null) {inherit freeform;}; - functor = - lib.types.functor "submodule" - // { - type = lib.types.submodules.of; - payload = { - inherit - modules - args - description - shorthand - ; - }; - merge = x: y: { - modules = x.modules ++ y.modules; + children = lib.attrs.when (freeform != null) { inherit freeform; }; + functor = lib.types.functor "submodule" // { + type = lib.types.submodules.of; + payload = { + inherit + modules + args + description + shorthand + ; + }; + merge = x: y: { + modules = x.modules ++ y.modules; - args = let + args = + let intersection = builtins.intersectAttrs x.args y.args; in - if intersection == {} - then x.args // y.args - else builtins.throw "A submodule option is declared multiple times with the same args: ${builtins.toString (builtins.attrNames intersection)}"; + if intersection == { } then + x.args // y.args + else + builtins.throw "A submodule option is declared multiple times with the same args: ${builtins.toString (builtins.attrNames intersection)}"; - description = - if x.description == null - then y.description - else if y.description == null - then x.description - else if x.description == y.description - then x.description - else builtins.throw "A submodule description is declared multiple times with conflicting values"; - }; + description = + if x.description == null then + y.description + else if y.description == null then + x.description + else if x.description == y.description then + x.description + else + builtins.throw "A submodule description is declared multiple times with conflicting values"; }; + }; }; }; @@ -880,15 +904,17 @@ lib: { ## A module that is imported in another part of the configuration. ## ## @type Attrs - default = lib.types.deferred.of {modules = [];}; + default = lib.types.deferred.of { modules = [ ]; }; ## Create a submodule type from a list of modules which will be imported in ## another part of the configuration. ## ## @type { modules :: List Module } -> Attrs - of = settings @ {modules}: let - submodule = lib.types.submodule modules; - in + of = + settings@{ modules }: + let + submodule = lib.types.submodule modules; + in lib.types.create { name = "Deferred"; description = "module"; @@ -898,22 +924,19 @@ lib: { modules ++ builtins.map (definition: { __file__ = "${definition.__file__}; via ${lib.options.getIdentifier location}"; - includes = [definition.value]; - }) - definitions; + includes = [ definition.value ]; + }) definitions; }; getSubOptions = submodule.getSubOptions; getSubModules = submodule.getSubModules; - withSubModules = modules: lib.types.deferred.of {modules = modules;}; - functor = - lib.types.functor "deferred.of" - // { - type = lib.types.deferred.of; - payload = { - inherit modules; - }; - merge = x: y: {modules = x.modules ++ y.modules;}; + withSubModules = modules: lib.types.deferred.of { modules = modules; }; + functor = lib.types.functor "deferred.of" // { + type = lib.types.deferred.of; + payload = { + inherit modules; }; + merge = x: y: { modules = x.modules ++ y.modules; }; + }; }; }; @@ -934,87 +957,94 @@ lib: { name = "Option"; description = "option"; check = lib.types.is "option"; - merge = location: definitions: let - first = builtins.elemAt definitions 0; - modules = - builtins.map (definition: { + merge = + location: definitions: + let + first = builtins.elemAt definitions 0; + modules = builtins.map (definition: { __file__ = definition.__file__; - options = lib.options.create {type = definition.value;}; - }) - definitions; - merged = lib.modules.fixup location (lib.options.merge.declarations location modules); - in - if builtins.length definitions == 1 - then first.value - else merged.type; + options = lib.options.create { type = definition.value; }; + }) definitions; + merged = lib.modules.fixup location (lib.options.merge.declarations location modules); + in + if builtins.length definitions == 1 then first.value else merged.type; }; ## Create a type that allows a specific primitive value from a given list. ## ## @type List Any -> Attrs - enum = values: let - serialize = value: - if builtins.isString value - then ''"${value}"'' - else if builtins.isInt value - then builtins.toString value - else if builtins.isBool value - then lib.bools.into.string value - else ''<${builtins.typeOf value}>''; - in + enum = + values: + let + serialize = + value: + if builtins.isString value then + ''"${value}"'' + else if builtins.isInt value then + builtins.toString value + else if builtins.isBool value then + lib.bools.into.string value + else + ''<${builtins.typeOf value}>''; + in lib.types.create { name = "Enum"; description = - if values == [] - then "empty enum" - else if builtins.length values == 1 - then "value ${serialize (builtins.elemAt values 0)} (singular enum)" - else "one of ${lib.strings.concatMapSep ", " serialize values}"; + if values == [ ] then + "empty enum" + else if builtins.length values == 1 then + "value ${serialize (builtins.elemAt values 0)} (singular enum)" + else + "one of ${lib.strings.concatMapSep ", " serialize values}"; check = value: builtins.elem value values; merge = lib.options.merge.equal; - functor = - lib.types.functor "enum" - // { - payload = values; - merge = x: y: lib.lists.unique (x ++ y); - }; + functor = lib.types.functor "enum" // { + payload = values; + merge = x: y: lib.lists.unique (x ++ y); + }; }; ## Create a type that allows either of two types. ## ## @type Attrs -> Attrs -> Attrs - either = left: right: let - name = "Either"; - functor = - lib.types.functor name - // { + either = + left: right: + let + name = "Either"; + functor = lib.types.functor name // { wrapped = [ left right ]; }; - in + in lib.types.create { inherit name functor; description = "${left.description} or ${right.description}"; check = value: left.check value || right.check value; - merge = location: definitions: let - values = lib.options.getDefinitionValues definitions; - isLeft = builtins.all left.check values; - isRight = builtins.all right.check values; - in - if isLeft - then left.merge location definitions - else if isRight - then right.merge location definitions - else lib.options.merge.one location definitions; - mergeType = f: let - mergedLeft = left.mergeType (builtins.elemAt f.wrapped 0).functor; - mergedRight = right.mergeType (builtins.elemAt f.wrapped 1).functor; - in - if (f.name == name) && (mergedLeft != null) && (mergedRight != null) - then functor.type mergedLeft mergedRight - else null; + merge = + location: definitions: + let + values = lib.options.getDefinitionValues definitions; + isLeft = builtins.all left.check values; + isRight = builtins.all right.check values; + in + if isLeft then + left.merge location definitions + else if isRight then + right.merge location definitions + else + lib.options.merge.one location definitions; + mergeType = + f: + let + mergedLeft = left.mergeType (builtins.elemAt f.wrapped 0).functor; + mergedRight = right.mergeType (builtins.elemAt f.wrapped 1).functor; + in + if (f.name == name) && (mergedLeft != null) && (mergedRight != null) then + functor.type mergedLeft mergedRight + else + null; children = { inherit left right; }; @@ -1023,46 +1053,48 @@ lib: { ## Create a type that allows a value of one of the given types. ## ## @type List Attrs -> Attrs - one = types: let - first = builtins.elemAt types 0; - rest = builtins.tail types; - in - if types == [] - then builtins.throw "lib.types.one must be given at least one type" - else builtins.foldl' lib.types.either first rest; + one = + types: + let + first = builtins.elemAt types 0; + rest = builtins.tail types; + in + if types == [ ] then + builtins.throw "lib.types.one must be given at least one type" + else + builtins.foldl' lib.types.either first rest; ## 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 - coerce = initial: transform: final: let - in - if initial.getSubModules != null - then builtins.throw "lib.types.coerce's first argument may not have submodules, but got ${initial.description}" + coerce = + initial: transform: final: + let + in + if initial.getSubModules != null then + builtins.throw "lib.types.coerce'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 value - else value; - normalize = definition: definition // {value = process definition.value;}; - normalized = builtins.map normalize definitions; - in + merge = + location: definitions: + let + process = value: if initial.check value then transform 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.coerce initial transform (final.withSubModules modules); mergeType = x: y: null; - functor = - lib.types.functor "coerce" - // { - wrapped = final; - }; + functor = lib.types.functor "coerce" // { + wrapped = final; + }; children = { inherit initial final; }; @@ -1072,34 +1104,34 @@ lib: { ## 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}" + 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 + 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); + withSubModules = + modules: lib.types.coerceWithLocation initial transform (final.withSubModules modules); mergeType = x: y: null; - functor = - lib.types.functor "coerceWithLocation" - // { - wrapped = final; - }; + functor = lib.types.functor "coerceWithLocation" // { + wrapped = final; + }; children = { inherit initial final; }; @@ -1109,23 +1141,23 @@ lib: { ## Create a type that allows a DAG (Directed Acyclic Graph) of a given type. ## ## @type Attrs -> Attrs - of = type: let - resolved = lib.types.attrs.of (lib.types.dag.entry type); - in + of = + type: + let + resolved = lib.types.attrs.of (lib.types.dag.entry type); + in lib.types.create { name = "Dag"; description = "Dag of ${type.description}"; check = resolved.check; merge = resolved.merge; fallback = resolved.fallback; - getSubOptions = prefix: type.getSubOptions (prefix ++ [""]); + getSubOptions = prefix: type.getSubOptions (prefix ++ [ "" ]); getSubModules = type.getSubModules; withSubModules = modules: lib.types.dag.of (type.withSubModules modules); - functor = - lib.types.functor "dag.of" - // { - wrapped = type; - }; + functor = lib.types.functor "dag.of" // { + wrapped = type; + }; children = { element = type; resolved = resolved; @@ -1135,36 +1167,40 @@ lib: { ## Create a type that allows a DAG entry of a given type. ## ## @type Attrs -> Attrs - entry = type: let - submodule = lib.types.submodule ( - {name}: { - options = { - value = lib.options.create {type = type;}; - before = lib.options.create {type = lib.types.list.of lib.types.string;}; - after = lib.options.create {type = lib.types.list.of lib.types.string;}; - }; - } - ); - normalize = definition: let - value = - if definition ? priority - then lib.modules.order definition.priority definition.value - else definition.value; + entry = + type: + let + submodule = lib.types.submodule ( + { name }: + { + options = { + value = lib.options.create { type = type; }; + before = lib.options.create { type = lib.types.list.of lib.types.string; }; + after = lib.options.create { type = lib.types.list.of lib.types.string; }; + }; + } + ); + normalize = + definition: + let + value = + if definition ? priority then + lib.modules.order definition.priority definition.value + else + definition.value; + in + if lib.dag.validate.entry definition.value then definition.value else lib.dag.entry.anywhere value; in - if lib.dag.validate.entry definition.value - then definition.value - else lib.dag.entry.anywhere value; - in lib.types.create { name = "DagEntry"; description = "DagEntry (${type.description})"; - merge = location: definitions: + merge = + location: definitions: submodule.merge location ( builtins.map (definition: { __file__ = definition.__file__; value = normalize definition; - }) - definitions + }) definitions ); }; }; diff --git a/tidepool/src/builders/basic.nix b/tidepool/src/builders/basic.nix index 1a8d460..0e2cee1 100644 --- a/tidepool/src/builders/basic.nix +++ b/tidepool/src/builders/basic.nix @@ -1,88 +1,85 @@ -{ - lib, - config, -}: let +{ lib, config }: +let cfg = config.builders.basic; lib' = config.lib; inherit (config) foundation; -in { +in +{ config.builders = { basic = { executable = "${foundation.stage2-bash}/bin/bash"; - build = package: let - phases = lib.dag.apply.defaults package.phases { - unpack = lib.dag.entry.before ["patch"] ""; + build = + package: + let + phases = lib.dag.apply.defaults package.phases { + unpack = lib.dag.entry.before [ "patch" ] ""; - patch = lib.dag.entry.between ["configure"] ["unpack"] ""; + patch = lib.dag.entry.between [ "configure" ] [ "unpack" ] ""; - configure = lib.dag.entry.between ["build"] ["patch"] ""; + configure = lib.dag.entry.between [ "build" ] [ "patch" ] ""; - build = lib.dag.entry.between ["install"] ["configure"] ""; + build = lib.dag.entry.between [ "install" ] [ "configure" ] ""; - install = lib.dag.entry.after ["build"] ""; - }; - sorted = lib.dag.sort.topographic phases; + install = lib.dag.entry.after [ "build" ] ""; + }; + sorted = lib.dag.sort.topographic phases; - script = - lib.strings.concatMapSep "\n" ( - entry: - if builtins.isFunction entry.value - then entry.value package - else entry.value - ) - sorted.result; + script = lib.strings.concatMapSep "\n" ( + entry: if builtins.isFunction entry.value then entry.value package else entry.value + ) sorted.result; - system = package.platform.build.double; + system = package.platform.build.double; - built = builtins.derivation ( - package.env - // { - inherit (package) name; - inherit script system; + built = builtins.derivation ( + package.env + // { + inherit (package) name; + inherit script system; - passAsFile = ["script"]; + passAsFile = [ "script" ]; - SHELL = cfg.executable; + SHELL = cfg.executable; - PATH = let - bins = lib.paths.bin ( - (lib'.packages.dependencies.getPackages package.deps.build.host) - ++ [ - foundation.stage2-bash - foundation.stage2-coreutils - ] - ); - in - builtins.concatStringsSep ":" ( - [bins] ++ (lib.lists.when (package.env ? PATH) [package.env.PATH]) - ); + PATH = + let + bins = lib.paths.bin ( + (lib'.packages.dependencies.getPackages package.deps.build.host) + ++ [ + foundation.stage2-bash + foundation.stage2-coreutils + ] + ); + in + builtins.concatStringsSep ":" ( + [ bins ] ++ (lib.lists.when (package.env ? PATH) [ package.env.PATH ]) + ); - builder = cfg.executable; + builder = cfg.executable; - args = [ - "-e" - (builtins.toFile "bash-builder.sh" '' - export CONFIG_SHELL=$SHELL + args = [ + "-e" + (builtins.toFile "bash-builder.sh" '' + export CONFIG_SHELL=$SHELL - # Normalize the NIX_BUILD_CORES variable. The value might be 0, which - # means that we're supposed to try and auto-detect the number of - # available CPU cores at run-time. - NIX_BUILD_CORES="''${NIX_BUILD_CORES:-1}" - if ((NIX_BUILD_CORES <= 0)); then - guess=$(nproc 2>/dev/null || true) - ((NIX_BUILD_CORES = guess <= 0 ? 1 : guess)) - fi - export NIX_BUILD_CORES + # Normalize the NIX_BUILD_CORES variable. The value might be 0, which + # means that we're supposed to try and auto-detect the number of + # available CPU cores at run-time. + NIX_BUILD_CORES="''${NIX_BUILD_CORES:-1}" + if ((NIX_BUILD_CORES <= 0)); then + guess=$(nproc 2>/dev/null || true) + ((NIX_BUILD_CORES = guess <= 0 ? 1 : guess)) + fi + export NIX_BUILD_CORES - bash -eux $scriptPath - '') - ]; - } - ); - in + bash -eux $scriptPath + '') + ]; + } + ); + in built // { inherit (package) meta; diff --git a/tidepool/src/export.nix b/tidepool/src/export.nix index f464865..56a470e 100644 --- a/tidepool/src/export.nix +++ b/tidepool/src/export.nix @@ -1,8 +1,10 @@ # This file handles creating all of the exports for this project and is not # exported itself. -{config}: let +{ config }: +let inherit (config) lib; -in { +in +{ # freeform = lib.types.any; config = { diff --git a/tidepool/src/lib/options.nix b/tidepool/src/lib/options.nix index 4850da0..e9370d2 100644 --- a/tidepool/src/lib/options.nix +++ b/tidepool/src/lib/options.nix @@ -1,8 +1,7 @@ +{ lib, config }: +let +in { - lib, - config, -}: let -in { config = { lib.options = { package = lib.options.create { diff --git a/tidepool/src/lib/packages.nix b/tidepool/src/lib/packages.nix index 2586246..f981a57 100644 --- a/tidepool/src/lib/packages.nix +++ b/tidepool/src/lib/packages.nix @@ -1,56 +1,62 @@ -{ - lib, - config, -}: let +{ lib, config }: +let lib' = config.lib; -in { +in +{ config = { lib.packages = { dependencies = { - getPackages = dependencies: let - available = builtins.filter (dependency: !(builtins.isNull dependency)) ( - builtins.attrValues dependencies - ); - in + getPackages = + dependencies: + let + available = builtins.filter (dependency: !(builtins.isNull dependency)) ( + builtins.attrValues dependencies + ); + in builtins.map (dependency: dependency.package) available; - build = build': host': target': - builtins.mapAttrs - (name: dep: lib'.packages.build dep build' host' target'); + build = + build': host': target': + builtins.mapAttrs (name: dep: lib'.packages.build dep build' host' target'); }; - getLatest = alias: let - versions = builtins.attrNames alias.versions; - sorted = builtins.sort (lib.versions.gte) versions; - in + getLatest = + alias: + let + versions = builtins.attrNames alias.versions; + sorted = builtins.sort (lib.versions.gte) versions; + in builtins.head sorted; - resolve = alias: - if alias ? versions - then + resolve = + alias: + if alias ? versions then alias.versions.${config.preferences.packages.version} - or (alias.versions.${lib'.packages.getLatest alias}) - else alias; + or (alias.versions.${lib'.packages.getLatest alias}) + else + alias; - build = alias: build: host: target: let - package = lib'.packages.resolve alias; + 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'); + buildDependencies = + build': host': target': + builtins.mapAttrs (name: dep: lib'.packages.build dep build' host' target'); - platform = { - build = lib.modules.overrides.force build; - host = lib.modules.overrides.force host; - target = lib.modules.overrides.force target; - }; + platform = { + build = lib.modules.overrides.force build; + host = lib.modules.overrides.force host; + target = lib.modules.overrides.force target; + }; - withPlatform = lib.modules.run { - modules = - package.__modules__ - ++ [ + withPlatform = lib.modules.run { + modules = package.__modules__ ++ [ lib'.types.package.children.submodule ( - {config}: { + { config }: + { config = { __modules__ = package.__modules__; @@ -59,14 +65,12 @@ in { } ) ]; - }; + }; - # Not all platform information can be effectively handled via submodules. To handle - # the case where a user copies the resolved config over we need to ensure that - # dependencies are appropriately updated. - withDeps = - withPlatform.config - // { + # Not all platform information can be effectively handled via submodules. To handle + # the case where a user copies the resolved config over we need to ensure that + # dependencies are appropriately updated. + withDeps = withPlatform.config // { deps = { build = { only = buildDependencies build build build withPlatform.config.deps.build.only; @@ -86,13 +90,12 @@ in { }; }; - withPackage = lib.modules.run { - modules = - package.__modules__ - ++ [ + withPackage = lib.modules.run { + modules = package.__modules__ ++ [ lib'.types.package.children.submodule ( - {config}: { + { config }: + { config = { __modules__ = package.__modules__; @@ -105,8 +108,8 @@ in { } ) ]; - }; - in + }; + in withPackage.config; }; }; diff --git a/tidepool/src/lib/systems.nix b/tidepool/src/lib/systems.nix index 0c99f98..0ca7790 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,51 +600,52 @@ 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" @@ -924,29 +925,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 ( [ @@ -956,8 +957,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 ( [ @@ -967,24 +968,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. @@ -1004,9 +1005,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" @@ -1017,33 +1018,36 @@ 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 ( @@ -1058,114 +1062,96 @@ 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 ) @@ -1186,13 +1172,8 @@ 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 { @@ -1211,7 +1192,8 @@ 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); }; @@ -1232,13 +1214,14 @@ 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 @@ -1249,7 +1232,8 @@ in { name = "systemWithBuildInfo"; description = "fully parsed representation of llvm- or nix-style platform tuple with build information"; merge = lib.options.merge.one; - check = value: + check = + value: lib.types.is "systemWithBuildInfo" value && value ? system && lib'.systems.types.platform.check value.system; @@ -1258,8 +1242,8 @@ in { endian = lib.types.enum (builtins.attrValues types.endians); endians = setTypes types.generic.endian { - big = {}; - little = {}; + big = { }; + little = { }; }; bits = lib.types.enum [ @@ -1273,34 +1257,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); @@ -1342,7 +1326,7 @@ in { }; linux = { exec = types.execs.elf; - families = {}; + families = { }; }; netbsd = { exec = types.execs.elf; @@ -1352,7 +1336,7 @@ in { }; none = { exec = types.execs.unknown; - families = {}; + families = { }; }; openbsd = { exec = types.execs.elf; @@ -1362,31 +1346,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 @@ -1679,8 +1663,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. @@ -1693,9 +1677,9 @@ in { }; # Other architectures should use ELF in embedded situations. - elf = {}; + elf = { }; - androideabi = {}; + androideabi = { }; android = { assertions = [ { @@ -1759,7 +1743,7 @@ in { musleabihf = { float = "hard"; }; - musl = {}; + musl = { }; uclibceabi = { float = "soft"; @@ -1767,169 +1751,187 @@ 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 @@ -1942,23 +1944,23 @@ in { "ghcjs" "mingw32" ]) - then { + 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 + { cpu = first; vendor = second; - kernel = - if third == "mingw32" - then "windows" - else third; + kernel = third; + abi = fourth; } - 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}."; + else + builtins.throw "Invalid component count for creating system skeleton. Expected 1-4, but got ${builtins.toString length}."; patterns = { isi686 = { @@ -2019,16 +2021,17 @@ 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"; @@ -2180,16 +2183,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; @@ -2275,10 +2278,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 @@ -2287,14 +2290,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 @@ -2540,288 +2543,268 @@ 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 ""; + 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; }; - 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; + useAndroidPrebuilt = false; + useiOSPrebuilt = false; - 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; + 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; - release = null; - }; + 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 - useAndroidPrebuilt = false; - useiOSPrebuilt = false; + 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; - 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; + 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; - 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 + darwin = { + arch = + if resolved.system.cpu.name == "armv7a" then + "armv7" + else if resolved.system.cpu.name == "aarch64" then + "arm64" + else + resolved.system.cpu.name; - 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; + platform = + if resolved.isMacOS then + "macos" + else if resolved.isiOS then + "ios" + else + null; - 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; + sdk = { + version = resolved.darwinSdkVersion or (if resolved.isAarch64 then "11.0" else "10.12"); - darwin = { - arch = - if resolved.system.cpu.name == "armv7a" - then "armv7" - else if resolved.system.cpu.name == "aarch64" - then "arm64" - else resolved.system.cpu.name; + min = resolved.darwin.sdk.version; - 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; + 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. - lib.types.set "systemWithBuildInfo" resolved; + lib.types.set "systemWithBuildInfo" resolved; }; }; } diff --git a/tidepool/src/lib/types.nix b/tidepool/src/lib/types.nix index cac0fd1..3444c14 100644 --- a/tidepool/src/lib/types.nix +++ b/tidepool/src/lib/types.nix @@ -1,65 +1,64 @@ -{ - lib, - config, -}: let +{ lib, config }: +let inherit (config) preferences builders; lib' = config.lib; -in { +in +{ config = { lib.types = { - license = let - type = lib.types.submodule ( - {config}: { - options = { - name = { - full = lib.options.create { - description = "The full name of the license."; - type = lib.types.string; + license = + let + type = lib.types.submodule ( + { config }: + { + options = { + name = { + full = lib.options.create { + description = "The full name of the license."; + type = lib.types.string; + }; + + short = lib.options.create { + description = "The short name of the license."; + type = lib.types.string; + }; }; - short = lib.options.create { - description = "The short name of the license."; - type = lib.types.string; + spdx = lib.options.create { + description = "The SPDX identifier for the license."; + type = lib.types.nullish lib.types.string; + default.value = null; + }; + + url = lib.options.create { + description = "The URL for the license."; + type = lib.types.nullish lib.types.string; + }; + + free = lib.options.create { + description = "Whether the license is free."; + type = lib.types.bool; + default.value = true; + }; + + redistributable = lib.options.create { + description = "Whether the license is allows redistribution."; + type = lib.types.bool; + default = { + text = "config.free"; + value = config.free; + }; }; }; - - spdx = lib.options.create { - description = "The SPDX identifier for the license."; - type = lib.types.nullish lib.types.string; - default.value = null; - }; - - url = lib.options.create { - description = "The URL for the license."; - type = lib.types.nullish lib.types.string; - }; - - free = lib.options.create { - description = "Whether the license is free."; - type = lib.types.bool; - default.value = true; - }; - - redistributable = lib.options.create { - description = "Whether the license is allows redistribution."; - type = lib.types.bool; - default = { - text = "config.free"; - value = config.free; - }; - }; - }; - } - ); - in + } + ); + in lib.types.either type (lib.types.list.of type); platform = - lib.types.coerce - lib.types.string - lib'.systems.withBuildInfo - lib'.systems.types.platformWithBuildInfo; + lib.types.coerce lib.types.string lib'.systems.withBuildInfo + lib'.systems.types.platformWithBuildInfo; builder = lib.types.submodule { freeform = lib.types.any; @@ -74,14 +73,18 @@ in { packages = lib.types.attrs.of (lib.types.attrs.of lib'.types.alias); - dependencies = build: host: target: let - initial = lib.types.raw; + dependencies = + build: host: target: + let + initial = lib.types.raw; - transform = value: let - package = lib'.packages.resolve value; + transform = + value: + let + package = lib'.packages.resolve value; + in + lib'.packages.build package build host target; in - lib'.packages.build package build host target; - in lib.types.attrs.of (lib.types.coerce initial transform lib'.types.package); alias = lib.types.submodule { @@ -99,288 +102,284 @@ in { versions = lib.options.create { description = "Available versions of the package."; type = lib.types.attrs.of lib'.types.package; - default.value = {}; + default.value = { }; }; }; }; - package = let - normalize = value: - if builtins.isFunction value || builtins.isList value - then value - else if value ? __modules__ - then value.__modules__ - else { - config = value; + package = + let + normalize = + value: + if builtins.isFunction value || builtins.isList value then + value + else if value ? __modules__ then + value.__modules__ + else + { config = value; }; + + 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.concatLists normalized; }; - 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.concatLists - normalized; - }; + transform = + location: value: + let + modules = lib.lists.from.any (normalize value); - transform = location: value: let - modules = - lib.lists.from.any (normalize value); - - result = lib.modules.run { - prefix = location; - modules = - modules - ++ [submodule {config.__modules__ = modules;}]; - }; - in - result.config; - - final = lib.types.raw; - - deps = build: host: target: - lib.types.submodule { - options = { - build = { - only = lib.options.create { - description = "Dependencies which are only used in the build environment."; - type = lib'.types.dependencies build build build; - 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 build build target; - 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 build host target; - 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 build target target; - default.value = {}; - }; + result = lib.modules.run { + prefix = location; + modules = modules ++ [ + submodule + { config.__modules__ = modules; } + ]; }; + in + result.config; - host = { - only = lib.options.create { - description = "Dependencies which are only used in the host environment."; - type = lib'.types.dependencies host host host; - default.value = {}; - }; + final = lib.types.raw; - host = lib.options.create { - description = "Dependencies which are executed in the host environment."; - type = lib'.types.dependencies host host target; - 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 host target target; - default.value = {}; - }; - }; - - target = { - only = lib.options.create { - description = "Dependencies which are only used in the target environment."; - type = lib'.types.dependencies target target target; - default.value = {}; - }; - - target = lib.options.create { - description = "Dependencies which are executed in the target environment."; - type = lib'.types.dependencies target target target; - default.value = {}; - }; - }; - }; - }; - - submodule = {config}: let - build = config.platform.build; - host = config.platform.host; - target = config.platform.target; - in { - 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 = []; - }; - - 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 = []; - }; - }; - - 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 = lib.options.create { - description = "The dependencies for the package."; - type = deps build host target; - default.value = {}; - apply = value: { + deps = + build: host: target: + lib.types.submodule { + options = { build = { - only = lib'.packages.dependencies.build build build build value.build.only; - build = lib'.packages.dependencies.build build build target value.build.build; - host = lib'.packages.dependencies.build build host target value.build.host; - target = lib'.packages.dependencies.build build target target value.build.target; + only = lib.options.create { + description = "Dependencies which are only used in the build environment."; + type = lib'.types.dependencies build build build; + 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 build build target; + 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 build host target; + 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 build target target; + default.value = { }; + }; }; + host = { - only = lib'.packages.dependencies.build host host host value.host.only; - host = lib'.packages.dependencies.build host host target value.host.host; - target = lib'.packages.dependencies.build host target target value.host.target; + only = lib.options.create { + description = "Dependencies which are only used in the host environment."; + type = lib'.types.dependencies host host host; + default.value = { }; + }; + + host = lib.options.create { + description = "Dependencies which are executed in the host environment."; + type = lib'.types.dependencies host host target; + 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 host target target; + default.value = { }; + }; }; + target = { - only = lib'.packages.dependencies.build target target target value.target.only; - target = lib'.packages.dependencies.build target target target value.target.target; + only = lib.options.create { + description = "Dependencies which are only used in the target environment."; + type = lib'.types.dependencies target target target; + default.value = { }; + }; + + target = lib.options.create { + description = "Dependencies which are executed in the target environment."; + type = lib'.types.dependencies target target target; + default.value = { }; + }; }; }; }; - }; - }; - type = - (lib.types.coerceWithLocation initial transform final) - // { + submodule = + { config }: + let + build = config.platform.build; + host = config.platform.host; + target = config.platform.target; + in + { + 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 = [ ]; + }; + + 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 = [ ]; + }; + }; + + 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 = lib.options.create { + description = "The dependencies for the package."; + type = deps build host target; + default.value = { }; + apply = value: { + build = { + only = lib'.packages.dependencies.build build build build value.build.only; + build = lib'.packages.dependencies.build build build target value.build.build; + host = lib'.packages.dependencies.build build host target value.build.host; + target = lib'.packages.dependencies.build build target target value.build.target; + }; + host = { + only = lib'.packages.dependencies.build host host host value.host.only; + host = lib'.packages.dependencies.build host host target value.host.host; + target = lib'.packages.dependencies.build host target target value.host.target; + }; + target = { + only = lib'.packages.dependencies.build target target target value.target.only; + target = lib'.packages.dependencies.build target target target value.target.target; + }; + }; + }; + }; + }; + + type = (lib.types.coerceWithLocation initial transform final) // { name = "Package"; description = "a package definition"; }; - in + in type // { - children = - type.children - // { - inherit submodule; - }; + children = type.children // { + inherit submodule; + }; }; }; }; diff --git a/tidepool/src/packages/aux/a.nix b/tidepool/src/packages/aux/a.nix index 01a67ae..3848de8 100644 --- a/tidepool/src/packages/aux/a.nix +++ b/tidepool/src/packages/aux/a.nix @@ -1,35 +1,36 @@ -{ - lib', - config, -}: let +{ lib', config }: +let inherit (config) builders packages; -in { +in +{ config.packages.aux.a = { versions = { - "latest" = {config}: { - config = { - meta = { - platforms = ["i686-linux"]; - }; + "latest" = + { config }: + { + config = { + meta = { + platforms = [ "i686-linux" ]; + }; - name = "${config.pname}-${config.version}"; + name = "${config.pname}-${config.version}"; - pname = "a"; - version = "1.0.0"; + pname = "a"; + version = "1.0.0"; - builder = builders.basic; + builder = builders.basic; - deps.build.host = { - inherit (packages.aux) b; - }; + deps.build.host = { + inherit (packages.aux) b; + }; - phases = { - install = '' - echo "a with b: ${config.deps.build.host.b.package.system}" > $out - ''; + phases = { + install = '' + echo "a with b: ${config.deps.build.host.b.package.system}" > $out + ''; + }; }; }; - }; }; }; } diff --git a/tidepool/src/packages/aux/b.nix b/tidepool/src/packages/aux/b.nix index b9c1148..b3d52f1 100644 --- a/tidepool/src/packages/aux/b.nix +++ b/tidepool/src/packages/aux/b.nix @@ -1,36 +1,38 @@ -{config}: let +{ config }: +let inherit (config) lib builders packages; -in { +in +{ config.packages.aux.b = { versions = { - "latest" = {config}: { - options = { - custom = lib.options.create { - type = lib.types.bool; + "latest" = + { config }: + { + options = { + custom = lib.options.create { type = lib.types.bool; }; + }; + + config = { + meta = { + platforms = [ "i686-linux" ]; + }; + + name = "${config.pname}-${config.version}"; + + custom = true; + + pname = "b"; + version = "1.0.0"; + + builder = builders.basic; + + phases = { + install = '' + echo "b" > $out + ''; + }; }; }; - - config = { - meta = { - platforms = ["i686-linux"]; - }; - - name = "${config.pname}-${config.version}"; - - custom = true; - - pname = "b"; - version = "1.0.0"; - - builder = builders.basic; - - phases = { - install = '' - echo "b" > $out - ''; - }; - }; - }; }; }; } diff --git a/tidepool/src/packages/default.nix b/tidepool/src/packages/default.nix index 6d04e32..ababd40 100644 --- a/tidepool/src/packages/default.nix +++ b/tidepool/src/packages/default.nix @@ -1,10 +1,12 @@ -{config}: let +{ config }: +let inherit (config) lib; doubles = lib.systems.doubles.all; - packages = builtins.removeAttrs config.packages ["cross"]; -in { + packages = builtins.removeAttrs config.packages [ "cross" ]; +in +{ includes = [ ./foundation ./aux/a.nix @@ -19,11 +21,11 @@ in { options.cross = lib.attrs.generate doubles ( system: - lib.options.create { - description = "The cross-compiled package set for the ${system} target."; - type = lib.types.packages; - default = {}; - } + lib.options.create { + description = "The cross-compiled package set for the ${system} target."; + type = lib.types.packages; + default = { }; + } ); }; }; @@ -42,63 +44,63 @@ in { config.packages.cross = lib.attrs.generate doubles ( system: + builtins.mapAttrs ( + namespace: builtins.mapAttrs ( - namespace: - builtins.mapAttrs ( - name: alias: let - setHost = package: - package // { - __modules__ = package.__modules__ ++ [ - { - config.platform = { - host = lib.modules.override 5 system; - target = lib.modules.override 5 system; - }; - } - ]; - }; - # if package != {} - # then - # (package.extend ( - # {config}: { - # config = { - # platform = { - # host = lib.modules.overrides.force system; - # target = lib.modules.overrides.default system; - # }; + name: alias: + let + setHost = + package: + package + // { + __modules__ = package.__modules__ ++ [ + { + config.platform = { + host = lib.modules.override 5 system; + target = lib.modules.override 5 system; + }; + } + ]; + }; + # 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 - // { - versions = builtins.mapAttrs (version: package: setHost package) alias.versions; - }; - in - updated - ) + updated = alias // { + versions = builtins.mapAttrs (version: package: setHost package) alias.versions; + }; + in + updated ) - packages + ) packages ); } diff --git a/tidepool/src/packages/foundation/binutils/default.nix b/tidepool/src/packages/foundation/binutils/default.nix index 08e1c2f..77c4bdd 100644 --- a/tidepool/src/packages/foundation/binutils/default.nix +++ b/tidepool/src/packages/foundation/binutils/default.nix @@ -3,121 +3,126 @@ lib', config, options, -}: let - inherit - (config) +}: +let + inherit (config) mirrors builders # These are the upstream foundational packages exported from the Aux Foundation project. - + foundation packages ; -in { +in +{ config.packages.foundation.binutils = { versions = { - "latest" = {config}: { - options = { - src = lib.options.create { - type = lib.types.derivation; - description = "Source for the package."; - }; - }; - - config = { - meta = { - platforms = ["i686-linux"]; - }; - - pname = "binutils"; - version = "2.41"; - - builder = builders.basic; - - deps = { - build = { - host = { - inherit (packages.foundation) gcc; - }; + "latest" = + { config }: + { + options = { + src = lib.options.create { + type = lib.types.derivation; + description = "Source for the package."; }; }; - env = { - PATH = lib.paths.bin [ - # foundation.stage2-gcc - foundation.stage2-binutils - foundation.stage2-gnumake - foundation.stage2-gnupatch - foundation.stage2-gnused - foundation.stage2-gnugrep - foundation.stage2-gawk - foundation.stage2-diffutils - foundation.stage2-findutils - foundation.stage2-gnutar - foundation.stage1-xz - ]; - }; + config = { + meta = { + platforms = [ "i686-linux" ]; + }; - phases = let - patches = [ - # Make binutils output deterministic by default. - ./patches/deterministic.patch - ]; + pname = "binutils"; + version = "2.41"; - configureFlags = [ - # "CC=musl-gcc" - "LDFLAGS=--static" - "--prefix=${builtins.placeholder "out"}" - "--build=${config.platform.build.triple}" - "--host=${config.platform.host.triple}" - "--target=${config.platform.target.triple}" + builder = builders.basic; - "--with-sysroot=/" - "--enable-deterministic-archives" - # depends on bison - "--disable-gprofng" + deps = { + build = { + host = { + inherit (packages.foundation) gcc; + }; + }; + }; - # Turn on --enable-new-dtags by default to make the linker set - # RUNPATH instead of RPATH on binaries. This is important because - # RUNPATH can be overridden using LD_LIBRARY_PATH at runtime. - "--enable-new-dtags" + env = { + PATH = lib.paths.bin [ + # foundation.stage2-gcc + foundation.stage2-binutils + foundation.stage2-gnumake + foundation.stage2-gnupatch + foundation.stage2-gnused + foundation.stage2-gnugrep + foundation.stage2-gawk + foundation.stage2-diffutils + foundation.stage2-findutils + foundation.stage2-gnutar + foundation.stage1-xz + ]; + }; - # By default binutils searches $libdir for libraries. This brings in - # libbfd and libopcodes into a default visibility. Drop default lib - # path to force users to declare their use of these libraries. - "--with-lib-path=:" + phases = + let + patches = [ + # Make binutils output deterministic by default. + ./patches/deterministic.patch + ]; - "--disable-multilib" - ]; - in { - unpack = '' - tar xf ${config.src} - cd binutils-${config.version} - ''; + configureFlags = [ + # "CC=musl-gcc" + "LDFLAGS=--static" + "--prefix=${builtins.placeholder "out"}" + "--build=${config.platform.build.triple}" + "--host=${config.platform.host.triple}" + "--target=${config.platform.target.triple}" - patch = '' - ${lib.strings.concatMapSep "\n" (file: "patch -Np1 -i ${file}") patches} - ''; + "--with-sysroot=/" + "--enable-deterministic-archives" + # depends on bison + "--disable-gprofng" - configure = '' - bash ./configure ${builtins.concatStringsSep " " configureFlags} - ''; + # Turn on --enable-new-dtags by default to make the linker set + # RUNPATH instead of RPATH on binaries. This is important because + # RUNPATH can be overridden using LD_LIBRARY_PATH at runtime. + "--enable-new-dtags" - build = '' - make -j $NIX_BUILD_CORES - ''; + # By default binutils searches $libdir for libraries. This brings in + # libbfd and libopcodes into a default visibility. Drop default lib + # path to force users to declare their use of these libraries. + "--with-lib-path=:" - install = '' - make -j $NIX_BUILD_CORES install-strip - ''; - }; + "--disable-multilib" + ]; + in + { + unpack = '' + tar xf ${config.src} + cd binutils-${config.version} + ''; - src = builtins.fetchurl { - url = "${mirrors.gnu}/binutils/binutils-${config.version}.tar.xz"; - sha256 = "rppXieI0WeWWBuZxRyPy0//DHAMXQZHvDQFb3wYAdFA="; + patch = '' + ${lib.strings.concatMapSep "\n" (file: "patch -Np1 -i ${file}") patches} + ''; + + configure = '' + bash ./configure ${builtins.concatStringsSep " " configureFlags} + ''; + + build = '' + make -j $NIX_BUILD_CORES + ''; + + install = '' + make -j $NIX_BUILD_CORES install-strip + ''; + }; + + src = builtins.fetchurl { + url = "${mirrors.gnu}/binutils/binutils-${config.version}.tar.xz"; + sha256 = "rppXieI0WeWWBuZxRyPy0//DHAMXQZHvDQFb3wYAdFA="; + }; }; }; - }; }; }; } diff --git a/tidepool/src/packages/foundation/default.nix b/tidepool/src/packages/foundation/default.nix index 0584e01..268593a 100644 --- a/tidepool/src/packages/foundation/default.nix +++ b/tidepool/src/packages/foundation/default.nix @@ -3,7 +3,8 @@ lib', config, options, -}: { +}: +{ includes = [ ./gcc ./binutils diff --git a/tidepool/src/packages/foundation/gcc/default.nix b/tidepool/src/packages/foundation/gcc/default.nix index 21292f9..dd96962 100644 --- a/tidepool/src/packages/foundation/gcc/default.nix +++ b/tidepool/src/packages/foundation/gcc/default.nix @@ -1,217 +1,210 @@ -{ - config, - options, -}: let - inherit - (config) +{ config, options }: +let + inherit (config) lib mirrors builders # These are the upstream foundational packages exported from the Aux Foundation project. - + foundation packages ; -in { +in +{ config.packages.foundation.gcc = { versions = { - "latest" = { - config, - meta, - }: { - options = { - src = lib.options.create { - type = lib.types.derivation; - description = "Source for the package."; - }; - - cc = { + "latest" = + { config, meta }: + { + options = { src = lib.options.create { type = lib.types.derivation; - description = "The cc source for the package."; + description = "Source for the package."; + }; + + cc = { + src = lib.options.create { + type = lib.types.derivation; + description = "The cc source for the package."; + }; + }; + + gmp = { + src = lib.options.create { + type = lib.types.derivation; + description = "The gmp source for the package."; + }; + + version = lib.options.create { + type = lib.types.string; + description = "Version of gmp."; + }; + }; + + mpfr = { + src = lib.options.create { + type = lib.types.derivation; + description = "The mpfr source for the package."; + }; + + version = lib.options.create { + type = lib.types.string; + description = "Version of mpfr."; + }; + }; + + mpc = { + src = lib.options.create { + type = lib.types.derivation; + description = "The mpc source for the package."; + }; + + version = lib.options.create { + type = lib.types.string; + description = "Version of mpc."; + }; + }; + + isl = { + src = lib.options.create { + type = lib.types.derivation; + description = "The isl source for the package."; + }; + version = lib.options.create { + type = lib.types.string; + description = "Version of isl."; + }; }; }; - gmp = { - src = lib.options.create { - type = lib.types.derivation; - description = "The gmp source for the package."; + config = { + meta = { + platforms = [ "i686-linux" ]; }; - version = lib.options.create { - type = lib.types.string; - description = "Version of gmp."; - }; - }; + pname = "gcc"; + version = "13.2.0"; - mpfr = { - src = lib.options.create { - type = lib.types.derivation; - description = "The mpfr source for the package."; + builder = builders.basic; + + env = { + PATH = lib.paths.bin [ + foundation.stage2-gcc + foundation.stage2-binutils + foundation.stage2-gnumake + foundation.stage2-gnused + foundation.stage2-gnugrep + foundation.stage2-gawk + foundation.stage2-diffutils + foundation.stage2-findutils + foundation.stage2-gnutar + foundation.stage2-gzip + foundation.stage2-bzip2 + foundation.stage1-xz + ]; }; - version = lib.options.create { - type = lib.types.string; - description = "Version of mpfr."; - }; - }; + phases = + let + host = lib.systems.withBuildInfo config.platform.host; - mpc = { - src = lib.options.create { - type = lib.types.derivation; - description = "The mpc source for the package."; + mbits = if host.system.cpu.family == "x86" then if host.is64bit then "-m64" else "-m32" else ""; + in + { + unpack = '' + # Unpack + tar xf ${config.src} + tar xf ${config.gmp.src} + tar xf ${config.mpfr.src} + tar xf ${config.mpc.src} + tar xf ${config.isl.src} + cd gcc-${config.version} + + ln -s ../gmp-${config.gmp.version} gmp + ln -s ../mpfr-${config.mpfr.version} mpfr + ln -s ../mpc-${config.mpc.version} mpc + ln -s ../isl-${config.isl.version} isl + ''; + + patch = '' + # Patch + # force musl even if host triple is gnu + sed -i 's|"os/gnu-linux"|"os/generic"|' libstdc++-v3/configure.host + ''; + + configure = '' + # Configure + export CC="gcc -Wl,-dynamic-linker -Wl,${foundation.stage1-musl}/lib/libc.so" + export CXX="g++ -Wl,-dynamic-linker -Wl,${foundation.stage1-musl}/lib/libc.so" + export CFLAGS_FOR_TARGET="-Wl,-dynamic-linker -Wl,${foundation.stage1-musl}/lib/libc.so" + export LIBRARY_PATH="${foundation.stage1-musl}/lib" + + bash ./configure \ + --prefix=$out \ + --build=${config.platform.build.triple} \ + --host=${config.platform.host.triple} \ + --target=${config.platform.target.triple} \ + --with-native-system-header-dir=/include \ + --with-sysroot=${foundation.stage1-musl} \ + --enable-languages=c,c++ \ + --disable-bootstrap \ + --disable-libsanitizer \ + --disable-lto \ + --disable-multilib \ + --disable-plugin \ + CFLAGS=-static \ + CXXFLAGS=-static + ''; + + build = '' + # Build + make -j $NIX_BUILD_CORES + ''; + + install = '' + # Install + make -j $NIX_BUILD_CORES install-strip + ''; + }; + + src = builtins.fetchurl { + url = "${mirrors.gnu}/gcc/gcc-${config.version}/gcc-${config.version}.tar.xz"; + sha256 = "4nXnZEKmBnNBon8Exca4PYYTFEAEwEE1KIY9xrXHQ9o="; }; - version = lib.options.create { - type = lib.types.string; - description = "Version of mpc."; + gmp = { + version = "6.3.0"; + src = builtins.fetchurl { + url = "${mirrors.gnu}/gmp/gmp-${config.gmp.version}.tar.xz"; + sha256 = "o8K4AgG4nmhhb0rTC8Zq7kknw85Q4zkpyoGdXENTiJg="; + }; }; - }; - isl = { - src = lib.options.create { - type = lib.types.derivation; - description = "The isl source for the package."; + mpfr = { + version = "4.2.1"; + src = builtins.fetchurl { + url = "${mirrors.gnu}/mpfr/mpfr-${config.mpfr.version}.tar.xz"; + sha256 = "J3gHNTpnJpeJlpRa8T5Sgp46vXqaW3+yeTiU4Y8fy7I="; + }; }; - version = lib.options.create { - type = lib.types.string; - description = "Version of isl."; + + mpc = { + version = "1.3.1"; + src = builtins.fetchurl { + url = "${mirrors.gnu}/mpc/mpc-${config.mpc.version}.tar.gz"; + sha256 = "q2QkkvXPiCt0qgy3MM1BCoHtzb7IlRg86TDnBsHHWbg="; + }; + }; + + isl = { + version = "0.24"; + src = builtins.fetchurl { + url = "https://gcc.gnu.org/pub/gcc/infrastructure/isl-${config.isl.version}.tar.bz2"; + sha256 = "/PeN2WVsEOuM+fvV9ZoLawE4YgX+GTSzsoegoYmBRcA="; + }; }; }; }; - - config = { - meta = { - platforms = ["i686-linux"]; - }; - - pname = "gcc"; - version = "13.2.0"; - - builder = builders.basic; - - env = { - PATH = lib.paths.bin [ - foundation.stage2-gcc - foundation.stage2-binutils - foundation.stage2-gnumake - foundation.stage2-gnused - foundation.stage2-gnugrep - foundation.stage2-gawk - foundation.stage2-diffutils - foundation.stage2-findutils - foundation.stage2-gnutar - foundation.stage2-gzip - foundation.stage2-bzip2 - foundation.stage1-xz - ]; - }; - - phases = let - host = lib.systems.withBuildInfo config.platform.host; - - mbits = - if host.system.cpu.family == "x86" - then - if host.is64bit - then "-m64" - else "-m32" - else ""; - in { - unpack = '' - # Unpack - tar xf ${config.src} - tar xf ${config.gmp.src} - tar xf ${config.mpfr.src} - tar xf ${config.mpc.src} - tar xf ${config.isl.src} - cd gcc-${config.version} - - ln -s ../gmp-${config.gmp.version} gmp - ln -s ../mpfr-${config.mpfr.version} mpfr - ln -s ../mpc-${config.mpc.version} mpc - ln -s ../isl-${config.isl.version} isl - ''; - - patch = '' - # Patch - # force musl even if host triple is gnu - sed -i 's|"os/gnu-linux"|"os/generic"|' libstdc++-v3/configure.host - ''; - - configure = '' - # Configure - export CC="gcc -Wl,-dynamic-linker -Wl,${foundation.stage1-musl}/lib/libc.so" - export CXX="g++ -Wl,-dynamic-linker -Wl,${foundation.stage1-musl}/lib/libc.so" - export CFLAGS_FOR_TARGET="-Wl,-dynamic-linker -Wl,${foundation.stage1-musl}/lib/libc.so" - export LIBRARY_PATH="${foundation.stage1-musl}/lib" - - bash ./configure \ - --prefix=$out \ - --build=${config.platform.build.triple} \ - --host=${config.platform.host.triple} \ - --target=${config.platform.target.triple} \ - --with-native-system-header-dir=/include \ - --with-sysroot=${foundation.stage1-musl} \ - --enable-languages=c,c++ \ - --disable-bootstrap \ - --disable-libsanitizer \ - --disable-lto \ - --disable-multilib \ - --disable-plugin \ - CFLAGS=-static \ - CXXFLAGS=-static - ''; - - build = '' - # Build - make -j $NIX_BUILD_CORES - ''; - - install = '' - # Install - make -j $NIX_BUILD_CORES install-strip - ''; - }; - - src = builtins.fetchurl { - url = "${mirrors.gnu}/gcc/gcc-${config.version}/gcc-${config.version}.tar.xz"; - sha256 = "4nXnZEKmBnNBon8Exca4PYYTFEAEwEE1KIY9xrXHQ9o="; - }; - - gmp = { - version = "6.3.0"; - src = builtins.fetchurl { - url = "${mirrors.gnu}/gmp/gmp-${config.gmp.version}.tar.xz"; - sha256 = "o8K4AgG4nmhhb0rTC8Zq7kknw85Q4zkpyoGdXENTiJg="; - }; - }; - - mpfr = { - version = "4.2.1"; - src = builtins.fetchurl { - url = "${mirrors.gnu}/mpfr/mpfr-${config.mpfr.version}.tar.xz"; - sha256 = "J3gHNTpnJpeJlpRa8T5Sgp46vXqaW3+yeTiU4Y8fy7I="; - }; - }; - - mpc = { - version = "1.3.1"; - src = builtins.fetchurl { - url = "${mirrors.gnu}/mpc/mpc-${config.mpc.version}.tar.gz"; - sha256 = "q2QkkvXPiCt0qgy3MM1BCoHtzb7IlRg86TDnBsHHWbg="; - }; - }; - - isl = { - version = "0.24"; - src = builtins.fetchurl { - url = "https://gcc.gnu.org/pub/gcc/infrastructure/isl-${config.isl.version}.tar.bz2"; - sha256 = "/PeN2WVsEOuM+fvV9ZoLawE4YgX+GTSzsoegoYmBRcA="; - }; - }; - }; - }; }; }; } diff --git a/tidepool/src/packages/foundation/linux-headers/default.nix b/tidepool/src/packages/foundation/linux-headers/default.nix index 3a04996..2201046 100644 --- a/tidepool/src/packages/foundation/linux-headers/default.nix +++ b/tidepool/src/packages/foundation/linux-headers/default.nix @@ -3,79 +3,79 @@ lib', config, options, -}: let - inherit - (config) +}: +let + inherit (config) mirrors builders # These are the upstream foundational packages exported from the Aux Foundation project. - + foundation ; -in { +in +{ config.packages.foundation.linux-headers = { versions = { - "latest" = { - config, - meta, - }: { - options = { - src = lib.options.create { - type = lib.types.derivation; - description = "Source for the package."; + "latest" = + { config, meta }: + { + options = { + src = lib.options.create { + type = lib.types.derivation; + description = "Source for the package."; + }; + }; + + config = { + meta = { + platforms = [ "i686-linux" ]; + }; + + pname = "linux-headers"; + version = "6.5.6"; + + builder = builders.basic; + + env = { + PATH = lib.paths.bin [ + foundation.stage2-gcc + foundation.stage1-musl + foundation.stage2-binutils + foundation.stage2-gnumake + foundation.stage2-gnupatch + foundation.stage2-gnused + foundation.stage2-gnugrep + foundation.stage2-gawk + foundation.stage2-diffutils + foundation.stage2-findutils + foundation.stage2-gnutar + foundation.stage1-xz + ]; + }; + + phases = { + unpack = '' + tar xf ${config.src} + cd linux-${config.version} + ''; + + build = '' + make -j $NIX_BUILD_CORES CC=musl-gcc HOSTCC=musl-gcc ARCH=${config.platform.host.linux.arch} headers + ''; + + install = '' + find usr/include -name '.*' -exec rm {} + + mkdir -p $out + cp -rv usr/include $out/ + ''; + }; + + src = builtins.fetchurl { + url = "https://cdn.kernel.org/pub/linux/kernel/v${lib.versions.major config.version}.x/linux-${config.version}.tar.xz"; + sha256 = "eONtQhRUcFHCTfIUD0zglCjWxRWtmnGziyjoCUqV0vY="; + }; }; }; - - config = { - meta = { - platforms = ["i686-linux"]; - }; - - pname = "linux-headers"; - version = "6.5.6"; - - builder = builders.basic; - - env = { - PATH = lib.paths.bin [ - foundation.stage2-gcc - foundation.stage1-musl - foundation.stage2-binutils - foundation.stage2-gnumake - foundation.stage2-gnupatch - foundation.stage2-gnused - foundation.stage2-gnugrep - foundation.stage2-gawk - foundation.stage2-diffutils - foundation.stage2-findutils - foundation.stage2-gnutar - foundation.stage1-xz - ]; - }; - - phases = { - unpack = '' - tar xf ${config.src} - cd linux-${config.version} - ''; - - build = '' - make -j $NIX_BUILD_CORES CC=musl-gcc HOSTCC=musl-gcc ARCH=${config.platform.host.linux.arch} headers - ''; - - install = '' - find usr/include -name '.*' -exec rm {} + - mkdir -p $out - cp -rv usr/include $out/ - ''; - }; - - src = builtins.fetchurl { - url = "https://cdn.kernel.org/pub/linux/kernel/v${lib.versions.major config.version}.x/linux-${config.version}.tar.xz"; - sha256 = "eONtQhRUcFHCTfIUD0zglCjWxRWtmnGziyjoCUqV0vY="; - }; - }; - }; }; }; }