Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib/systems: elaborate properly with non-matching system / config / parsed args #351608

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions lib/systems/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ let
filterAttrs
foldl
hasInfix
isAttrs
isFunction
isList
isString
mapAttrs
optional
optionalAttrs
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -435,5 +445,6 @@ in
inspect
parse
platforms
systemToAttrs
;
}
12 changes: 12 additions & 0 deletions lib/tests/systems.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 8 additions & 7 deletions pkgs/top-level/stage.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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.";

Expand All @@ -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.";

Expand All @@ -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.";

Expand Down Expand Up @@ -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 {};
};
Expand Down