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.
This commit is contained in:
parent
eae1f31968
commit
3c21a5c9d6
@ -6,9 +6,9 @@ let
|
||||
filterAttrs
|
||||
foldl
|
||||
hasInfix
|
||||
isAttrs
|
||||
isFunction
|
||||
isList
|
||||
isString
|
||||
mapAttrs
|
||||
optional
|
||||
optionalAttrs
|
||||
@ -55,24 +55,34 @@ let
|
||||
*/
|
||||
flakeExposed = import ./flake-systems.nix { };
|
||||
|
||||
# Turn localSystem or crossSystem, which could be system-string or attrset, into
|
||||
# attrset.
|
||||
systemToAttrs = systemOrArgs:
|
||||
if isAttrs systemOrArgs then systemOrArgs else { system = systemOrArgs; };
|
||||
|
||||
# Elaborate a `localSystem` or `crossSystem` so that it contains everything
|
||||
# necessary.
|
||||
#
|
||||
# `parsed` is inferred from args, both because there are two options with one
|
||||
# clearly preferred, and to prevent cycles. A simpler fixed point where the RHS
|
||||
# always just used `final.*` would fail on both counts.
|
||||
elaborate = args': let
|
||||
args = if isString args' then { system = args'; }
|
||||
else args';
|
||||
elaborate = systemOrArgs: let
|
||||
allArgs = systemToAttrs systemOrArgs;
|
||||
|
||||
# Those two will always be derived from "config", if given, so they should NOT
|
||||
# be overridden further down with "// args".
|
||||
args = builtins.removeAttrs allArgs [ "parsed" "system" ];
|
||||
|
||||
# TODO: deprecate args.rustc in favour of args.rust after 23.05 is EOL.
|
||||
rust = args.rust or args.rustc or {};
|
||||
|
||||
final = {
|
||||
# Prefer to parse `config` as it is strictly more informative.
|
||||
parsed = parse.mkSystemFromString (if args ? config then args.config else args.system);
|
||||
# Either of these can be losslessly-extracted from `parsed` iff parsing succeeds.
|
||||
parsed = parse.mkSystemFromString (args.config or allArgs.system);
|
||||
# This can be losslessly-extracted from `parsed` iff parsing succeeds.
|
||||
system = parse.doubleFromSystem final.parsed;
|
||||
# TODO: This currently can't be losslessly-extracted from `parsed`, for example
|
||||
# because of -mingw32.
|
||||
config = parse.tripleFromSystem final.parsed;
|
||||
# Determine whether we can execute binaries built for the provided platform.
|
||||
canExecute = platform:
|
||||
@ -435,5 +445,6 @@ in
|
||||
inspect
|
||||
parse
|
||||
platforms
|
||||
systemToAttrs
|
||||
;
|
||||
}
|
||||
|
@ -78,6 +78,18 @@ lib.runTests (
|
||||
expr = toLosslessStringMaybe (lib.systems.elaborate "x86_64-linux" // { something = "extra"; });
|
||||
expected = null;
|
||||
};
|
||||
test_elaborate_config_over_system = {
|
||||
expr = (lib.systems.elaborate { config = "i686-unknown-linux-gnu"; system = "x86_64-linux"; }).system;
|
||||
expected = "i686-linux";
|
||||
};
|
||||
test_elaborate_config_over_parsed = {
|
||||
expr = (lib.systems.elaborate { config = "i686-unknown-linux-gnu"; parsed = (lib.systems.elaborate "x86_64-linux").parsed; }).parsed.cpu.arch;
|
||||
expected = "i686";
|
||||
};
|
||||
test_elaborate_system_over_parsed = {
|
||||
expr = (lib.systems.elaborate { system = "i686-linux"; parsed = (lib.systems.elaborate "x86_64-linux").parsed; }).parsed.cpu.arch;
|
||||
expected = "i686";
|
||||
};
|
||||
}
|
||||
|
||||
# Generate test cases to assert that a change in any non-function attribute makes a platform unequal
|
||||
|
@ -246,7 +246,7 @@ let
|
||||
})] ++ overlays;
|
||||
${if stdenv.hostPlatform == stdenv.buildPlatform
|
||||
then "localSystem" else "crossSystem"} = {
|
||||
parsed = makeMuslParsedPlatform stdenv.hostPlatform.parsed;
|
||||
config = lib.systems.parse.tripleFromSystem (makeMuslParsedPlatform stdenv.hostPlatform.parsed);
|
||||
};
|
||||
} else throw "Musl libc only supports 64-bit Linux systems.";
|
||||
|
||||
@ -258,9 +258,9 @@ let
|
||||
})] ++ overlays;
|
||||
${if stdenv.hostPlatform == stdenv.buildPlatform
|
||||
then "localSystem" else "crossSystem"} = {
|
||||
parsed = stdenv.hostPlatform.parsed // {
|
||||
config = lib.systems.parse.tripleFromSystem (stdenv.hostPlatform.parsed // {
|
||||
cpu = lib.systems.parse.cpuTypes.i686;
|
||||
};
|
||||
});
|
||||
};
|
||||
} else throw "i686 Linux package set can only be used with the x86 family.";
|
||||
|
||||
@ -270,9 +270,9 @@ let
|
||||
pkgsx86_64Darwin = super';
|
||||
})] ++ overlays;
|
||||
localSystem = {
|
||||
parsed = stdenv.hostPlatform.parsed // {
|
||||
config = lib.systems.parse.tripleFromSystem (stdenv.hostPlatform.parsed // {
|
||||
cpu = lib.systems.parse.cpuTypes.x86_64;
|
||||
};
|
||||
});
|
||||
};
|
||||
} else throw "x86_64 Darwin package set can only be used on Darwin systems.";
|
||||
|
||||
@ -311,10 +311,11 @@ let
|
||||
})] ++ overlays;
|
||||
crossSystem = {
|
||||
isStatic = true;
|
||||
parsed =
|
||||
config = lib.systems.parse.tripleFromSystem (
|
||||
if stdenv.hostPlatform.isLinux
|
||||
then makeMuslParsedPlatform stdenv.hostPlatform.parsed
|
||||
else stdenv.hostPlatform.parsed;
|
||||
else stdenv.hostPlatform.parsed
|
||||
);
|
||||
gcc = lib.optionalAttrs (stdenv.hostPlatform.system == "powerpc64-linux") { abi = "elfv2"; } //
|
||||
stdenv.hostPlatform.gcc or {};
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user