Compare commits

...

18 commits

Author SHA1 Message Date
Jake Hamilton 7d94b7f665
feat: package extend, dynamic propagation 2024-07-09 02:54:33 -07:00
Jake Hamilton 3f9d287065
refactor: format 2024-07-09 01:49:44 -07:00
Jake Hamilton ea200d834e
feat: pass through package dependencies via context 2024-07-08 23:18:11 -07:00
Jake Hamilton 62bc2f4eee
feat: propagating hooks and context 2024-07-08 23:07:59 -07:00
Steve D 42e69f7d43 "topographic" -> "topological" in latest tidepool commit (#6)
Reviewed-on: auxolotl/labs#6
Co-authored-by: Steve Dodd <steved424@gmail.com>
Co-committed-by: Steve Dodd <steved424@gmail.com>
2024-07-08 19:19:49 +00:00
Jake Hamilton 0ad14e8795
refactor: make dag helpers easier to reason about 2024-07-07 15:10:37 -07:00
Jake Hamilton 0a63667459
refactor(format): apply formatting 2024-07-07 15:03:48 -07:00
Jake Hamilton d2b053d63a
feat: export linux-headers 2024-07-07 15:03:47 -07:00
Jake Hamilton 7774f65079
refactor: minor cleanup 2024-07-07 15:03:46 -07:00
Jake Hamilton fd9b85f29e
feat: apply platform to deps inside submodules 2024-07-07 15:03:45 -07:00
Jake Hamilton b315ae81f6
refactor: only support i686-linux for foundation gcc 2024-07-07 15:03:45 -07:00
Jake Hamilton 193a52cbc8
fix: cross-platform deps 2024-07-07 15:03:44 -07:00
Jake Hamilton 27a0e3d59f
fix: remove failing build args 2024-07-07 15:03:43 -07:00
Jake Hamilton 2b5f90d4e5
refactor: make dependencies dynamically built per-package 2024-07-07 15:03:42 -07:00
Jake Hamilton 008632bc8b
feat: working transient deps 2024-07-07 15:03:41 -07:00
Jake Hamilton 0f602b1cb7
wip: working single dependency reference via coercion 2024-07-07 15:03:38 -07:00
Alex Kladov 8233d4aedf use correct name for topological sort (#5)
I am 0.8 sure this is a typo, I've never seen this being referred to as topographic sorting!

Reviewed-on: auxolotl/labs#5
Reviewed-by: Jake Hamilton <jake.hamilton@hey.com>
Co-authored-by: Alex Kladov <aleksey.kladov@gmail.com>
Co-committed-by: Alex Kladov <aleksey.kladov@gmail.com>
2024-06-23 18:39:30 +00:00
Steve D a2f0a06426 Fix non-deterministic "missing: Permission denied" errors (#4)
Make 'missing' executable where source tarballs use autotools and are unpacked with untar.  untar doesn't preserve or set mtime, which may result in autotools generated files, e.g. configure, having newer timestamps than their source files (e.g. configure.in.) In these circumstances autotools generated Makefiles will call 'missing' to either regenerate them or fix-up the timestamps.

Reviewed-on: auxolotl/labs#4
Reviewed-by: isabel roses <isabel@isabelroses.com>
Reviewed-by: Jake Hamilton <jake.hamilton@hey.com>
Co-authored-by: Steve Dodd <steved424@gmail.com>
Co-committed-by: Steve Dodd <steved424@gmail.com>
2024-06-23 17:32:11 +00:00
26 changed files with 1202 additions and 557 deletions

View file

@ -1,5 +1,5 @@
#!/usr/bin/env nix-shell #!/usr/bin/env nix-shell
#!nix-shell -i bash -I "nixpkgs=https://github.com/nixos/nixpkgs/archive/nixos-24.05.tar.gz" -p nixfmt-rfc-style #!nix-shell -i bash -I "nixpkgs=https://github.com/nixos/nixpkgs/archive/nixos-unstable.tar.gz" -p nixfmt-rfc-style
files=$(find . -name "*.nix" -type f) files=$(find . -name "*.nix" -type f)

View file

@ -3,10 +3,10 @@
"lib": { "lib": {
"locked": { "locked": {
"dir": "lib", "dir": "lib",
"dirtyRev": "9850da8aa9dc9be22e237c9b424a18e801e53ecb-dirty", "dirtyRev": "2be3111b2c0911f40b47fe0a1fb22b5f5188cf59-dirty",
"dirtyShortRev": "9850da8-dirty", "dirtyShortRev": "2be3111-dirty",
"lastModified": 1718529861, "lastModified": 1719251485,
"narHash": "sha256-tv/0C7ixH+9Ij+r+5nua48OlXXXnbdEsnenxX4eG/Sk=", "narHash": "sha256-63NvfFVeTDITfNu60rmCUlaZtAeZUnvrIaOLSk9ScC8=",
"type": "git", "type": "git",
"url": "file:../?dir=lib" "url": "file:../?dir=lib"
}, },

View file

@ -68,6 +68,7 @@ in
export CC="tcc -B ${stage1.tinycc.mes.libs.package}/lib" export CC="tcc -B ${stage1.tinycc.mes.libs.package}/lib"
export ac_cv_func_getpgrp_void=yes export ac_cv_func_getpgrp_void=yes
export ac_cv_func_tzset=yes export ac_cv_func_tzset=yes
chmod 0755 missing
bash ./configure \ bash ./configure \
--build=${platform.build} \ --build=${platform.build} \
--host=${platform.host} \ --host=${platform.host} \

View file

@ -58,6 +58,7 @@ in
# Configure # Configure
export CC="tcc -B ${stage1.tinycc.mes.libs.package}/lib" export CC="tcc -B ${stage1.tinycc.mes.libs.package}/lib"
chmod 0755 missing
bash ./configure \ bash ./configure \
--build=${platform.build} \ --build=${platform.build} \
--host=${platform.host} \ --host=${platform.host} \

View file

@ -59,6 +59,7 @@ in
export ac_cv_sizeof_unsigned_long=4 export ac_cv_sizeof_unsigned_long=4
export ac_cv_sizeof_long_long=8 export ac_cv_sizeof_long_long=8
export ac_cv_header_netdb_h=no export ac_cv_header_netdb_h=no
chmod 0755 missing
bash ./configure \ bash ./configure \
--prefix=$out \ --prefix=$out \
--build=${platform.build} \ --build=${platform.build} \

View file

@ -21,7 +21,7 @@ lib: {
## Apply a topological sort to a DAG. ## Apply a topological sort to a DAG.
## ##
## @type Dag a -> { result :: List a } | { cycle :: List a, loops :: List a } ## @type Dag a -> { result :: List a } | { cycle :: List a, loops :: List a }
topographic = topological =
graph: graph:
let let
getEntriesBefore = getEntriesBefore =
@ -43,7 +43,7 @@ lib: {
isBefore = a: b: builtins.elem a.name b.after; isBefore = a: b: builtins.elem a.name b.after;
sorted = lib.lists.sort.topographic isBefore entries; sorted = lib.lists.sort.topological isBefore entries;
in in
if sorted ? result then if sorted ? result then
{ {
@ -95,7 +95,7 @@ lib: {
## Create a new DAG entry. ## Create a new DAG entry.
## ##
## @type List String -> List String -> a -> { before :: List String, after :: List String, value :: a } ## @type List String -> List String -> a -> { before :: List String, after :: List String, value :: a }
between = before: after: value: { inherit before after value; }; between = after: before: value: { inherit before after value; };
## Create a new DAG entry with no dependencies. ## Create a new DAG entry with no dependencies.
## ##
@ -105,12 +105,12 @@ lib: {
## Create a new DAG entry that occurs before other entries. ## Create a new DAG entry that occurs before other entries.
## ##
## @type List String -> a -> { before :: List String, after :: List String, value :: a } ## @type List String -> a -> { before :: List String, after :: List String, value :: a }
before = before: lib.dag.entry.between before [ ]; before = before: lib.dag.entry.between [ ] before;
## Create a new DAG entry that occurs after other entries. ## Create a new DAG entry that occurs after other entries.
## ##
## @type List String -> a -> { before :: List String, after :: List String, value :: a } ## @type List String -> a -> { before :: List String, after :: List String, value :: a }
after = lib.dag.entry.between [ ]; after = after: lib.dag.entry.between after [ ];
}; };
entries = { entries = {
@ -121,7 +121,7 @@ lib: {
tag: tag:
let let
process = process =
i: before: after: entries: i: after: before: entries:
let let
name = "${tag}-${builtins.toString i}"; name = "${tag}-${builtins.toString i}";
entry = builtins.head entries; entry = builtins.head entries;
@ -130,7 +130,7 @@ lib: {
if builtins.length entries == 0 then if builtins.length entries == 0 then
{ } { }
else if builtins.length entries == 1 then else if builtins.length entries == 1 then
{ "${name}" = lib.dag.entry.between before after entry; } { "${name}" = lib.dag.entry.between after before entry; }
else else
{ "${name}" = lib.dag.entry.after after entry; } // (process (i + 1) before [ name ] rest); { "${name}" = lib.dag.entry.after after entry; } // (process (i + 1) before [ name ] rest);
in in
@ -144,12 +144,12 @@ lib: {
## Create a DAG from a list of entries, prefixed with a tag, that occurs before other entries. ## Create a DAG from a list of entries, prefixed with a tag, that occurs before other entries.
## ##
## @type String -> List String -> List a -> Dag a ## @type String -> List String -> List a -> Dag a
before = tag: before: lib.dag.entries.between tag before [ ]; before = tag: before: lib.dag.entries.between tag [ ] before;
## Create a DAG from a list of entries, prefixed with a tag, that occurs after other entries. ## Create a DAG from a list of entries, prefixed with a tag, that occurs after other entries.
## ##
## @type String -> List String -> List a -> Dag a ## @type String -> List String -> List a -> Dag a
after = tag: lib.dag.entries.between tag [ ]; after = tag: after: lib.dag.entries.between tag after [ ];
}; };
}; };
} }

View file

@ -119,11 +119,11 @@ in
}; };
"sort" = { "sort" = {
"topographic" = { "topological" = {
"handles an empty graph" = "handles an empty graph" =
let let
expected = [ ]; expected = [ ];
actual = lib.dag.sort.topographic { }; actual = lib.dag.sort.topological { };
in in
actual.result == expected; actual.result == expected;
@ -147,7 +147,7 @@ in
value = "d"; value = "d";
} }
]; ];
actual = lib.dag.sort.topographic { actual = lib.dag.sort.topological {
a = lib.dag.entry.anywhere "a"; a = lib.dag.entry.anywhere "a";
b = lib.dag.entry.between [ "c" ] [ "a" ] "b"; b = lib.dag.entry.between [ "c" ] [ "a" ] "b";
c = lib.dag.entry.before [ "c" ] "c"; c = lib.dag.entry.before [ "c" ] "c";

View file

@ -31,15 +31,15 @@ lib: {
in in
builtins.map (x: builtins.elemAt x 1) (builtins.sort isLess prepared); builtins.map (x: builtins.elemAt x 1) (builtins.sort isLess prepared);
## Perform a topographic sort on a list of items. The predicate function determines whether ## Perform a topological sort on a list of items. The predicate function determines whether
## its first argument comes before the second argument. ## its first argument comes before the second argument.
## ##
## @type (a -> a -> Bool) -> List a -> List a ## @type (a -> a -> Bool) -> List a -> List a
topographic = topological =
predicate: list: predicate: list:
let let
searched = lib.lists.search.depthFirst true predicate list; searched = lib.lists.search.depthFirst true predicate list;
results = lib.lists.sort.topographic predicate (searched.visited ++ searched.rest); results = lib.lists.sort.topological predicate (searched.visited ++ searched.rest);
in in
if builtins.length list < 2 then if builtins.length list < 2 then
{ result = list; } { result = list; }
@ -224,5 +224,11 @@ lib: {
filter = result: value: if builtins.elem value result then result else result ++ [ value ]; filter = result: value: if builtins.elem value result then result else result ++ [ value ];
in in
builtins.foldl' filter [ ] list; builtins.foldl' filter [ ] list;
## Flatten a list of lists into a single list.
##
## @type List (List a) -> List a
flatten =
value: if builtins.isList value then builtins.concatMap lib.lists.flatten value else [ value ];
}; };
} }

View file

@ -43,7 +43,7 @@ lib: {
resolve = resolve =
definition: definition:
let let
properties = builtins.addErrorContext "while evaluating definitions from `${definition.__file__}`:" ( properties = builtins.addErrorContext "while evaluating definitions from `${definition.__file__ or "<unknown>"}`:" (
lib.modules.apply.properties definition.value lib.modules.apply.properties definition.value
); );
normalize = value: { normalize = value: {

View file

@ -49,18 +49,18 @@ lib: {
## ##
## @type Attrs -> Attrs ## @type Attrs -> Attrs
create = create =
settings@{ settings@{ name
name, , description ? name
description ? name, , fallback ? { }
fallback ? { }, , check ? lib.fp.const true
check ? lib.fp.const true, , merge ? lib.options.merge.default
merge ? lib.options.merge.default, , functor ? lib.types.functor name
functor ? lib.types.functor name, , mergeType ? lib.types.merge functor
mergeType ? lib.types.merge functor, , getSubOptions ? lib.fp.const { }
getSubOptions ? lib.fp.const { }, , getSubModules ? null
getSubModules ? null, , withSubModules ? lib.fp.const null
withSubModules ? lib.fp.const null, , children ? { }
children ? { }, ,
}: }:
{ {
__type__ = "type"; __type__ = "type";
@ -108,7 +108,7 @@ lib: {
identifier = lib.options.getIdentifier location; identifier = lib.options.getIdentifier location;
first = builtins.elemAt definitions 0; first = builtins.elemAt definitions 0;
files = builtins.map lib.modules.getFiles definitions; files = lib.modules.getFiles definitions;
serializedFiles = builtins.concatStringsSep " and " files; serializedFiles = builtins.concatStringsSep " and " files;
getType = getType =
@ -118,13 +118,16 @@ lib: {
else else
builtins.typeOf value; builtins.typeOf value;
commonType = builtins.foldl' ( commonType = builtins.foldl'
type: definition: (
if getType definition.value != type then type: definition:
builtins.throw "The option `${identifier}` has conflicting definitions in ${files}" if getType definition.value != type then
else builtins.throw "The option `${identifier}` has conflicting definitions in ${serializedFiles}"
type else
) (getType first.value) definitions; type
)
(getType first.value)
definitions;
mergeStringifiableAttrs = lib.options.merge.one; mergeStringifiableAttrs = lib.options.merge.one;
@ -132,7 +135,7 @@ lib: {
mergeList = mergeList =
if builtins.length definitions > 1 then if builtins.length definitions > 1 then
builtins.throw "The option `${identifier}` has conflicting definitions in ${files}" builtins.throw "The option `${identifier}` has conflicting definitions in ${serializedFiles}"
else else
(lib.types.list.of lib.types.any).merge; (lib.types.list.of lib.types.any).merge;
@ -140,10 +143,12 @@ lib: {
location: definitions: x: location: definitions: x:
let let
resolvedLocation = location ++ [ "<function body>" ]; resolvedLocation = location ++ [ "<function body>" ];
resolvedDefinitions = builtins.map (definition: { resolvedDefinitions = builtins.map
__file__ = definition.__file__; (definition: {
value = definition.value x; __file__ = definition.__file__;
}) definitions; value = definition.value x;
})
definitions;
in in
lib.types.any.merge resolvedLocation resolvedDefinitions; lib.types.any.merge resolvedLocation resolvedDefinitions;
@ -200,14 +205,15 @@ lib: {
## @type Int -> Int -> Attrs ## @type Int -> Int -> Attrs
between = between =
start: end: start: end:
assert lib.errors.trace ( assert lib.errors.trace
start <= end (
) "lib.types.ints.between start must be less than or equal to end"; start <= end
lib.types.withCheck lib.types.int (value: value >= start && value <= 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}"; name = "IntBetween";
}; description = "integer between ${description start end}";
};
## Create a type that allows an integer value between a given range with a specific ## Create a type that allows an integer value between a given range with a specific
## number of bits. ## number of bits.
@ -317,14 +323,15 @@ lib: {
## @type Int -> Int -> Attrs ## @type Int -> Int -> Attrs
between = between =
start: end: start: end:
assert lib.errors.trace ( assert lib.errors.trace
start <= end (
) "lib.types.numbers.between start must be less than or equal to end"; start <= end
lib.types.withCheck lib.types.number (value: value >= start && value <= 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}"; name = "NumberBetween";
}; description = "numbereger between ${description start end}";
};
in in
{ {
inherit between; inherit between;
@ -447,8 +454,7 @@ lib: {
}; };
attrs = { attrs = {
## A type that allows an attribute set containing any type of value. The merged ## A type that allows an attribute set containing any type of value.
## definitions must all be.
## ##
## @type Attrs ## @type Attrs
any = lib.types.create { any = lib.types.create {
@ -480,10 +486,12 @@ lib: {
let let
normalize = normalize =
definition: definition:
builtins.mapAttrs (name: value: { builtins.mapAttrs
__file__ = definition.__file__; (name: value: {
value = value; __file__ = definition.__file__;
}) definition.value; value = value;
})
definition.value;
normalized = builtins.map normalize definitions; normalized = builtins.map normalize definitions;
zipper = zipper =
name: definitions: (lib.options.merge.definitions (location ++ [ name ]) type definitions).optional; name: definitions: (lib.options.merge.definitions (location ++ [ name ]) type definitions).optional;
@ -520,17 +528,19 @@ lib: {
let let
normalize = normalize =
definition: definition:
builtins.mapAttrs (name: value: { builtins.mapAttrs
__file__ = definition.__file__; (name: value: {
value = value; __file__ = definition.__file__;
}) definition.value; value = value;
})
definition.value;
normalized = builtins.map normalize definitions; normalized = builtins.map normalize definitions;
zipper = zipper =
name: definitions: name: definitions:
let let
merged = lib.options.merge.definitions (location ++ [ name ]) type definitions; merged = lib.options.merge.definitions (location ++ [ name ]) type definitions;
in in
merged.optional.value or type.fallback.value or merged.merged; merged.optional.value or type.fallback.value or merged.merged;
in in
builtins.zipAttrsWith zipper normalized; builtins.zipAttrsWith zipper normalized;
getSubOptions = prefix: type.getSubOptions (prefix ++ [ "<name>" ]); getSubOptions = prefix: type.getSubOptions (prefix ++ [ "<name>" ]);
@ -606,25 +616,30 @@ lib: {
merge = merge =
location: definitions: location: definitions:
let let
result = lib.lists.mapWithIndex1 ( result = lib.lists.mapWithIndex1
i: definition: (
lib.lists.mapWithIndex1 ( i: definition:
j: value: lib.lists.mapWithIndex1
let (
resolved = j: value:
lib.options.merge.definitions (location ++ [ "[definition ${builtins.toString i}-entry ${j}]" ]) let
type resolved =
[ lib.options.merge.definitions (location ++ [ "[definition ${builtins.toString i}-entry ${j}]" ])
{ type
file = definition.file; [
value = value; {
} file = definition.file;
]; value = value;
in }
resolved.optional ];
) definition.value in
) definitions; resolved.optional
merged = builtins.concatLists result; )
definition.value
)
definitions;
merged = lib.lists.flatten result;
filtered = builtins.filter (definition: definition ? value) merged; filtered = builtins.filter (definition: definition ? value) merged;
values = lib.options.getDefinitionValues filtered; values = lib.options.getDefinitionValues filtered;
in in
@ -777,11 +792,11 @@ lib: {
## ##
## @type { modules :: List Module, args? :: Attrs, description? :: String | Null, shorthand? :: Bool } -> Attrs ## @type { modules :: List Module, args? :: Attrs, description? :: String | Null, shorthand? :: Bool } -> Attrs
of = of =
settings@{ settings@{ modules
modules, , args ? { }
args ? { }, , description ? null
description ? null, , shorthand ? true
shorthand ? true, ,
}: }:
let let
getModules = builtins.map ( getModules = builtins.map (
@ -790,9 +805,12 @@ lib: {
let let
# TODO: Figure out if we can apply additional attributes to the generated module. # TODO: Figure out if we can apply additional attributes to the generated module.
# Currently this causes issues to do with redefined options. # Currently this causes issues to do with redefined options.
rest = builtins.removeAttrs (lib.attrs.filter ( rest = builtins.removeAttrs
name: value: builtins.elem name lib.modules.VALID_KEYS (lib.attrs.filter
) definition.value) [ "freeform" ]; (
name: value: builtins.elem name lib.modules.VALID_KEYS
)
definition.value) [ "freeform" ];
in in
if definition.value ? config then if definition.value ? config then
rest rest
@ -922,10 +940,12 @@ lib: {
merge = location: definitions: { merge = location: definitions: {
includes = includes =
modules modules
++ builtins.map (definition: { ++ builtins.map
__file__ = "${definition.__file__}; via ${lib.options.getIdentifier location}"; (definition: {
includes = [ definition.value ]; __file__ = "${definition.__file__}; via ${lib.options.getIdentifier location}";
}) definitions; includes = [ definition.value ];
})
definitions;
}; };
getSubOptions = submodule.getSubOptions; getSubOptions = submodule.getSubOptions;
getSubModules = submodule.getSubModules; getSubModules = submodule.getSubModules;
@ -961,10 +981,12 @@ lib: {
location: definitions: location: definitions:
let let
first = builtins.elemAt definitions 0; first = builtins.elemAt definitions 0;
modules = builtins.map (definition: { modules = builtins.map
__file__ = definition.__file__; (definition: {
options = lib.options.create { type = definition.value; }; __file__ = definition.__file__;
}) definitions; options = lib.options.create { type = definition.value; };
})
definitions;
merged = lib.modules.fixup location (lib.options.merge.declarations location modules); merged = lib.modules.fixup location (lib.options.merge.declarations location modules);
in in
if builtins.length definitions == 1 then first.value else merged.type; if builtins.length definitions == 1 then first.value else merged.type;
@ -1100,6 +1122,43 @@ lib: {
}; };
}; };
## Create a type that allows a value which is either the final type or is transformable
## to the final type.
##
## @type Attrs -> (Any -> Any) -> Attrs -> Attrs
coerceWithLocation =
initial: transform: final:
let
in
if initial.getSubModules != null then
builtins.throw "lib.types.coerceWithLocation's first argument may not have submodules, but got ${initial.description}"
else
lib.types.create {
name = "Coerce";
description = "${initial.description} that is transformed to ${final.description}";
fallback = final.fallback;
check = value: final.check value || (initial.check value && final.check (transform [ ] value));
merge =
location: definitions:
let
process = value: if initial.check value then transform location value else value;
normalize = definition: definition // { value = process definition.value; };
normalized = builtins.map normalize definitions;
in
final.merge location normalized;
getSubOptions = final.getSubOptions;
getSubModules = final.getSubModules;
withSubModules =
modules: lib.types.coerceWithLocation initial transform (final.withSubModules modules);
mergeType = x: y: null;
functor = lib.types.functor "coerceWithLocation" // {
wrapped = final;
};
children = {
inherit initial final;
};
};
dag = { dag = {
## Create a type that allows a DAG (Directed Acyclic Graph) of a given type. ## Create a type that allows a DAG (Directed Acyclic Graph) of a given type.
## ##
@ -1160,10 +1219,12 @@ lib: {
merge = merge =
location: definitions: location: definitions:
submodule.merge location ( submodule.merge location (
builtins.map (definition: { builtins.map
__file__ = definition.__file__; (definition: {
value = normalize definition; __file__ = definition.__file__;
}) definitions value = normalize definition;
})
definitions
); );
}; };
}; };

View file

@ -8,10 +8,10 @@
}, },
"locked": { "locked": {
"dir": "foundation", "dir": "foundation",
"dirtyRev": "9850da8aa9dc9be22e237c9b424a18e801e53ecb-dirty", "dirtyRev": "3f9d287065ac685ce500c2cddb35428b2927f5a2-dirty",
"dirtyShortRev": "9850da8-dirty", "dirtyShortRev": "3f9d287-dirty",
"lastModified": 1718529861, "lastModified": 1720514984,
"narHash": "sha256-X1Wd6mDz8GTaoxt1ylkvZfrJOcZtspJrEjXMtJ2ZyG0=", "narHash": "sha256-AuixwSlYk34Z6+GEc7y4QotF3Hk963zC9I9hAwX5KCE=",
"type": "git", "type": "git",
"url": "file:../?dir=foundation" "url": "file:../?dir=foundation"
}, },
@ -24,10 +24,10 @@
"lib": { "lib": {
"locked": { "locked": {
"dir": "lib", "dir": "lib",
"dirtyRev": "9850da8aa9dc9be22e237c9b424a18e801e53ecb-dirty", "dirtyRev": "3f9d287065ac685ce500c2cddb35428b2927f5a2-dirty",
"dirtyShortRev": "9850da8-dirty", "dirtyShortRev": "3f9d287-dirty",
"lastModified": 1718529861, "lastModified": 1720514984,
"narHash": "sha256-X1Wd6mDz8GTaoxt1ylkvZfrJOcZtspJrEjXMtJ2ZyG0=", "narHash": "sha256-AuixwSlYk34Z6+GEc7y4QotF3Hk963zC9I9hAwX5KCE=",
"type": "git", "type": "git",
"url": "file:../?dir=lib" "url": "file:../?dir=lib"
}, },

View file

@ -1,10 +1,8 @@
{ lib, config }: { config }:
let let
cfg = config.builders.basic; cfg = config.builders.basic;
lib' = config.lib; inherit (config) lib foundation;
inherit (config) foundation;
in in
{ {
config.builders = { config.builders = {
@ -14,15 +12,46 @@ in
build = build =
package: package:
let let
phases = package.phases;
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;
system = package.platform.build.double; system = package.platform.build.double;
dependencies = lib.packages.dependencies.collect package;
context = lib.packages.context.create dependencies { };
hooks = lib.packages.hooks.create dependencies context;
phasesWithHooks =
let
all = lib.lists.flatten [
hooks.build.only
hooks.build.build
hooks.build.host
hooks.build.target
hooks.host.only
hooks.host.host
hooks.host.target
hooks.target.only
hooks.target.target
];
in
builtins.foldl' (final: defaults: lib.dag.apply.defaults final defaults) package.phases all;
phases = lib.dag.apply.defaults phasesWithHooks {
unpack = lib.dag.entry.before [ "patch" ] "";
patch = lib.dag.entry.between [ "unpack" ] [ "configure" ] "";
configure = lib.dag.entry.between [ "patch" ] [ "build" ] "";
build = lib.dag.entry.between [ "configure" ] [ "install" ] "";
install = lib.dag.entry.after [ "build" ] "";
};
sorted = lib.dag.sort.topological phases;
script = lib.strings.concatMapSep "\n" (entry: entry.value) sorted.result;
built = builtins.derivation ( built = builtins.derivation (
package.env package.env
// { // {
@ -36,7 +65,7 @@ in
PATH = PATH =
let let
bins = lib.paths.bin ( bins = lib.paths.bin (
(lib'.packages.dependencies.getPackages package.deps.build.host) (lib.packages.dependencies.get dependencies.build.host)
++ [ ++ [
foundation.stage2-bash foundation.stage2-bash
foundation.stage2-coreutils foundation.stage2-coreutils
@ -70,7 +99,14 @@ in
} }
); );
in in
built // { inherit (package) meta; }; built
// {
inherit (package) meta;
extras = {
inherit package context;
phases = builtins.listToAttrs sorted.result;
} // package.extras;
};
}; };
}; };
} }

View file

@ -1,18 +1,21 @@
# This file handles creating all of the exports for this project and is not # This file handles creating all of the exports for this project and is not
# exported itself. # exported itself.
{ lib, config }: { config }:
let let
lib' = config.lib; inherit (config) lib;
in in
{ {
freeform = lib.types.any; # freeform = lib.types.any;
config = { config = {
exports = { exports = {
lib = config.lib; inherit lib;
modules = import ./modules.nix; modules = import ./modules.nix;
packages = { packages = {
aux-a = config.packages.aux.a;
aux-b = config.packages.aux.b;
# foundation-gcc-x86_64 = # foundation-gcc-x86_64 =
# (config.packages.foundation.gcc.versions."13.2.0".extend (args: { # (config.packages.foundation.gcc.versions."13.2.0".extend (args: {
# config = { # config = {
@ -24,11 +27,13 @@ in
# .config; # .config;
foundation-gcc = config.packages.foundation.gcc; foundation-gcc = config.packages.foundation.gcc;
foundation-binutils = config.packages.foundation.binutils; foundation-binutils = config.packages.foundation.binutils;
foundation-linux-headers = config.packages.foundation.linux-headers.versions.latest.extend { foundation-linux-headers = config.packages.foundation.linux-headers;
platform.host = lib.modules.overrides.force "x86_64-linux"; # foundation-linux-headers = config.packages.foundation.linux-headers.versions.latest.extend {
}; # platform.host = lib.modules.overrides.force "x86_64-linux";
# };
# example-x = config.packages.example.x; # example-x = config.packages.example.x;
# cross-example-x-x86_64-linux = config.packages.cross.x86_64-linux.example.x; cross-aux-a-x86_64-linux = config.packages.cross.x86_64-linux.aux.a;
cross-foundation-gcc-x86_64-linux = config.packages.cross.x86_64-linux.foundation.gcc;
}; };
}; };

View file

@ -5,7 +5,7 @@ in
config = { config = {
lib.options = { lib.options = {
package = lib.options.create { package = lib.options.create {
type = config.lib.types.package; type = config.lib.types.package.base;
description = "A package definition."; description = "A package definition.";
}; };
}; };

View file

@ -1,20 +1,272 @@
{ { lib, config }:
lib, let
lib', lib' = config.lib;
config, in
}:
{ {
config = { config = {
lib.packages = { lib.packages = {
dependencies = { dependencies = {
getPackages = get =
dependencies: dependencies:
let let
available = builtins.filter (dependency: !(builtins.isNull dependency)) ( exists = value: !(builtins.isNull value);
builtins.attrValues dependencies available = builtins.filter exists dependencies;
);
in in
builtins.map (dependency: dependency.package) available; builtins.map (dependency: dependency.package) available;
build =
build': host': target':
builtins.mapAttrs (name: dep: lib'.packages.build dep build' host' target');
collect =
package:
let
isPropagated = name: package: package.propagate or false;
getPropagatedDependencies = target: builtins.attrValues (lib.attrs.filter isPropagated target);
process =
dependencies:
let
getDeps =
name: dependency:
let
deps = {
build = {
only = getPropagatedDependencies dependency.deps.build.only ++ process dependency.deps.build.only;
build =
getPropagatedDependencies dependency.deps.build.build
++ process dependency.deps.build.build;
host = getPropagatedDependencies dependency.deps.build.host ++ process dependency.deps.build.host;
target =
getPropagatedDependencies dependency.deps.build.target
++ process dependency.deps.build.target;
};
host = {
only = getPropagatedDependencies dependency.deps.host.only ++ process dependency.deps.host.only;
host = getPropagatedDependencies dependency.deps.host.host ++ process dependency.deps.host.host;
target =
getPropagatedDependencies dependency.deps.host.target
++ process dependency.deps.host.target;
};
target = {
only = getPropagatedDependencies dependency.deps.target.only ++ process dependency.deps.target.only;
target =
getPropagatedDependencies dependency.deps.target.target
++ process dependency.deps.target.target;
};
};
in
lib.lists.flatten [
deps.build.only
deps.build.build
deps.build.host
deps.build.target
deps.host.only
deps.host.host
deps.host.target
deps.target.only
deps.target.target
];
propagated = lib.attrs.mapToList getDeps dependencies;
in
lib.lists.flatten propagated;
in
{
build = {
only = builtins.attrValues package.deps.build.only ++ process package.deps.build.only;
build = builtins.attrValues package.deps.build.build ++ process package.deps.build.build;
host = builtins.attrValues package.deps.build.host ++ process package.deps.build.host;
target = builtins.attrValues package.deps.build.target ++ process package.deps.build.target;
};
host = {
only = builtins.attrValues package.deps.host.only ++ process package.deps.host.only;
host = builtins.attrValues package.deps.host.host ++ process package.deps.host.host;
target = builtins.attrValues package.deps.host.target ++ process package.deps.host.target;
};
target = {
only = builtins.attrValues package.deps.target.only ++ process package.deps.target.only;
target = builtins.attrValues package.deps.target.target ++ process package.deps.target.target;
};
};
};
context = {
create =
collected: ctx:
let
process =
path:
let
dependencies = lib.attrs.selectOrThrow path collected;
contexts = builtins.map (dependency: dependency.context or { }) dependencies;
result = lib.modules.run {
prefix = [ "<package>" ];
modules = builtins.map (context: { config = context; }) contexts ++ [
{
freeform = lib.types.any;
options = config.packages.context.options // {
target = lib.options.create {
description = "The dependency target that is being generated.";
type = lib.types.enum [
"build.only"
"build.build"
"build.host"
"build.target"
"host.only"
"host.host"
"host.target"
"target.only"
"target.target"
];
writable = false;
default.value = builtins.concatStringsSep "." path;
};
deps = lib.options.create {
description = "The collected dependencies.";
writable = false;
default.value = collected;
type = lib.types.submodule {
options = {
build = {
only = lib.options.create { type = lib.types.list.of lib'.types.package; };
build = lib.options.create { type = lib.types.list.of lib'.types.package; };
host = lib.options.create { type = lib.types.list.of lib'.types.package; };
target = lib.options.create { type = lib.types.list.of lib'.types.package; };
};
host = {
only = lib.options.create { type = lib.types.list.of lib'.types.package; };
host = lib.options.create { type = lib.types.list.of lib'.types.package; };
target = lib.options.create { type = lib.types.list.of lib'.types.package; };
};
target = {
only = lib.options.create { type = lib.types.list.of lib'.types.package; };
target = lib.options.create { type = lib.types.list.of lib'.types.package; };
};
};
};
};
};
config = ctx;
}
];
};
in
result.config;
in
{
build = {
only = process [
"build"
"only"
];
build = process [
"build"
"build"
];
host = process [
"build"
"host"
];
target = process [
"build"
"target"
];
};
host = {
only = process [
"host"
"only"
];
host = process [
"host"
"host"
];
target = process [
"host"
"target"
];
};
target = {
only = process [
"target"
"only"
];
target = process [
"target"
"target"
];
};
};
};
hooks = {
create =
collected: ctx:
let
process =
path:
let
dependencies = lib.attrs.selectOrThrow path collected;
hooks = builtins.map
(
dependency:
let
getHooks = dependency.hooks or (lib.fp.const { });
in
getHooks ctx
)
dependencies;
in
hooks;
in
{
build = {
only = process [
"build"
"only"
];
build = process [
"build"
"build"
];
host = process [
"build"
"host"
];
target = process [
"build"
"target"
];
};
host = {
only = process [
"host"
"only"
];
host = process [
"host"
"host"
];
target = process [
"host"
"target"
];
};
target = {
only = process [
"target"
"only"
];
target = process [
"target"
"target"
];
};
};
}; };
getLatest = getLatest =
@ -25,54 +277,89 @@
in in
builtins.head sorted; builtins.head sorted;
resolve =
alias:
if alias ? versions then
alias.versions.${config.preferences.packages.version}
or (alias.versions.${lib'.packages.getLatest alias})
else
alias;
build = build =
package: build: host: target: alias: build: host: target:
let let
resolved = package = lib'.packages.resolve alias;
if package ? versions then
package.versions.${config.preferences.packages.version}
or (package.versions.${lib'.packages.getLatest package})
else
package;
buildDependencies = buildDependencies =
build': host': target': build': host': target':
builtins.mapAttrs (name: dep: lib'.packages.build dep build' host' target'); builtins.mapAttrs (name: dep: lib'.packages.build dep build' host' target');
result = resolved.extend ( platform = {
{ config }: build = lib.modules.overrides.force build;
{ host = lib.modules.overrides.force host;
config = { target = lib.modules.overrides.force target;
platform = { };
build = build;
host = host;
target = lib.modules.override 150 target;
};
deps = { withPlatform = lib.modules.run {
build = { modules = package.__modules__ ++ [
only = buildDependencies build build build resolved.deps.build.only; lib'.types.package.children.submodule
build = buildDependencies build build target resolved.deps.build.build; (
host = buildDependencies build host target resolved.deps.build.host; { config }:
target = buildDependencies build target target resolved.deps.build.target; {
}; config = {
host = { __modules__ = package.__modules__;
only = buildDependencies host host host resolved.deps.host.only;
host = buildDependencies host host target resolved.deps.host.host;
target = buildDependencies host target target resolved.deps.host.target;
};
target = {
only = buildDependencies target target target resolved.deps.target.only;
target = buildDependencies target target target resolved.deps.target.target;
};
};
package = config.builder.build config; inherit platform;
};
}
)
];
};
# 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;
build = buildDependencies build build target withPlatform.config.deps.build.build;
host = buildDependencies build host target withPlatform.config.deps.build.host;
target = buildDependencies build target target withPlatform.config.deps.build.target;
}; };
} host = {
); only = buildDependencies host host host withPlatform.config.deps.host.only;
host = buildDependencies host host target withPlatform.config.deps.host.host;
target = buildDependencies host target target withPlatform.config.deps.host.target;
};
target = {
only = buildDependencies target target target withPlatform.config.deps.target.only;
target = buildDependencies target target target withPlatform.config.deps.target.target;
};
};
};
withPackage = lib.modules.run {
modules = package.__modules__ ++ [
lib'.types.package.children.submodule
(
{ config }:
{
config = {
__modules__ = package.__modules__;
inherit platform;
deps = lib.modules.overrides.force withDeps.deps;
package = lib.modules.overrides.force (withDeps.builder.build withDeps);
};
}
)
];
};
in in
result; withPackage.config;
}; };
}; };
} }

View file

@ -1220,6 +1220,7 @@ in
vendor, vendor,
kernel, kernel,
abi, abi,
...
}: }:
types.cpu.check cpu types.cpu.check cpu
&& types.vendor.check vendor && types.vendor.check vendor
@ -1227,6 +1228,17 @@ in
&& types.abi.check abi; && types.abi.check abi;
}; };
platformWithBuildInfo = lib.types.create {
name = "systemWithBuildInfo";
description = "fully parsed representation of llvm- or nix-style platform tuple with build information";
merge = lib.options.merge.one;
check =
value:
lib.types.is "systemWithBuildInfo" value
&& value ? system
&& lib'.systems.types.platform.check value.system;
};
endian = lib.types.enum (builtins.attrValues types.endians); endian = lib.types.enum (builtins.attrValues types.endians);
endians = setTypes types.generic.endian { endians = setTypes types.generic.endian {
@ -2792,7 +2804,7 @@ in
assert resolved.useAndroidPrebuilt -> resolved.isAndroid; assert resolved.useAndroidPrebuilt -> resolved.isAndroid;
assert assertions; assert assertions;
# And finally, return the generated system info. # And finally, return the generated system info.
resolved; lib.types.set "systemWithBuildInfo" resolved;
}; };
}; };
} }

View file

@ -1,8 +1,9 @@
{ { lib, config }:
lib, let
lib', inherit (config) preferences builders;
config,
}: lib' = config.lib;
in
{ {
config = { config = {
lib.types = { lib.types = {
@ -55,6 +56,10 @@
in in
lib.types.either type (lib.types.list.of type); lib.types.either type (lib.types.list.of type);
platform =
lib.types.coerce lib.types.string lib'.systems.withBuildInfo
lib'.systems.types.platformWithBuildInfo;
builder = lib.types.submodule { builder = lib.types.submodule {
freeform = lib.types.any; freeform = lib.types.any;
@ -66,256 +71,368 @@
}; };
}; };
packages = lib.types.attrs.of (lib'.types.alias); packages = lib.types.attrs.of (lib.types.attrs.of lib'.types.alias);
alias = lib.types.attrs.of ( dependencies =
lib.types.submodule { build: host: target:
options = { let
versions = lib.options.create { initial = lib.types.raw;
description = "All available package versions.";
type = lib.types.attrs.of lib'.types.package; transform =
}; value:
let
package = lib'.packages.resolve value;
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 {
options = {
stable = lib.options.create {
description = "The stable version of the package.";
type = lib.types.nullish lib'.types.package;
}; };
}
);
dependencies = lib.types.attrs.of ( latest = lib.options.create {
lib.types.nullish (lib.types.either lib'.types.alias lib'.types.package) description = "The latest version of the package.";
); type = lib'.types.package;
};
package = lib.types.submodule ( versions = lib.options.create {
{ config, meta }: description = "Available versions of the package.";
{ type = lib.types.attrs.of lib'.types.package;
options = { default.value = { };
extend = lib.options.create { };
description = "Extend the package's submodules with additional configuration."; };
type = lib.types.function lib.types.raw; };
default.value =
value: package =
let let
result = meta.extend { normalize =
modules = if builtins.isAttrs value then [ { config = value; } ] else lib.lists.from.any value; 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;
};
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 = { };
}; };
in
result.config;
};
name = lib.options.create { build = lib.options.create {
description = "The name of the package."; description = "Dependencies which are created in the build environment and are executed in the build environment.";
type = lib.types.string; type = lib'.types.dependencies build build target;
default = { default.value = { };
text = "\${config.pname}-\${config.version}"; };
value =
if config.pname != null && config.version != null then "${config.pname}-${config.version}" else "";
};
};
pname = lib.options.create { host = lib.options.create {
description = "The program name for the package"; description = "Dependencies which are created in the build environment and are executed in the host environment.";
type = lib.types.nullish lib.types.string; type = lib'.types.dependencies build host target;
default.value = null; default.value = { };
}; };
version = lib.options.create { target = lib.options.create {
description = "The version for the package."; description = "Dependencies which are created in the build environment and are executed in the target environment.";
type = lib.types.nullish lib.types.version; type = lib'.types.dependencies build target target;
default.value = null; 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.string;
default.value = "x86_64-linux";
apply =
raw:
let
system = lib'.systems.from.string raw;
x = lib'.systems.withBuildInfo raw;
in
x;
};
host = lib.options.create {
description = "The host platform for the package.";
type = lib.types.string;
default.value = "x86_64-linux";
# apply = raw: let
# system = lib'.systems.from.string raw;
# in {
# inherit raw system;
# double = lib'.systems.into.double system;
# triple = lib'.systems.into.triple system;
# };
apply =
raw:
let
system = lib'.systems.from.string raw;
x = lib'.systems.withBuildInfo raw;
in
x;
};
target = lib.options.create {
description = "The target platform for the package.";
type = lib.types.string;
default.value = "x86_64-linux";
# apply = raw: let
# system = lib'.systems.from.string raw;
# in {
# inherit raw system;
# double = lib'.systems.into.double system;
# triple = lib'.systems.into.triple system;
# };
apply =
raw:
let
system = lib'.systems.from.string raw;
x = lib'.systems.withBuildInfo raw;
in
x;
};
};
phases = lib.options.create {
description = "The phases for the package.";
type = lib.types.dag.of (lib.types.either lib.types.string (lib.types.function lib.types.string));
default.value = { };
};
env = lib.options.create {
description = "The environment for the package.";
type = lib.types.attrs.of lib.types.string;
default.value = { };
};
builder = lib.options.create {
description = "The builder for the package.";
type = lib'.types.builder;
};
deps = {
build = {
only = lib.options.create {
description = "Dependencies which are only used in the build environment.";
type = lib'.types.dependencies;
default.value = { };
}; };
build = lib.options.create { host = {
description = "Dependencies which are created in the build environment and are executed in the build environment."; only = lib.options.create {
type = lib'.types.dependencies; description = "Dependencies which are only used in the host environment.";
default.value = { }; 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 = { };
};
}; };
host = lib.options.create { target = {
description = "Dependencies which are created in the build environment and are executed in the host environment."; only = lib.options.create {
type = lib'.types.dependencies; description = "Dependencies which are only used in the target environment.";
default.value = { }; type = lib'.types.dependencies target target target;
}; default.value = { };
};
target = lib.options.create { target = lib.options.create {
description = "Dependencies which are created in the build environment and are executed in the target environment."; description = "Dependencies which are executed in the target environment.";
type = lib'.types.dependencies; type = lib'.types.dependencies target target target;
default.value = { }; default.value = { };
}; };
};
host = {
only = lib.options.create {
description = "Dependencies which are only used in the host environment.";
type = lib'.types.dependencies;
default.value = { };
};
host = lib.options.create {
description = "Dependencies which are executed in the host environment.";
type = lib'.types.dependencies;
default.value = { };
};
target = lib.options.create {
description = "Dependencies which are executed in the host environment which produces code for the target environment.";
type = lib'.types.dependencies;
default.value = { };
};
};
target = {
only = lib.options.create {
description = "Dependencies which are only used in the target environment.";
type = lib'.types.dependencies;
default.value = { };
};
target = lib.options.create {
description = "Dependencies which are executed in the target environment.";
type = lib'.types.dependencies;
default.value = { };
}; };
}; };
}; };
package = lib.options.create { submodule =
description = "The built derivation."; { config, meta }:
type = lib.types.derivation; let
default.value = config.builder.build config; 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 = [ ];
};
extend = lib.options.create {
description = "Extend the package definition.";
type = lib.types.function lib.types.raw;
internal = true;
writable = false;
default.value = module:
let
normalized =
if builtins.isList module then
module
else if builtins.isFunction module || module ? config then
[ module ]
else
[{
config = module;
}];
result = meta.extend {
modules =
normalized ++ [
{
config.__modules__ = lib.modules.overrides.force (config.__modules__ ++ normalized);
}
];
};
in
result.config;
};
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 = [ ];
};
};
extras = lib.options.create {
description = "Extra information for the package.";
type = lib.types.attrs.of lib.types.any;
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;
};
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;
};
phases = lib.options.create {
description = "The phases for the package.";
type = lib.types.dag.of lib.types.string;
default.value = { };
};
context = lib.options.create {
description = "The context information that the package provides.";
type = lib.types.attrs.of lib.types.raw;
default.value = { };
};
hooks = lib.options.create {
description = "The hooks that the package provides.";
type = lib.types.function (lib.types.dag.of lib.types.string);
default.value = ctx: { };
};
propagate = lib.options.create {
description = "Whether the package should propagate its hooks and context.";
type = lib.types.bool;
default.value = false;
};
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
); type
// {
children = type.children // {
inherit submodule;
};
};
}; };
}; };
} }

View file

@ -0,0 +1,36 @@
{ lib', config }:
let
inherit (config) builders packages;
in
{
config.packages.aux.a = {
versions = {
"latest" =
{ config }:
{
config = {
meta = {
platforms = [ "i686-linux" ];
};
name = "${config.pname}-${config.version}";
pname = "a";
version = "1.0.0";
builder = builders.basic;
deps.build.host = {
inherit (packages.aux) b;
};
phases = {
install = ''
echo "a with b: ${config.deps.build.host.b.package.system}" > $out
'';
};
};
};
};
};
}

View file

@ -0,0 +1,54 @@
{ config }:
let
inherit (config) lib builders packages;
in
{
config.packages.aux.b = {
versions = {
"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;
deps = {
build = {
host = {
c = packages.aux.c.versions.latest.extend {
propagate = true;
};
};
};
};
context = {
"foundation:cflags" = [ "-I $AUX_B/include" ];
};
hooks = ctx: { "aux:b:env" = lib.dag.entry.after [ "unpack" ] ''export AUX_B=${config.package}''; };
phases = {
install = ''
echo "b" > $out
'';
};
};
};
};
};
}

View file

@ -0,0 +1,44 @@
{ config }:
let
inherit (config) lib builders packages;
in
{
config.packages.aux.c = {
versions = {
"latest" =
{ config }:
{
options = {
custom = lib.options.create { type = lib.types.bool; };
};
config = {
meta = {
platforms = [ "i686-linux" ];
};
name = "${config.pname}-${config.version}";
custom = true;
pname = "c";
version = "1.0.0";
builder = builders.basic;
context = {
"foundation:cflags" = [ "-I $AUX_C/include" ];
};
hooks = ctx: { "aux:c:env" = lib.dag.entry.after [ "unpack" ] ''export AUX_C=${config.package}''; };
phases = {
install = ''
echo "c" > $out
'';
};
};
};
};
};
}

View file

@ -1,30 +1,43 @@
{ { config }:
lib,
lib',
config,
}:
let let
doubles = lib'.systems.doubles.all; inherit (config) lib;
doubles = lib.systems.doubles.all;
packages = builtins.removeAttrs config.packages [ "cross" ]; packages = builtins.removeAttrs config.packages [ "cross" ];
in in
{ {
includes = [ ./foundation ]; includes = [
./foundation
./aux/a.nix
./aux/b.nix
./aux/c.nix
];
options = { options = {
packages = lib.options.create { packages = lib.options.create {
description = "The package set."; description = "The package set.";
type = lib.types.submodule { type = lib.types.submodule {
freeform = lib.types.attrs.of (lib.types.submodule { freeform = lib'.types.alias; }); freeform = lib.types.packages;
options.cross = lib.attrs.generate doubles ( options = {
system: cross = lib.attrs.generate doubles (
lib.options.create { system:
description = "The cross-compiled package set for the ${system} target."; lib.options.create {
type = lib'.types.packages; description = "The cross-compiled package set for the ${system} target.";
default = { }; type = lib.types.packages;
} default.value = { };
); }
);
# NOTE: We may offer a way to set default context values. For this reason we have
# nested `options` under `context` rather than using a plain option directly under `packages`.
context.options = lib.options.create {
description = "The available options for package contexts.";
default.value = { };
type = lib.types.attrs.of lib.types.option;
};
};
}; };
}; };
@ -40,54 +53,37 @@ in
}; };
}; };
config.packages.cross = lib.attrs.generate doubles ( config = {
system: packages.cross = lib.attrs.generate doubles (
builtins.mapAttrs ( system:
namespace: builtins.mapAttrs
builtins.mapAttrs ( (
name: alias: namespace:
let builtins.mapAttrs (
setHost = name: alias:
package: let
if package != { } then setHost =
(package.extend ( package:
{ config }: package
{ // {
config = { __modules__ = package.__modules__ ++ [
platform = { {
host = lib.modules.overrides.force system; config.platform = {
target = lib.modules.overrides.default system; host = lib.modules.override 5 system;
}; target = lib.modules.override 5 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;
updated = alias // { updated = alias // {
versions = builtins.mapAttrs (version: package: setHost package) alias.versions; versions = builtins.mapAttrs (version: package: setHost package) alias.versions;
}; };
in in
updated updated
) )
) packages )
); packages
);
};
} }

View file

@ -11,13 +11,14 @@ let
# These are the upstream foundational packages exported from the Aux Foundation project. # These are the upstream foundational packages exported from the Aux Foundation project.
foundation foundation
packages
; ;
in in
{ {
config.packages.foundation.binutils = { config.packages.foundation.binutils = {
versions = { versions = {
"latest" = "latest" =
{ config, meta }: { config }:
{ {
options = { options = {
src = lib.options.create { src = lib.options.create {
@ -36,9 +37,17 @@ in
builder = builders.basic; builder = builders.basic;
deps = {
build = {
host = {
inherit (packages.foundation) gcc;
};
};
};
env = { env = {
PATH = lib.paths.bin [ PATH = lib.paths.bin [
foundation.stage2-gcc # foundation.stage2-gcc
foundation.stage2-binutils foundation.stage2-binutils
foundation.stage2-gnumake foundation.stage2-gnumake
foundation.stage2-gnupatch foundation.stage2-gnupatch
@ -86,24 +95,24 @@ in
]; ];
in in
{ {
unpack = lib.dag.entry.before [ "patch" ] '' unpack = ''
tar xf ${config.src} tar xf ${config.src}
cd binutils-${config.version} cd binutils-${config.version}
''; '';
patch = lib.dag.entry.between [ "configure" ] [ "unpack" ] '' patch = ''
${lib.strings.concatMapSep "\n" (file: "patch -Np1 -i ${file}") patches} ${lib.strings.concatMapSep "\n" (file: "patch -Np1 -i ${file}") patches}
''; '';
configure = lib.dag.entry.between [ "build" ] [ "patch" ] '' configure = ''
bash ./configure ${builtins.concatStringsSep " " configureFlags} bash ./configure ${builtins.concatStringsSep " " configureFlags}
''; '';
build = lib.dag.entry.between [ "install" ] [ "configure" ] '' build = ''
make -j $NIX_BUILD_CORES make -j $NIX_BUILD_CORES
''; '';
install = lib.dag.entry.after [ "build" ] '' install = ''
make -j $NIX_BUILD_CORES install-strip make -j $NIX_BUILD_CORES install-strip
''; '';
}; };

View file

@ -9,6 +9,8 @@
./gcc ./gcc
./binutils ./binutils
./linux-headers ./linux-headers
./glibc
# ./xz
]; ];
config = { config = {

View file

@ -1,19 +1,23 @@
{ { config, options }:
lib,
lib',
config,
options,
}:
let let
inherit (config) inherit (config)
lib
mirrors mirrors
builders builders
# These are the upstream foundational packages exported from the Aux Foundation project. # These are the upstream foundational packages exported from the Aux Foundation project.
foundation foundation
packages
; ;
in in
{ {
config.packages.context.options = {
"foundation:cflags" = lib.options.create {
type = lib.types.list.of lib.types.string;
default.value = [ ];
};
};
config.packages.foundation.gcc = { config.packages.foundation.gcc = {
versions = { versions = {
"latest" = "latest" =
@ -91,51 +95,30 @@ in
builder = builders.basic; builder = builders.basic;
env = { env = {
PATH = PATH = lib.paths.bin [
let foundation.stage2-gcc
gcc = foundation.stage2-binutils
if foundation.stage2-gnumake
config.platform.build.triple == config.platform.host.triple foundation.stage2-gnused
# If we're on the same system then we can use the existing GCC instance. foundation.stage2-gnugrep
then foundation.stage2-gawk
foundation.stage2-gcc foundation.stage2-diffutils
# Otherwise we are going to need a cross-compiler. foundation.stage2-findutils
else foundation.stage2-gnutar
# TODO: Create a gcc-cross package. foundation.stage2-gzip
(meta.extend (args: { foundation.stage2-bzip2
config = { foundation.stage1-xz
platform = { ];
build = config.platform.build.triple;
host = config.platform.build.triple;
target = lib.modules.override.force config.platform.host.triple;
};
};
})).config.package;
in
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 = phases =
let let
host = lib'.systems.withBuildInfo config.platform.host; host = lib.systems.withBuildInfo config.platform.host;
mbits = if host.system.cpu.family == "x86" then if host.is64bit then "-m64" else "-m32" else ""; mbits = if host.system.cpu.family == "x86" then if host.is64bit then "-m64" else "-m32" else "";
in in
{ {
unpack = lib.dag.entry.before [ "patch" ] '' unpack = ''
# Unpack # Unpack
tar xf ${config.src} tar xf ${config.src}
tar xf ${config.gmp.src} tar xf ${config.gmp.src}
@ -150,17 +133,15 @@ in
ln -s ../isl-${config.isl.version} isl ln -s ../isl-${config.isl.version} isl
''; '';
patch = lib.dag.entry.between [ "configure" ] [ "unpack" ] '' patch = ''
# Patch # Patch
# force musl even if host triple is gnu # force musl even if host triple is gnu
sed -i 's|"os/gnu-linux"|"os/generic"|' libstdc++-v3/configure.host sed -i 's|"os/gnu-linux"|"os/generic"|' libstdc++-v3/configure.host
''; '';
configure = lib.dag.entry.between [ "build" ] [ "patch" ] '' configure = ''
# Configure # Configure
export CC="gcc -Wl,-dynamic-linker -march=${ export CC="gcc -Wl,-dynamic-linker -Wl,${foundation.stage1-musl}/lib/libc.so"
host.gcc.arch or host.system.cpu.family
} ${mbits} -Wl,${foundation.stage1-musl}/lib/libc.so"
export CXX="g++ -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 CFLAGS_FOR_TARGET="-Wl,-dynamic-linker -Wl,${foundation.stage1-musl}/lib/libc.so"
export LIBRARY_PATH="${foundation.stage1-musl}/lib" export LIBRARY_PATH="${foundation.stage1-musl}/lib"
@ -182,12 +163,12 @@ in
CXXFLAGS=-static CXXFLAGS=-static
''; '';
build = lib.dag.entry.between [ "install" ] [ "configure" ] '' build = ''
# Build # Build
make -j $NIX_BUILD_CORES make -j $NIX_BUILD_CORES
''; '';
install = lib.dag.entry.after [ "build" ] '' install = ''
# Install # Install
make -j $NIX_BUILD_CORES install-strip make -j $NIX_BUILD_CORES install-strip
''; '';

View file

@ -79,12 +79,12 @@ in
}; };
phases = { phases = {
unpack = lib.dag.entry.before [ "patch" ] '' unpack = ''
tar xf ${config.src} tar xf ${config.src}
cd glibc-${config.version} cd glibc-${config.version}
''; '';
configure = lib.dag.entry.between [ "build" ] [ "patch" ] '' configure = ''
mkdir build mkdir build
cd build cd build
# libstdc++.so is built against musl and fails to link # libstdc++.so is built against musl and fails to link
@ -96,12 +96,12 @@ in
--with-headers=${foundation.stage1-linux-headers}/include --with-headers=${foundation.stage1-linux-headers}/include
''; '';
build = lib.dag.entry.between [ "install" ] [ "configure" ] '' build = ''
# Build # Build
make -j $NIX_BUILD_CORES make -j $NIX_BUILD_CORES
''; '';
install = lib.dag.entry.after [ "build" ] '' install = ''
# Install # Install
make -j $NIX_BUILD_CORES install-strip make -j $NIX_BUILD_CORES install-strip
''; '';

View file

@ -54,20 +54,16 @@ in
}; };
phases = { phases = {
unpack = lib.dag.entry.before [ "patch" ] '' unpack = ''
tar xf ${config.src} tar xf ${config.src}
cd linux-${config.version} cd linux-${config.version}
''; '';
patch = lib.dag.entry.between [ "configure" ] [ "unpack" ] ''''; build = ''
configure = lib.dag.entry.between [ "build" ] [ "patch" ] '''';
build = lib.dag.entry.between [ "install" ] [ "configure" ] ''
make -j $NIX_BUILD_CORES CC=musl-gcc HOSTCC=musl-gcc ARCH=${config.platform.host.linux.arch} headers make -j $NIX_BUILD_CORES CC=musl-gcc HOSTCC=musl-gcc ARCH=${config.platform.host.linux.arch} headers
''; '';
install = lib.dag.entry.after [ "build" ] '' install = ''
find usr/include -name '.*' -exec rm {} + find usr/include -name '.*' -exec rm {} +
mkdir -p $out mkdir -p $out
cp -rv usr/include $out/ cp -rv usr/include $out/