Compare commits

...

21 commits

Author SHA1 Message Date
Austreelis 866b8902c9 fix(lib): swapped entries in test dag.sort.topological."sorts a graph" (#9)
Some checks failed
buildbot/nix-eval Build done.
I figure it's a simple typo. This test expects entries `"a"`, `"b"`, `"c"`, `"d"` to be lexicographically sorted but fails. The actual result is that entries are sorted in this order: `c, b, a, d`. This is because the test adds the entry `"b" = lib.dag.entry.between [ "c" ] [ "a" ] "b"`, i.e. after `"c"` and before `"a"`. I haven't checked if it was a logic error in the sort implementation, as other pieces of labs rely on it (and use `lib.dag.entry.between` with the arguments flipped relative to the test, which makes sense), and the arguments of the function `lib.dag.entry.between` are named "after", *then* "before".

Co-authored-by: Austreelis <dev.austreelis@swhaele.net>
Reviewed-on: auxolotl/labs#9
Reviewed-by: Jake Hamilton <jake.hamilton@hey.com>
Co-authored-by: Austreelis <austreelis@noreply.git.auxolotl.org>
Co-committed-by: Austreelis <austreelis@noreply.git.auxolotl.org>
2024-10-08 18:44:31 +00:00
Victor Fuentes d7762a5a78 add bootstraped x86_64-linux cross compiled gcc (#8)
Some checks failed
buildbot/nix-eval Build done.
Work in progress cross compiler for x86_64. I've managed to get a full x86_64 gcc using the binaries built from foundation, and am working on implementing their builds into tidepool.

### Bootstrapping steps
0) Start with i686 tools (gcc, binutils, musl, etc)
1) Build binutils targeting x86_64-linux
2) Build a minimal gcc cross compiler using the cross binutils. This minimal cross compiler does not have support for libc, so is pretty much only useful for building musl or glibc.
3) Use the minimal cross compiler to build x86_64-linux glibc or musl
4) Now that we have a cross compiler and x86_64-linux libc, we can build gcc for the target architecture!
5) Profit! We can now build anything x86_64 using our gcc compiler!

Co-authored-by: Jake Hamilton <jake.hamilton@hey.com>
Reviewed-on: auxolotl/labs#8
Reviewed-by: Jake Hamilton <jake.hamilton@hey.com>
Co-authored-by: Victor Fuentes <vmfuentes64@gmail.com>
Co-committed-by: Victor Fuentes <vmfuentes64@gmail.com>
2024-09-22 02:55:02 +00:00
Austreelis cadfaabc85 "Fix lib.types.derivations.shell's check" (#7)
Some checks failed
buildbot/nix-eval Build done.
"`lib.types.derivations.shell` uses `lib.packages.isDerivation` but didn't passed an argument, making code using it fail with `error: value is a function while a Boolean was expected`"

Co-authored-by: Austreelis <dev@austreelis.net>
Reviewed-on: auxolotl/labs#7
Reviewed-by: isabel roses <isabel@isabelroses.com>
Reviewed-by: Jake Hamilton <jake.hamilton@hey.com>
Co-authored-by: Austreelis <austreelis@noreply.git.auxolotl.org>
Co-committed-by: Austreelis <austreelis@noreply.git.auxolotl.org>
2024-08-15 16:06:20 +00:00
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
30 changed files with 2010 additions and 807 deletions

View file

@ -1,5 +1,5 @@
#!/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)

View file

@ -3,17 +3,18 @@
"lib": {
"locked": {
"dir": "lib",
"dirtyRev": "9850da8aa9dc9be22e237c9b424a18e801e53ecb-dirty",
"dirtyShortRev": "9850da8-dirty",
"lastModified": 1718529861,
"narHash": "sha256-tv/0C7ixH+9Ij+r+5nua48OlXXXnbdEsnenxX4eG/Sk=",
"lastModified": 1723737980,
"narHash": "sha256-1WnFatW5kSuO2jjt62hvSbH84TSYyO+VmvkJ0d5e/ZY=",
"ref": "master",
"rev": "cadfaabc853d20f2bc20bad794fcbe520ea48f13",
"revCount": 82,
"type": "git",
"url": "file:../?dir=lib"
"url": "file:../"
},
"original": {
"dir": "lib",
"type": "git",
"url": "file:../?dir=lib"
"url": "file:../"
}
},
"root": {

View file

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

View file

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

View file

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

View file

@ -21,7 +21,7 @@ lib: {
## Apply a topological sort to a DAG.
##
## @type Dag a -> { result :: List a } | { cycle :: List a, loops :: List a }
topographic =
topological =
graph:
let
getEntriesBefore =
@ -43,7 +43,7 @@ lib: {
isBefore = a: b: builtins.elem a.name b.after;
sorted = lib.lists.sort.topographic isBefore entries;
sorted = lib.lists.sort.topological isBefore entries;
in
if sorted ? result then
{
@ -95,7 +95,7 @@ lib: {
## Create a new DAG entry.
##
## @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.
##
@ -105,12 +105,12 @@ lib: {
## Create a new DAG entry that occurs before other entries.
##
## @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.
##
## @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 = {
@ -121,7 +121,7 @@ lib: {
tag:
let
process =
i: before: after: entries:
i: after: before: entries:
let
name = "${tag}-${builtins.toString i}";
entry = builtins.head entries;
@ -130,7 +130,7 @@ lib: {
if builtins.length entries == 0 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
{ "${name}" = lib.dag.entry.after after entry; } // (process (i + 1) before [ name ] rest);
in
@ -144,12 +144,12 @@ lib: {
## 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
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.
##
## @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" = {
"topographic" = {
"topological" = {
"handles an empty graph" =
let
expected = [ ];
actual = lib.dag.sort.topographic { };
actual = lib.dag.sort.topological { };
in
actual.result == expected;
@ -147,9 +147,9 @@ in
value = "d";
}
];
actual = lib.dag.sort.topographic {
actual = lib.dag.sort.topological {
a = lib.dag.entry.anywhere "a";
b = lib.dag.entry.between [ "c" ] [ "a" ] "b";
b = lib.dag.entry.between [ "a" ] [ "c" ] "b";
c = lib.dag.entry.before [ "c" ] "c";
d = lib.dag.entry.after [ "c" ] "d";
};

View file

@ -31,15 +31,15 @@ lib: {
in
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.
##
## @type (a -> a -> Bool) -> List a -> List a
topographic =
topological =
predicate: list:
let
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
if builtins.length list < 2 then
{ result = list; }
@ -224,5 +224,11 @@ lib: {
filter = result: value: if builtins.elem value result then result else result ++ [ value ];
in
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 =
definition:
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
);
normalize = value: {

View file

@ -49,18 +49,18 @@ lib: {
##
## @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 ? { },
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";
@ -108,7 +108,7 @@ lib: {
identifier = lib.options.getIdentifier location;
first = builtins.elemAt definitions 0;
files = builtins.map lib.modules.getFiles definitions;
files = lib.modules.getFiles definitions;
serializedFiles = builtins.concatStringsSep " and " files;
getType =
@ -118,13 +118,16 @@ lib: {
else
builtins.typeOf value;
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;
commonType = builtins.foldl'
(
type: definition:
if getType definition.value != type then
builtins.throw "The option `${identifier}` has conflicting definitions in ${serializedFiles}"
else
type
)
(getType first.value)
definitions;
mergeStringifiableAttrs = lib.options.merge.one;
@ -132,7 +135,7 @@ lib: {
mergeList =
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
(lib.types.list.of lib.types.any).merge;
@ -140,10 +143,12 @@ lib: {
location: definitions: x:
let
resolvedLocation = location ++ [ "<function body>" ];
resolvedDefinitions = builtins.map (definition: {
__file__ = definition.__file__;
value = definition.value x;
}) definitions;
resolvedDefinitions = builtins.map
(definition: {
__file__ = definition.__file__;
value = definition.value x;
})
definitions;
in
lib.types.any.merge resolvedLocation resolvedDefinitions;
@ -200,14 +205,15 @@ lib: {
## @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}";
};
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.
@ -317,14 +323,15 @@ lib: {
## @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}";
};
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;
@ -447,8 +454,7 @@ lib: {
};
attrs = {
## A type that allows an attribute set containing any type of value. The merged
## definitions must all be.
## A type that allows an attribute set containing any type of value.
##
## @type Attrs
any = lib.types.create {
@ -480,10 +486,12 @@ lib: {
let
normalize =
definition:
builtins.mapAttrs (name: value: {
__file__ = definition.__file__;
value = value;
}) definition.value;
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;
@ -520,17 +528,19 @@ lib: {
let
normalize =
definition:
builtins.mapAttrs (name: value: {
__file__ = definition.__file__;
value = value;
}) definition.value;
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;
merged.optional.value or type.fallback.value or merged.merged;
in
builtins.zipAttrsWith zipper normalized;
getSubOptions = prefix: type.getSubOptions (prefix ++ [ "<name>" ]);
@ -569,7 +579,7 @@ lib: {
##
## @type Attrs
shell = lib.types.derivation // {
check = value: lib.packages.isDerivation && builtins.hasAttr "shellPath" value;
check = value: lib.packages.isDerivation value && builtins.hasAttr "shellPath" value;
};
};
@ -606,25 +616,30 @@ lib: {
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}]" ])
type
[
{
file = definition.file;
value = value;
}
];
in
resolved.optional
) definition.value
) definitions;
merged = builtins.concatLists result;
result = lib.lists.mapWithIndex1
(
i: definition:
lib.lists.mapWithIndex1
(
j: value:
let
resolved =
lib.options.merge.definitions (location ++ [ "[definition ${builtins.toString i}-entry ${j}]" ])
type
[
{
file = definition.file;
value = value;
}
];
in
resolved.optional
)
definition.value
)
definitions;
merged = lib.lists.flatten result;
filtered = builtins.filter (definition: definition ? value) merged;
values = lib.options.getDefinitionValues filtered;
in
@ -777,11 +792,11 @@ lib: {
##
## @type { modules :: List Module, args? :: Attrs, description? :: String | Null, shorthand? :: Bool } -> Attrs
of =
settings@{
modules,
args ? { },
description ? null,
shorthand ? true,
settings@{ modules
, args ? { }
, description ? null
, shorthand ? true
,
}:
let
getModules = builtins.map (
@ -790,9 +805,12 @@ lib: {
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" ];
rest = builtins.removeAttrs
(lib.attrs.filter
(
name: value: builtins.elem name lib.modules.VALID_KEYS
)
definition.value) [ "freeform" ];
in
if definition.value ? config then
rest
@ -922,10 +940,12 @@ lib: {
merge = location: definitions: {
includes =
modules
++ builtins.map (definition: {
__file__ = "${definition.__file__}; via ${lib.options.getIdentifier location}";
includes = [ definition.value ];
}) definitions;
++ builtins.map
(definition: {
__file__ = "${definition.__file__}; via ${lib.options.getIdentifier location}";
includes = [ definition.value ];
})
definitions;
};
getSubOptions = submodule.getSubOptions;
getSubModules = submodule.getSubModules;
@ -961,10 +981,12 @@ lib: {
location: definitions:
let
first = builtins.elemAt definitions 0;
modules = builtins.map (definition: {
__file__ = definition.__file__;
options = lib.options.create { type = definition.value; };
}) definitions;
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;
@ -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 = {
## Create a type that allows a DAG (Directed Acyclic Graph) of a given type.
##
@ -1160,10 +1219,12 @@ lib: {
merge =
location: definitions:
submodule.merge location (
builtins.map (definition: {
__file__ = definition.__file__;
value = normalize definition;
}) definitions
builtins.map
(definition: {
__file__ = definition.__file__;
value = normalize definition;
})
definitions
);
};
};

View file

@ -8,33 +8,35 @@
},
"locked": {
"dir": "foundation",
"dirtyRev": "9850da8aa9dc9be22e237c9b424a18e801e53ecb-dirty",
"dirtyShortRev": "9850da8-dirty",
"lastModified": 1718529861,
"narHash": "sha256-X1Wd6mDz8GTaoxt1ylkvZfrJOcZtspJrEjXMtJ2ZyG0=",
"lastModified": 1724190751,
"narHash": "sha256-e8sOmeXS9YWuQqjW6gvtS3PIueazkf4S1iiJ/94eXv4=",
"ref": "master",
"rev": "4b36a5a0133f5481840bdfaf693c971215a7ef1f",
"revCount": 84,
"type": "git",
"url": "file:../?dir=foundation"
"url": "file:../"
},
"original": {
"dir": "foundation",
"type": "git",
"url": "file:../?dir=foundation"
"url": "file:../"
}
},
"lib": {
"locked": {
"dir": "lib",
"dirtyRev": "9850da8aa9dc9be22e237c9b424a18e801e53ecb-dirty",
"dirtyShortRev": "9850da8-dirty",
"lastModified": 1718529861,
"narHash": "sha256-X1Wd6mDz8GTaoxt1ylkvZfrJOcZtspJrEjXMtJ2ZyG0=",
"lastModified": 1724190751,
"narHash": "sha256-e8sOmeXS9YWuQqjW6gvtS3PIueazkf4S1iiJ/94eXv4=",
"ref": "master",
"rev": "4b36a5a0133f5481840bdfaf693c971215a7ef1f",
"revCount": 84,
"type": "git",
"url": "file:../?dir=lib"
"url": "file:../"
},
"original": {
"dir": "lib",
"type": "git",
"url": "file:../?dir=lib"
"url": "file:../"
}
},
"root": {

View file

@ -1,10 +1,8 @@
{ lib, config }:
{ config }:
let
cfg = config.builders.basic;
lib' = config.lib;
inherit (config) foundation;
inherit (config) lib foundation;
in
{
config.builders = {
@ -14,15 +12,46 @@ in
build =
package:
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;
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 (
package.env
// {
@ -36,7 +65,15 @@ in
PATH =
let
bins = lib.paths.bin (
(lib'.packages.dependencies.getPackages package.deps.build.host)
(lib.packages.dependencies.get dependencies.build.only)
++ (lib.packages.dependencies.get dependencies.build.build)
++ (lib.packages.dependencies.get dependencies.build.host)
++ (lib.packages.dependencies.get dependencies.build.target)
++ (lib.packages.dependencies.get dependencies.host.only)
++ (lib.packages.dependencies.get dependencies.host.host)
++ (lib.packages.dependencies.get dependencies.host.target)
++ (lib.packages.dependencies.get dependencies.target.only)
++ (lib.packages.dependencies.get dependencies.target.target)
++ [
foundation.stage2-bash
foundation.stage2-coreutils
@ -70,7 +107,15 @@ in
}
);
in
built // { inherit (package) meta; };
# (builtins.trace "build: ${package.name} -> build=${package.platform.build.triple} host=${package.platform.host.triple} target=${package.platform.target.triple}")
built
// {
inherit (package) meta;
extras = {
inherit package context;
phases = builtins.listToAttrs sorted.result;
} // package.extras;
};
};
};
}

View file

@ -1,37 +1,39 @@
# This file handles creating all of the exports for this project and is not
# exported itself.
{ lib, config }:
{ config }:
let
lib' = config.lib;
inherit (config) lib;
in
{
freeform = lib.types.any;
# freeform = lib.types.any;
config = {
exports = {
lib = config.lib;
inherit lib;
modules = import ./modules.nix;
packages = {
# foundation-gcc-x86_64 =
# (config.packages.foundation.gcc.versions."13.2.0".extend (args: {
# config = {
# platform = {
# target = lib.modules.overrides.force "x86_64-linux";
# };
# };
# }))
# .config;
aux-a = config.packages.aux.a;
aux-b = config.packages.aux.b;
foundation-gcc = config.packages.foundation.gcc;
foundation-glibc = config.packages.foundation.glibc;
foundation-binutils = config.packages.foundation.binutils;
foundation-linux-headers = config.packages.foundation.linux-headers.versions.latest.extend {
platform.host = lib.modules.overrides.force "x86_64-linux";
foundation-linux-headers = config.packages.foundation.linux-headers;
cross-foundation-glibc-x86_64-linux = config.packages.cross.x86_64-linux.foundation.glibc;
cross-foundation-binutils-x86_64-linux = config.packages.cross.x86_64-linux.foundation.binutils;
cross-tool-foundation-gcc-newlib-x86_64-linux = config.packages.cross-tools.x86_64-linux.foundation.gcc-newlib;
cross-tool-foundation-gcc-x86_64-linux = config.packages.cross-tools.x86_64-linux.foundation.gcc-cross;
cross-foundation-gcc-x86_64-linux = config.packages.cross.x86_64-linux.foundation.gcc-bootstrap;
example-a = config.packages.foundation.gcc.versions.latest.extend {
platform = {
target = lib.modules.override 0 "x86_64-linux";
};
};
# example-x = config.packages.example.x;
# cross-example-x-x86_64-linux = config.packages.cross.x86_64-linux.example.x;
};
};
# exported.packages.i686-linux.cross-foundation-gcc-x86_64-linux = config.packages.cross.x86_64-linux.foundation.gcc.package;
};
}

View file

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

View file

@ -1,20 +1,272 @@
{
lib,
lib',
config,
}:
{ lib, config }:
let
lib' = config.lib;
in
{
config = {
lib.packages = {
dependencies = {
getPackages =
get =
dependencies:
let
available = builtins.filter (dependency: !(builtins.isNull dependency)) (
builtins.attrValues dependencies
);
exists = value: !(builtins.isNull value);
available = builtins.filter exists dependencies;
in
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 =
@ -25,54 +277,89 @@
in
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 =
package: build: host: target:
alias: build: host: target:
let
resolved =
if package ? versions then
package.versions.${config.preferences.packages.version}
or (package.versions.${lib'.packages.getLatest package})
else
package;
package = lib'.packages.resolve alias;
buildDependencies =
build': host': target':
builtins.mapAttrs (name: dep: lib'.packages.build dep build' host' target');
result = resolved.extend (
{ config }:
{
config = {
platform = {
build = build;
host = host;
target = lib.modules.override 150 target;
};
platform = {
build = lib.modules.overrides.force build;
host = lib.modules.overrides.force host;
target = lib.modules.overrides.force target;
};
deps = {
build = {
only = buildDependencies build build build resolved.deps.build.only;
build = buildDependencies build build target resolved.deps.build.build;
host = buildDependencies build host target resolved.deps.build.host;
target = buildDependencies build target target resolved.deps.build.target;
};
host = {
only = buildDependencies host host host resolved.deps.host.only;
host = buildDependencies host host target resolved.deps.host.host;
target = buildDependencies host target target resolved.deps.host.target;
};
target = {
only = buildDependencies target target target resolved.deps.target.only;
target = buildDependencies target target target resolved.deps.target.target;
};
};
withPlatform = lib.modules.run {
modules = package.__modules__ ++ [
lib'.types.package.children.submodule
(
{ config }:
{
config = {
__modules__ = package.__modules__;
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
result;
withPackage.config;
};
};
}

View file

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

View file

@ -1,8 +1,9 @@
{
lib,
lib',
config,
}:
{ lib, config }:
let
inherit (config) preferences builders;
lib' = config.lib;
in
{
config = {
lib.types = {
@ -55,6 +56,10 @@
in
lib.types.either type (lib.types.list.of type);
platform =
lib.types.coerce lib.types.string lib'.systems.withBuildInfo
lib'.systems.types.platformWithBuildInfo;
builder = lib.types.submodule {
freeform = lib.types.any;
@ -66,256 +71,397 @@
};
};
packages = lib.types.attrs.of (lib'.types.alias);
packages = lib.types.attrs.of (lib.types.attrs.of lib'.types.alias);
alias = lib.types.attrs.of (
lib.types.submodule {
options = {
versions = lib.options.create {
description = "All available package versions.";
type = lib.types.attrs.of lib'.types.package;
};
dependencies =
build: host: target:
let
initial = lib.types.raw;
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 (
lib.types.nullish (lib.types.either lib'.types.alias lib'.types.package)
);
latest = lib.options.create {
description = "The latest version of the package.";
type = lib'.types.package;
};
package = lib.types.submodule (
{ config, meta }:
{
options = {
extend = lib.options.create {
description = "Extend the package's submodules with additional configuration.";
type = lib.types.function lib.types.raw;
default.value =
value:
let
result = meta.extend {
modules = if builtins.isAttrs value then [ { config = value; } ] else lib.lists.from.any value;
versions = lib.options.create {
description = "Available versions of the package.";
type = lib.types.attrs.of lib'.types.package;
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; };
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 {
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 "";
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.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.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 = { };
};
};
};
};
pname = lib.options.create {
description = "The program name for the package";
type = lib.types.nullish lib.types.string;
default.value = null;
};
submodule =
{ config, meta }:
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 = [ ];
};
version = lib.options.create {
description = "The version for the package.";
type = lib.types.nullish lib.types.version;
default.value = null;
};
meta = {
description = lib.options.create {
description = "The description for the package.";
type = lib.types.nullish lib.types.string;
default.value = null;
};
homepage = lib.options.create {
description = "The homepage for the package.";
type = lib.types.nullish lib.types.string;
default.value = null;
};
license = lib.options.create {
description = "The license for the package.";
type = lib.types.nullish lib'.types.license;
default.value = null;
};
free = lib.options.create {
description = "Whether the package is free.";
type = lib.types.bool;
default.value = true;
};
insecure = lib.options.create {
description = "Whether the package is insecure.";
type = lib.types.bool;
default.value = false;
};
broken = lib.options.create {
description = "Whether the package is broken.";
type = lib.types.bool;
default.value = false;
};
main = lib.options.create {
description = "The main entry point for the package.";
type = lib.types.nullish lib.types.string;
default.value = null;
};
platforms = lib.options.create {
description = "The platforms the package supports.";
type = lib.types.list.of lib.types.string;
default.value = [ ];
};
};
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;
# 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;
# };
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;
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;
}];
# 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;
};
};
modules = config.__modules__ ++ normalized;
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 = { };
};
result = lib.modules.run {
modules = [
submodule
{ config.__modules__ = modules; }
] ++ modules;
};
in
result.config;
};
env = lib.options.create {
description = "The environment for the package.";
type = lib.types.attrs.of lib.types.string;
default.value = { };
};
meta = {
description = lib.options.create {
description = "The description for the package.";
type = lib.types.string;
default.value = "";
};
builder = lib.options.create {
description = "The builder for the package.";
type = lib'.types.builder;
};
homepage = lib.options.create {
description = "The homepage for the package.";
type = lib.types.nullish lib.types.string;
default.value = null;
};
deps = {
build = {
only = lib.options.create {
description = "Dependencies which are only used in the build environment.";
type = lib'.types.dependencies;
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 = { };
};
build = lib.options.create {
description = "Dependencies which are created in the build environment and are executed in the build environment.";
type = lib'.types.dependencies;
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 = { };
};
host = lib.options.create {
description = "Dependencies which are created in the build environment and are executed in the host environment.";
type = lib'.types.dependencies;
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 = { };
};
target = lib.options.create {
description = "Dependencies which are created in the build environment and are executed in the target environment.";
type = lib'.types.dependencies;
default.value = { };
};
};
host = {
only = lib.options.create {
description = "Dependencies which are only used in the host environment.";
type = lib'.types.dependencies;
context = lib.options.create {
description = "The context information that the package provides.";
type = lib.types.attrs.of lib.types.raw;
default.value = { };
};
host = lib.options.create {
description = "Dependencies which are executed in the host environment.";
type = lib'.types.dependencies;
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: { };
};
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 = { };
propagate = lib.options.create {
description = "Whether the package should propagate its hooks and context.";
type = lib.types.bool;
default.value = false;
};
target = lib.options.create {
description = "Dependencies which are executed in the target environment.";
type = lib'.types.dependencies;
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;
};
};
};
};
};
package = lib.options.create {
description = "The built derivation.";
type = lib.types.derivation;
default.value = config.builder.build config;
};
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 @@
{ 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,51 @@
{
lib,
lib',
config,
}:
{ config }:
let
doubles = lib'.systems.doubles.all;
inherit (config) lib;
packages = builtins.removeAttrs config.packages [ "cross" ];
doubles = lib.systems.doubles.all;
packages = builtins.removeAttrs config.packages [ "cross" "cross-tools" ];
in
{
includes = [ ./foundation ];
includes = [
./foundation
./aux/a.nix
./aux/b.nix
./aux/c.nix
];
options = {
packages = lib.options.create {
description = "The package set.";
type = lib.types.submodule {
freeform = lib.types.attrs.of (lib.types.submodule { freeform = lib'.types.alias; });
freeform = lib.types.packages;
options.cross = lib.attrs.generate doubles (
system:
lib.options.create {
description = "The cross-compiled package set for the ${system} target.";
type = lib'.types.packages;
default = { };
}
);
options = {
cross-tools = lib.attrs.generate doubles (
system:
lib.options.create {
description = "The cross-compilation tools for the ${system} target.";
type = lib.types.packages;
default.value = { };
}
);
cross = lib.attrs.generate doubles (
system:
lib.options.create {
description = "The cross-compiled package set for the ${system} target.";
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 +61,67 @@ in
};
};
config.packages.cross = lib.attrs.generate doubles (
system:
builtins.mapAttrs (
namespace:
builtins.mapAttrs (
name: alias:
let
setHost =
package:
if package != { } then
(package.extend (
{ config }:
{
config = {
platform = {
host = lib.modules.overrides.force system;
target = lib.modules.overrides.default system;
};
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 = {
packages.cross-tools = lib.attrs.generate doubles (
system:
builtins.mapAttrs
(
namespace:
builtins.mapAttrs (
name: alias:
let
setTarget =
package:
package
// {
__modules__ = package.__modules__ ++ [
{
config.platform = {
target = lib.modules.override 5 system;
};
}
];
};
}
)).config
else
package;
updated = alias // {
versions = builtins.mapAttrs (version: package: setHost package) alias.versions;
};
in
updated
)
) packages
);
updated = alias // {
versions = builtins.mapAttrs (version: package: setTarget package) alias.versions;
};
in
updated
)
)
packages
);
packages.cross = lib.attrs.generate doubles (
system:
builtins.mapAttrs
(
namespace:
builtins.mapAttrs (
name: alias:
let
setPlatform =
package:
package
// {
__modules__ = package.__modules__ ++ [
{
config.platform = {
host = lib.modules.override 5 system;
target = lib.modules.override 5 system;
};
}
];
};
updated = alias // {
versions = builtins.mapAttrs (version: package: setPlatform package) alias.versions;
};
in
updated
)
)
packages
);
};
}

View file

@ -1,8 +1,8 @@
{
lib,
lib',
config,
options,
{ lib
, lib'
, config
, options
,
}:
let
inherit (config)
@ -11,13 +11,14 @@ let
# These are the upstream foundational packages exported from the Aux Foundation project.
foundation
packages
;
in
{
config.packages.foundation.binutils = {
versions = {
"latest" =
{ config, meta }:
{ config }:
{
options = {
src = lib.options.create {
@ -26,93 +27,149 @@ in
};
};
config = {
meta = {
platforms = [ "i686-linux" ];
};
config =
let
isBuildBootstrapped = config.platform.build.double == "i686-linux";
isHostBootstrapped = config.platform.host.double == "i686-linux";
pname = "binutils";
version = "2.41";
isBootstrapped = isBuildBootstrapped && isHostBootstrapped;
builder = builders.basic;
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
];
};
phases =
let
patches = [
# Make binutils output deterministic by default.
./patches/deterministic.patch
isCross =
config.platform.build.double != config.platform.host.double
&& config.platform.host.double == config.platform.target.double;
in
{
meta = {
platforms = [
"i686-linux"
"x86_64-linux"
];
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}"
"--with-sysroot=/"
"--enable-deterministic-archives"
# depends on bison
"--disable-gprofng"
# 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"
# 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=:"
"--disable-multilib"
];
in
{
unpack = lib.dag.entry.before [ "patch" ] ''
tar xf ${config.src}
cd binutils-${config.version}
'';
patch = lib.dag.entry.between [ "configure" ] [ "unpack" ] ''
${lib.strings.concatMapSep "\n" (file: "patch -Np1 -i ${file}") patches}
'';
configure = lib.dag.entry.between [ "build" ] [ "patch" ] ''
bash ./configure ${builtins.concatStringsSep " " configureFlags}
'';
build = lib.dag.entry.between [ "install" ] [ "configure" ] ''
make -j $NIX_BUILD_CORES
'';
install = lib.dag.entry.after [ "build" ] ''
make -j $NIX_BUILD_CORES install-strip
'';
};
src = builtins.fetchurl {
url = "${mirrors.gnu}/binutils/binutils-${config.version}.tar.xz";
sha256 = "rppXieI0WeWWBuZxRyPy0//DHAMXQZHvDQFb3wYAdFA=";
pname = "binutils";
version = "2.41";
builder = builders.basic;
deps = {
build = {
only = {
gcc = lib.modules.when (!isBootstrapped) (
if isCross then
packages.foundation.gcc-cross.versions.latest.extend
{
platform = lib.modules.override 0 {
inherit (config.platform) build target;
host = config.platform.build;
};
}
else
packages.foundation.gcc.versions.latest
);
glibc = lib.modules.when (isCross) (
packages.foundation.glibc.versions.latest.extend {
platform = lib.modules.override 0 {
inherit (config.platform) host target build;
};
}
);
binutils = lib.modules.when (isCross) (
packages.foundation.binutils.versions.latest.extend {
platform = lib.modules.override 0 {
inherit (config.platform) target build;
host = config.platform.build;
};
}
);
};
};
};
env = {
PATH = lib.paths.bin (
lib.lists.when (isBootstrapped) [ foundation.stage2-gcc ]
++ [
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
]
);
} // (lib.attrs.when (isCross) {
LDFLAGS_FOR_TARGET = "-B${config.deps.build.only.glibc.package}/lib -L${config.deps.build.only.glibc.package}/lib -I${config.deps.build.only.glibc.package}/include";
});
phases =
let
patches = [
# Make binutils output deterministic by default.
./patches/deterministic.patch
];
configureFlags =
lib.lists.when (!isCross) [
"LDFLAGS=--static"
]
++ [
"--prefix=${builtins.placeholder "out"}"
"--build=${config.platform.build.triple}"
"--host=${config.platform.host.triple}"
"--target=${config.platform.target.triple}"
"--with-sysroot=/"
"--enable-deterministic-archives"
# depends on bison
"--disable-gprofng"
# 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"
# 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=:"
"--disable-multilib"
];
in
{
unpack = ''
tar xf ${config.src}
cd binutils-${config.version}
'';
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=";
};
};
};
};
};
};

View file

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

View file

@ -0,0 +1,84 @@
{ config, options }:
let
inherit (config)
lib
packages
;
in
{
config.packages.foundation.gcc-bootstrap = {
versions = {
"latest" = config.packages.foundation.gcc.versions.latest.extend
(
{ config }:
{
config = {
meta = {
platforms = lib.modules.override 0 [
"i686-linux"
];
};
deps = {
build = {
build = {
gcc = lib.modules.override 0 (
packages.foundation.gcc-cross.versions.latest.extend {
platform = lib.modules.override 0 {
build = "i686-linux";
target = config.platform.target;
host = "i686-linux";
};
}
);
binutils = lib.modules.override 0 (
packages.foundation.binutils.versions.latest.extend {
platform = lib.modules.override 0 {
build = "i686-linux";
target = config.platform.target;
host = config.platform.host;
};
}
);
glibc = lib.modules.override 0 (
packages.foundation.glibc.versions.latest.extend {
platform = lib.modules.override 0 {
build = "i686-linux";
target = config.platform.target;
host = config.platform.host;
};
}
);
};
};
};
env = {
LIBRARY_PATH = lib.modules.override 0 "${config.deps.build.build.glibc.package}/lib";
LDFLAGS_FOR_TARGET =
lib.modules.override 0
"-L$(pwd)/${config.platform.target.triple}/libgcc -L${config.deps.build.build.glibc.package}/lib";
};
configureFlags = lib.modules.override 0 [
"--prefix=${builtins.placeholder "out"}"
# Pretend we're native even though we're not
"--build=${config.platform.target.triple}"
"--host=${config.platform.host.triple}"
"--target=${config.platform.target.triple}"
"--with-as=${config.deps.build.build.binutils.package}/bin/as"
"--with-ld=${config.deps.build.build.binutils.package}/bin/ld"
"--enable-languages=c,c++"
"--disable-bootstrap"
"--disable-libsanitizer"
"--disable-multilib"
"--with-native-system-header-dir=${config.deps.build.build.glibc.package}/include"
"--with-gxx-include-dir=${placeholder "out"}/include/c++/${config.version}/"
"--with-build-sysroot=/"
];
};
}
);
};
};
}

View file

@ -0,0 +1,104 @@
{ config, options }:
let
inherit (config)
lib
foundation
packages
;
in
{
config.packages.foundation.gcc-cross = {
versions = {
"latest" = config.packages.foundation.gcc.versions.latest.extend
(
{ config }:
{
config =
let
programPrefix = lib.strings.when
(
config.platform.build.triple != config.platform.target.triple
) "${config.platform.target.triple}-";
in
{
meta = {
platforms = lib.modules.override 0 [
"i686-linux"
];
};
deps = {
build = {
build = {
binutils = (
packages.foundation.binutils.versions.latest.extend {
platform = lib.modules.override 0 config.platform;
}
);
glibc = (
packages.foundation.glibc.versions.latest.extend {
platform = lib.modules.override 0 {
inherit (config.platform) build target;
host = config.platform.target;
};
}
);
linux-headers = (
packages.foundation.linux-headers.versions.latest.extend {
platform.target = lib.modules.override 0 config.platform.target;
}
);
};
};
};
env = {
# LIBRARY_PATH = lib.modules.override 0 "${foundation.stage1-musl}/lib";
CC = lib.modules.override 0 "gcc -Wl,-dynamic-linker -Wl,${foundation.stage1-musl}/lib/libc.so -idirafter ${foundation.stage1-musl}/include";
CXX = lib.modules.override 0 "g++ -Wl,-dynamic-linker -Wl,${foundation.stage1-musl}/lib/libc.so -idirafter ${foundation.stage1-musl}/include";
CFLAGS_FOR_TARGET =
lib.modules.override 0
"-Wl,-dynamic-linker -Wl,${config.deps.build.build.glibc.package}/lib/ld-linux-x86-64.so.2 -B${config.deps.build.build.glibc.package}/lib";
LDFLAGS_FOR_TARGET =
lib.modules.override 0
"-L$(pwd)/${config.platform.target.triple}/libgcc -L${config.deps.build.build.glibc.package}/lib";
};
configureFlags = lib.modules.override 0 [
"--prefix=${builtins.placeholder "out"}"
"--build=${config.platform.build.triple}"
"--host=${config.platform.host.triple}"
"--target=${config.platform.target.triple}"
"--with-as=${config.deps.build.build.binutils.package}/bin/${programPrefix}as"
"--with-ld=${config.deps.build.build.binutils.package}/bin/${programPrefix}ld"
"--enable-languages=c,c++"
"--disable-libsanitizer"
"--disable-lto"
"--disable-multilib"
"--with-headers=${config.deps.build.build.glibc.package}/include"
"--with-build-sysroot=/"
# "--with-sysroot=${config.deps.build.build.glibc.package}"
"--with-native-system-header-dir=${config.deps.build.build.glibc.package}/include"
];
phases.configure = lib.modules.override 0 ''
# Configure
mkdir build
cd build
echo PATH=$PATH
# TODO(vlinkz) Hack to fix missing crti.o and crtn.o. Figure out how to properly find their paths.
mkdir gcc
ln -sv ${config.deps.build.build.glibc.package}/lib/{crti.o,crtn.o} gcc
mkdir -p x86_64-unknown-linux-gnu/libstdc++-v3/src
ln -sv ${config.deps.build.build.glibc.package}/lib/{crti.o,crtn.o} x86_64-unknown-linux-gnu/libstdc++-v3/src
bash ../configure ${builtins.concatStringsSep " " config.configureFlags}
'';
};
}
);
};
};
}

View file

@ -1,19 +1,22 @@
{
lib,
lib',
config,
options,
}:
{ config, options }:
let
inherit (config)
lib
mirrors
builders
# These are the upstream foundational packages exported from the Aux Foundation project.
foundation
packages
;
in
{
includes = [
./newlib.nix
./cross.nix
./bootstrap.nix
];
config.packages.foundation.gcc = {
versions = {
"latest" =
@ -78,158 +81,239 @@ in
description = "Version of isl.";
};
};
};
config = {
meta = {
platforms = [ "i686-linux" ];
configureFlags = lib.options.create {
type = lib.types.list.of lib.types.string;
description = "Flags to pass to the configure script.";
};
pname = "gcc";
version = "13.2.0";
exports = lib.options.create {
type = lib.types.attrs.of lib.types.string;
description = "List of exports to add to the environment.";
};
};
builder = builders.basic;
config =
let
isBuildBootstrapped = config.platform.build.double == "i686-linux";
isHostBootstrapped = config.platform.host.double == "i686-linux";
env = {
PATH =
let
gcc =
if
config.platform.build.triple == config.platform.host.triple
# If we're on the same system then we can use the existing GCC instance.
then
foundation.stage2-gcc
# Otherwise we are going to need a cross-compiler.
else
# TODO: Create a gcc-cross package.
(meta.extend (args: {
config = {
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
isBootstrapped = isBuildBootstrapped && isHostBootstrapped;
crossTool =
(config.platform.target.triple != config.platform.host.triple)
&& (config.platform.host.triple == config.platform.build.triple);
cross =
(config.platform.target.triple != config.platform.host.triple)
&& (config.platform.host.triple == config.platform.target.triple);
programPrefix = lib.strings.when
(
config.platform.build.triple != config.platform.target.triple
) "${config.platform.target.triple}-";
libc = if isBootstrapped then foundation.stage1-musl else config.deps.build.build.glibc.package;
libcLd =
if isBootstrapped then
"${foundation.stage1-musl}/lib/libc.so"
else
"${config.deps.build.build.glibc.package}/lib/ld-linux-x86-64.so.2";
host = lib.systems.withBuildInfo config.platform.host;
target = lib.systems.withBuildInfo config.platform.target;
in
{
meta = {
platforms = [
"i686-linux"
];
};
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 = lib.dag.entry.before [ "patch" ] ''
# 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 = lib.dag.entry.between [ "configure" ] [ "unpack" ] ''
# Patch
# force musl even if host triple is gnu
sed -i 's|"os/gnu-linux"|"os/generic"|' libstdc++-v3/configure.host
'';
configure = lib.dag.entry.between [ "build" ] [ "patch" ] ''
# Configure
export CC="gcc -Wl,-dynamic-linker -march=${
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 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 = lib.dag.entry.between [ "install" ] [ "configure" ] ''
# Build
make -j $NIX_BUILD_CORES
'';
install = lib.dag.entry.after [ "build" ] ''
# 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=";
};
pname = "gcc-${config.platform.build.double}--${config.platform.host.double}--${config.platform.target.double}";
version = "13.2.0";
builder = builders.basic;
deps = {
build = {
build = lib.modules.when (!isBootstrapped) {
gcc = packages.foundation.gcc-cross.versions.latest;
glibc = packages.foundation.glibc.versions.latest;
linux-headers = packages.foundation.linux-headers.versions.latest;
binutils = packages.foundation.binutils.versions.latest;
};
};
};
env =
{
PATH = lib.modules.when (isBuildBootstrapped) (
lib.paths.bin ([
foundation.stage2-gnumake
foundation.stage2-gnused
foundation.stage2-gnugrep
foundation.stage2-gnupatch
foundation.stage2-gawk
foundation.stage2-diffutils
foundation.stage2-findutils
foundation.stage2-gnutar
foundation.stage2-gzip
foundation.stage2-bzip2
foundation.stage1-xz
] ++ (lib.lists.when (isBootstrapped) [
foundation.stage2-gcc
foundation.stage2-binutils
]))
);
CFLAGS_FOR_TARGET = "-Wl,-dynamic-linker -Wl,${libcLd}";
}
// lib.attrs.when (isBootstrapped) {
CC = "gcc -Wl,-dynamic-linker -Wl,${foundation.stage1-musl}/lib/libc.so";
CXX = "g++ -Wl,-dynamic-linker -Wl,${foundation.stage1-musl}/lib/libc.so";
}
// lib.attrs.when (!cross && !crossTool) {
LIBRARY_PATH = "${libc}/lib";
};
hooks =
let
flags =
if (isBootstrapped && !(cross || crossTool)) then
[
"-Wl,-dynamic-linker"
"-Wl,${foundation.stage1-musl}/lib/libc.so"
]
else
[
"-Wl,-dynamic-linker"
"-Wl,${config.deps.build.build.glibc.package}/lib/ld-linux${lib.strings.when (target.isx86 && target.is64bit) "-x86-64"}.so.2"
"-B${config.deps.build.build.glibc.package}/lib"
# "-idirafter ${config.deps.build.build.glibc.package}/include"
];
in
ctx: {
"aux:gcc:env" = lib.dag.entry.between [ "unpack" ] [ "configure" ] ''
export CC='${config.package}/bin/${programPrefix}gcc ${builtins.concatStringsSep " " flags}'
export CXX='${config.package}/bin/${programPrefix}g++ ${builtins.concatStringsSep " " flags}'
export CC_FOR_TARGET=$CC
export CXX_FOR_TARGET=$CXX
export CC_FOR_BUILD=$CC
export CXX_FOR_BUILD=$CXX
alias gcc='$CC'
alias g++='$CXX'
'';
};
configureFlags =
[
"--prefix=${builtins.placeholder "out"}"
"--build=${config.platform.build.triple}"
"--host=${config.platform.host.triple}"
"--target=${config.platform.target.triple}"
"--enable-languages=c,c++"
"--disable-bootstrap"
"--disable-libsanitizer"
"--disable-multilib"
"--with-build-sysroot=/"
"--with-native-system-header-dir=${libc}/include"
]
++ lib.lists.when (isBootstrapped) [
"--disable-lto"
];
phases =
let
patches = [
# Make binutils output deterministic by default.
./patches/libstdc++-target.patch
];
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 = ''
${lib.strings.concatMapSep "\n" (file: "patch -Np1 -i ${file}") patches}
${lib.strings.when (isBootstrapped && !(crossTool || cross))''
# force musl even if host triple is gnu
sed -i 's|"os/gnu-linux"|"os/generic"|' libstdc++-v3/configure.host
''}
'';
configure = ''
# Configure
mkdir build
cd build
bash ../configure ${builtins.concatStringsSep " " config.configureFlags}
'';
build = ''
# Build
make -j $NIX_BUILD_CORES
'';
install = ''
# Install
${
lib.strings.when (host.is64bit) ''
mkdir -p $out/lib
ln -s lib $out/lib64
''
}
make -j $NIX_BUILD_CORES install
'';
};
gmp = {
version = "6.3.0";
src = builtins.fetchurl {
url = "${mirrors.gnu}/gmp/gmp-${config.gmp.version}.tar.xz";
sha256 = "o8K4AgG4nmhhb0rTC8Zq7kknw85Q4zkpyoGdXENTiJg=";
url = "${mirrors.gnu}/gcc/gcc-${config.version}/gcc-${config.version}.tar.xz";
sha256 = "4nXnZEKmBnNBon8Exca4PYYTFEAEwEE1KIY9xrXHQ9o=";
};
};
mpfr = {
version = "4.2.1";
src = builtins.fetchurl {
url = "${mirrors.gnu}/mpfr/mpfr-${config.mpfr.version}.tar.xz";
sha256 = "J3gHNTpnJpeJlpRa8T5Sgp46vXqaW3+yeTiU4Y8fy7I=";
gmp = {
version = "6.3.0";
src = builtins.fetchurl {
url = "${mirrors.gnu}/gmp/gmp-${config.gmp.version}.tar.xz";
sha256 = "o8K4AgG4nmhhb0rTC8Zq7kknw85Q4zkpyoGdXENTiJg=";
};
};
};
mpc = {
version = "1.3.1";
src = builtins.fetchurl {
url = "${mirrors.gnu}/mpc/mpc-${config.mpc.version}.tar.gz";
sha256 = "q2QkkvXPiCt0qgy3MM1BCoHtzb7IlRg86TDnBsHHWbg=";
mpfr = {
version = "4.2.1";
src = builtins.fetchurl {
url = "${mirrors.gnu}/mpfr/mpfr-${config.mpfr.version}.tar.xz";
sha256 = "J3gHNTpnJpeJlpRa8T5Sgp46vXqaW3+yeTiU4Y8fy7I=";
};
};
};
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=";
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=";
};
};
};
};
};
};
};

View file

@ -0,0 +1,71 @@
{ config, options }:
let
inherit (config)
lib
packages
;
in
{
config.packages.foundation.gcc-newlib = {
versions = {
"latest" = config.packages.foundation.gcc.versions.latest.extend (
{ config }:
{
config =
let
programPrefix = lib.strings.when
(
config.platform.build.triple != config.platform.target.triple
) "${config.platform.target.triple}-";
in
{
meta = {
platforms = lib.modules.override 0 [
"i686-linux"
];
};
deps = {
build = {
build = {
binutils = (
packages.foundation.binutils.versions.latest.extend {
platform = lib.modules.override 0 config.platform;
}
);
};
};
};
configureFlags = lib.modules.override 0 [
"--prefix=${builtins.placeholder "out"}"
"--build=${config.platform.build.triple}"
"--host=${config.platform.host.triple}"
"--target=${config.platform.target.triple}"
"--with-as=${config.deps.build.build.binutils.package}/bin/${programPrefix}as"
"--with-ld=${config.deps.build.build.binutils.package}/bin/${programPrefix}ld"
"--enable-languages=c,c++"
"--disable-bootstrap"
"--disable-libsanitizer"
"--disable-lto"
"--disable-multilib"
"--disable-plugin"
"--disable-libssp"
"--disable-libvtv"
"--disable-libstdcxx"
"--disable-libquadmath"
"--disable-threads"
"--disable-decimal-float"
"--disable-shared"
"--disable-libmudflap"
"--disable-libgomp"
"--disable-libatomic"
"--without-headers"
"--with-newlib"
];
};
}
);
};
};
}

View file

@ -0,0 +1,33 @@
# From https://github.com/NixOS/nixpkgs/blob/nixos-24.05/pkgs/development/compilers/gcc/patches/libstdc%2B%2B-target.patch
Patch to make the target libraries 'configure' scripts find the proper CPP.
I noticed that building the mingw32 cross compiler.
Looking at the build script for mingw in archlinux, I think that only nixos
needs this patch. I don't know why.
diff --git a/Makefile.in b/Makefile.in
index 93f66b6..d691917 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -266,6 +266,7 @@ BASE_TARGET_EXPORTS = \
AR="$(AR_FOR_TARGET)"; export AR; \
AS="$(COMPILER_AS_FOR_TARGET)"; export AS; \
CC="$(CC_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export CC; \
+ CPP="$(CC_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS -E"; export CC; \
CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \
CONFIG_SHELL="$(SHELL)"; export CONFIG_SHELL; \
CPPFLAGS="$(CPPFLAGS_FOR_TARGET)"; export CPPFLAGS; \
@@ -291,11 +292,13 @@ BASE_TARGET_EXPORTS = \
RAW_CXX_TARGET_EXPORTS = \
$(BASE_TARGET_EXPORTS) \
CXX_FOR_TARGET="$(RAW_CXX_FOR_TARGET)"; export CXX_FOR_TARGET; \
- CXX="$(RAW_CXX_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export CXX;
+ CXX="$(RAW_CXX_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export CXX; \
+ CXXCPP="$(RAW_CXX_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS -E"; export CXX;
NORMAL_TARGET_EXPORTS = \
$(BASE_TARGET_EXPORTS) \
- CXX="$(CXX_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export CXX;
+ CXX="$(CXX_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export CXX; \
+ CXXCPP="$(CXX_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS -E"; export CXX;
# Where to find GMP
HOST_GMPLIBS = @gmplibs@

View file

@ -3,6 +3,7 @@
lib',
config,
options,
packages,
}:
let
inherit (config)
@ -10,6 +11,7 @@ let
builders
# These are the upstream foundational packages exported from the Aux Foundation project.
packages
foundation
;
in
@ -26,87 +28,124 @@ in
};
};
config = {
meta = {
platforms = [ "i686-linux" ];
};
config =
let
isCross =
(config.platform.build.triple != config.platform.host.triple)
&& (config.platform.host.triple == config.platform.target.triple);
pname = "gcc";
version = "2.38";
binutils =
if isCross then
"${
(packages.foundation.binutils.versions.latest.extend {
platform = lib.modules.override 0 {
inherit (config.platform) build target;
host = config.platform.build;
};
}).package
}/${config.platform.target.triple}"
else
foundation.stage2-binutils;
in
{
src = builtins.fetchurl {
url = "${mirrors.gnu}/libc/glibc-${config.version}.tar.xz";
sha256 = "+4KZiZiyspllRnvBtp0VLpwwfSzzAcnq+0VVt3DvP9I=";
};
builder = builders.basic;
env = {
PATH =
let
gcc =
if
config.platform.build.triple == config.platform.host.triple
# If we're on the same system then we can use the existing GCC instance.
then
foundation.stage2-gcc
# Otherwise we are going to need a cross-compiler.
else
(meta.extend (args: {
config = {
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
meta = {
platforms = [
"i686-linux"
"x86_64-linux"
];
};
pname = "glibc";
version = "2.38";
src = builtins.fetchurl {
url = "${mirrors.gnu}/libc/glibc-${config.version}.tar.xz";
sha256 = "+4KZiZiyspllRnvBtp0VLpwwfSzzAcnq+0VVt3DvP9I=";
};
builder = builders.basic;
deps = {
build = {
host = {
linux-headers = (
packages.foundation.linux-headers.versions.latest.extend {
platform.target = lib.modules.override 0 config.platform.target;
}
);
};
};
};
env = {
PATH =
let
gcc =
if
isCross
# Otherwise we are going to need a cross-compiler.
then
(packages.foundation.gcc-newlib.versions.latest.extend {
platform = lib.modules.override 0 {
inherit (config.platform) build target;
host = config.platform.build;
};
}).package
# If we're on the same system then we can use the existing GCC instance.
else
foundation.stage2-gcc;
in
lib.paths.bin [
gcc
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-python
foundation.stage1-bison
foundation.stage1-xz
];
};
phases =
{
unpack = ''
tar xf ${config.src}
cd glibc-${config.version}
'';
configure = ''
mkdir build
cd build
bash ../configure \
--prefix=$out \
--build=${config.platform.build.triple} \
--host=${config.platform.host.triple} \
--with-headers=${config.deps.build.host.linux-headers.package}/include \
--with-binutils=${binutils}/bin
'';
build = ''
# Build
make -j $NIX_BUILD_CORES
'';
install = ''
# Install
make -j $NIX_BUILD_CORES install
ln -sv $(ls -d ${config.deps.build.host.linux-headers.package}/include/* | grep -v scsi\$) $out/include/
'';
};
};
phases = {
unpack = lib.dag.entry.before [ "patch" ] ''
tar xf ${config.src}
cd glibc-${config.version}
'';
configure = lib.dag.entry.between [ "build" ] [ "patch" ] ''
mkdir build
cd build
# libstdc++.so is built against musl and fails to link
export CXX=false
bash ../configure \
--prefix=$out \
--build=${config.platform.build.triple} \
--host=${config.platform.host.triple} \
--with-headers=${foundation.stage1-linux-headers}/include
'';
build = lib.dag.entry.between [ "install" ] [ "configure" ] ''
# Build
make -j $NIX_BUILD_CORES
'';
install = lib.dag.entry.after [ "build" ] ''
# Install
make -j $NIX_BUILD_CORES install-strip
'';
};
};
};
};
};

View file

@ -1,8 +1,8 @@
{
lib,
lib',
config,
options,
{ lib
, lib'
, config
, options
,
}:
let
inherit (config)
@ -28,7 +28,7 @@ in
config = {
meta = {
platforms = [ "i686-linux" ];
platforms = [ "x86_64-linux" "i686-linux" ];
};
pname = "linux-headers";
@ -54,20 +54,16 @@ in
};
phases = {
unpack = lib.dag.entry.before [ "patch" ] ''
unpack = ''
tar xf ${config.src}
cd linux-${config.version}
'';
patch = lib.dag.entry.between [ "configure" ] [ "unpack" ] '''';
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
build = ''
make -j $NIX_BUILD_CORES CC=musl-gcc HOSTCC=musl-gcc ARCH=${config.platform.target.linux.arch} headers
'';
install = lib.dag.entry.after [ "build" ] ''
install = ''
find usr/include -name '.*' -exec rm {} +
mkdir -p $out
cp -rv usr/include $out/