Skip to content

Commit 3c21a5c

Browse files
lib/systems: elaborate properly with non-matching system / config / parsed args
When elaborating a system with both "config" and "system" arguments given, they might not match the parsed results. Example: elaborate { config = "i686-unknown-linux-gnu"; system = "x86_64-linux"; } This would result in a parsed system for i686, because the config argument is preferred. But since "// args //" comes after system has been inferred from parsed, it is overwritten again. This results in config and parsed all pointing to i686, while system still tells the story of x86_64. Inconsistent arguments can also be given when passing "parsed" directly. This happened in stage.nix for the various package sets. The solution is simple: One of the three arguments needs to be treated as the ultimate source of truth. "system" can already be losslessly extracted from "parsed". However, "config" currently can not, for example for various -mingw32 cases. Thus everything must be derived from "config". To do so, "system" and "parsed" arguments are made non-overrideable for systems.elaborate. This means, that "system" will be used to parse when "config" is not given - and "parsed" will be ignored entirely. The systemToAttrs helper is exposed on lib.systems, because it's useful to deal with top-level localSystem / crossSystem arguments elsewhere.
1 parent eae1f31 commit 3c21a5c

File tree

3 files changed

+37
-13
lines changed

3 files changed

+37
-13
lines changed

lib/systems/default.nix

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ let
66
filterAttrs
77
foldl
88
hasInfix
9+
isAttrs
910
isFunction
1011
isList
11-
isString
1212
mapAttrs
1313
optional
1414
optionalAttrs
@@ -55,24 +55,34 @@ let
5555
*/
5656
flakeExposed = import ./flake-systems.nix { };
5757

58+
# Turn localSystem or crossSystem, which could be system-string or attrset, into
59+
# attrset.
60+
systemToAttrs = systemOrArgs:
61+
if isAttrs systemOrArgs then systemOrArgs else { system = systemOrArgs; };
62+
5863
# Elaborate a `localSystem` or `crossSystem` so that it contains everything
5964
# necessary.
6065
#
6166
# `parsed` is inferred from args, both because there are two options with one
6267
# clearly preferred, and to prevent cycles. A simpler fixed point where the RHS
6368
# always just used `final.*` would fail on both counts.
64-
elaborate = args': let
65-
args = if isString args' then { system = args'; }
66-
else args';
69+
elaborate = systemOrArgs: let
70+
allArgs = systemToAttrs systemOrArgs;
71+
72+
# Those two will always be derived from "config", if given, so they should NOT
73+
# be overridden further down with "// args".
74+
args = builtins.removeAttrs allArgs [ "parsed" "system" ];
6775

6876
# TODO: deprecate args.rustc in favour of args.rust after 23.05 is EOL.
6977
rust = args.rust or args.rustc or {};
7078

7179
final = {
7280
# Prefer to parse `config` as it is strictly more informative.
73-
parsed = parse.mkSystemFromString (if args ? config then args.config else args.system);
74-
# Either of these can be losslessly-extracted from `parsed` iff parsing succeeds.
81+
parsed = parse.mkSystemFromString (args.config or allArgs.system);
82+
# This can be losslessly-extracted from `parsed` iff parsing succeeds.
7583
system = parse.doubleFromSystem final.parsed;
84+
# TODO: This currently can't be losslessly-extracted from `parsed`, for example
85+
# because of -mingw32.
7686
config = parse.tripleFromSystem final.parsed;
7787
# Determine whether we can execute binaries built for the provided platform.
7888
canExecute = platform:
@@ -435,5 +445,6 @@ in
435445
inspect
436446
parse
437447
platforms
448+
systemToAttrs
438449
;
439450
}

lib/tests/systems.nix

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,18 @@ lib.runTests (
7878
expr = toLosslessStringMaybe (lib.systems.elaborate "x86_64-linux" // { something = "extra"; });
7979
expected = null;
8080
};
81+
test_elaborate_config_over_system = {
82+
expr = (lib.systems.elaborate { config = "i686-unknown-linux-gnu"; system = "x86_64-linux"; }).system;
83+
expected = "i686-linux";
84+
};
85+
test_elaborate_config_over_parsed = {
86+
expr = (lib.systems.elaborate { config = "i686-unknown-linux-gnu"; parsed = (lib.systems.elaborate "x86_64-linux").parsed; }).parsed.cpu.arch;
87+
expected = "i686";
88+
};
89+
test_elaborate_system_over_parsed = {
90+
expr = (lib.systems.elaborate { system = "i686-linux"; parsed = (lib.systems.elaborate "x86_64-linux").parsed; }).parsed.cpu.arch;
91+
expected = "i686";
92+
};
8193
}
8294

8395
# Generate test cases to assert that a change in any non-function attribute makes a platform unequal

pkgs/top-level/stage.nix

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ let
246246
})] ++ overlays;
247247
${if stdenv.hostPlatform == stdenv.buildPlatform
248248
then "localSystem" else "crossSystem"} = {
249-
parsed = makeMuslParsedPlatform stdenv.hostPlatform.parsed;
249+
config = lib.systems.parse.tripleFromSystem (makeMuslParsedPlatform stdenv.hostPlatform.parsed);
250250
};
251251
} else throw "Musl libc only supports 64-bit Linux systems.";
252252

@@ -258,9 +258,9 @@ let
258258
})] ++ overlays;
259259
${if stdenv.hostPlatform == stdenv.buildPlatform
260260
then "localSystem" else "crossSystem"} = {
261-
parsed = stdenv.hostPlatform.parsed // {
261+
config = lib.systems.parse.tripleFromSystem (stdenv.hostPlatform.parsed // {
262262
cpu = lib.systems.parse.cpuTypes.i686;
263-
};
263+
});
264264
};
265265
} else throw "i686 Linux package set can only be used with the x86 family.";
266266

@@ -270,9 +270,9 @@ let
270270
pkgsx86_64Darwin = super';
271271
})] ++ overlays;
272272
localSystem = {
273-
parsed = stdenv.hostPlatform.parsed // {
273+
config = lib.systems.parse.tripleFromSystem (stdenv.hostPlatform.parsed // {
274274
cpu = lib.systems.parse.cpuTypes.x86_64;
275-
};
275+
});
276276
};
277277
} else throw "x86_64 Darwin package set can only be used on Darwin systems.";
278278

@@ -311,10 +311,11 @@ let
311311
})] ++ overlays;
312312
crossSystem = {
313313
isStatic = true;
314-
parsed =
314+
config = lib.systems.parse.tripleFromSystem (
315315
if stdenv.hostPlatform.isLinux
316316
then makeMuslParsedPlatform stdenv.hostPlatform.parsed
317-
else stdenv.hostPlatform.parsed;
317+
else stdenv.hostPlatform.parsed
318+
);
318319
gcc = lib.optionalAttrs (stdenv.hostPlatform.system == "powerpc64-linux") { abi = "elfv2"; } //
319320
stdenv.hostPlatform.gcc or {};
320321
};

0 commit comments

Comments
 (0)