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/tests/triples.nix: add test suite and fix our parser so it passes #235230

Closed
wants to merge 33 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
d43029c
lib/systems: replicate cygwin/msvc parsing hack when unparsing
May 31, 2023
9a2c5b1
lib/systems: factor tripleFromSkeleton out of tripleFromSystem
Jun 20, 2023
89007a7
lib/systems: rename vendors.none -> vendors.""
Jun 20, 2023
c03ef39
lib/systems: introduce tripleFromSystemLossy
Jun 20, 2023
bda7ba8
lib/systems: accomodate nonstandard `vc4-elf` triple
Jun 19, 2023
26c22f7
lib/systems: handle Solaris properly
Jun 19, 2023
7c77d76
lib/systems: add TODO regarding execFormats
Jun 19, 2023
b14dc66
lib/systems: add and check valid kernels for each abi
Jun 19, 2023
109454a
lib/systems: move powerpc64-be ABI-defaulting out of the parser
Jun 20, 2023
637cc8a
lib/systems: default arm-apple-linux to -gnu ABI
Jun 20, 2023
9413a2c
lib/systems: add vendors.{ibm,xilinx}
Jun 20, 2023
dc332ea
lib/systems: omit optExecFormat from triples
Jun 20, 2023
a3cf669
lib/systems: fix abi inference for aarch32-linux
Jun 20, 2023
eee685f
lib/systems: fix vendor fallback logic
Jun 20, 2023
2a244cd
lib/tests/triples.nix: add gnu-config conformance test suite
Jun 19, 2023
19d9620
lib/systems: add vendors.solo5
Jun 20, 2023
b414cc9
lib/systems: add kernels."", distinct from kernels.none
Jun 20, 2023
b8da7cd
implement formatting suggestion from @RaitoBezarius
Jun 28, 2023
0e3ad85
lib.systems: clean up abi defaulting
Aug 19, 2023
494246c
lib.systems: allow *-none-elf
Aug 19, 2023
8583581
lib.systems.parse: rename abis.unknown to abis.""
Aug 19, 2023
30d295f
lib.systems.parse: abis.gnu: allow kernels.windows
Oct 22, 2023
9f2a61f
lib.systems.parse: remove assertion now that gnu-config has bumped
Oct 22, 2023
f3441fc
lib.systems.inspect: exclude kernel="" from isNone
Oct 22, 2023
21882ca
lib.systems.parse: do not infer vendor="pc" for *-elf
Oct 22, 2023
7b6cd7d
lib.tests.systems: include lib.systems.doubles.vc4
Oct 22, 2023
8707d2c
lib.systems.triples: remove exception for ghcjs-javascript (gnu-confi…
Oct 22, 2023
62b5c35
lib/systems/parse.nix: remove commented-out obsolete attribute
Oct 30, 2023
95d0b0e
lib/tests/triples.nix: reword comment
Oct 30, 2023
dd58ed9
lib/tests/triples.nix: add --silent to make invocation
Oct 30, 2023
014902c
lib/tests/triples.nix: add *-*-uefi exception
Nov 1, 2023
a364aea
Revert "lib/tests/triples.nix: add *-*-uefi exception"
Nov 2, 2023
021526a
lib/systems/default.nix: fix darwin missing bootstrap url for platfor…
Nov 30, 2023
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
4 changes: 2 additions & 2 deletions lib/systems/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ rec {
parsed = parse.mkSystemFromString (if args ? config then args.config else args.system);
# Either of these can be losslessly-extracted from `parsed` iff parsing succeeds.
system = parse.doubleFromSystem final.parsed;
config = parse.tripleFromSystem final.parsed;
config = parse.tripleFromSystemLossy final.parsed;
# Determine whether we can execute binaries built for the provided platform.
canExecute = platform:
final.isAndroid == platform.isAndroid &&
Expand Down Expand Up @@ -325,7 +325,7 @@ rec {
}.${cpu.name} or cpu.name;
vendor_ = final.rust.platform.vendor;
in rust.config
or "${cpu_}-${vendor_}-${kernel.name}${lib.optionalString (abi.name != "unknown") "-${abi.name}"}";
or "${cpu_}-${vendor_}-${kernel.name}${lib.optionalString (abi.name != "unknown" && abi.name != "") "-${abi.name}"}";

# The name of the rust target if it is standard, or the json file
# containing the custom target spec.
Expand Down
6 changes: 4 additions & 2 deletions lib/systems/doubles.nix
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ let
"aarch64-genode" "i686-genode" "x86_64-genode"

# illumos
"x86_64-solaris"
"x86_64-solaris2"

# JS
"javascript-ghcjs"
Expand All @@ -43,7 +43,9 @@ let
"aarch64_be-none" "aarch64-none" "arm-none" "armv6l-none" "avr-none" "i686-none"
"microblaze-none" "microblazeel-none" "mips-none" "mips64-none" "msp430-none" "or1k-none" "m68k-none"
"powerpc-none" "powerpcle-none" "riscv32-none" "riscv64-none" "rx-none"
"s390-none" "s390x-none" "vc4-none" "x86_64-none"
"s390-none" "s390x-none"
"vc4-elf" # nonstandard triple, requires many hacks
"x86_64-none"

# OpenBSD
"i686-openbsd" "x86_64-openbsd"
Expand Down
2 changes: 1 addition & 1 deletion lib/systems/inspect.nix
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ rec {
isMacOS = { kernel = kernels.macos; };
isiOS = { kernel = kernels.ios; };
isLinux = { kernel = kernels.linux; };
isSunOS = { kernel = kernels.solaris; };
isSunOS = { kernel = kernels.solaris2; };
isFreeBSD = { kernel = { name = "freebsd"; }; };
isNetBSD = { kernel = kernels.netbsd; };
isOpenBSD = { kernel = kernels.openbsd; };
Expand Down
211 changes: 163 additions & 48 deletions lib/systems/parse.nix
Original file line number Diff line number Diff line change
Expand Up @@ -230,13 +230,19 @@ rec {
vendors = setTypes types.openVendor {
apple = {};
pc = {};
ibm = {};
knuth = {};
xilinx = {};
solo5 = {};

# Actually matters, unlocking some MinGW-w64-specific options in GCC. See
# bottom of https://sourceforge.net/p/mingw-w64/wiki2/Unicode%20apps/
w64 = {};

none = {};
# gnu-config distinguishes between `foo-bar-baz` and
# `foo-unknown-bar-baz`; we use `""` to represent the
# former case.
"" = { name = ""; };
unknown = {};
};

Expand Down Expand Up @@ -287,6 +293,9 @@ rec {

types.kernel = enum (attrValues kernels);

# TODO (@amjoseph): we should eliminate execFormats or move it to
# abis; executable format is a property of the ABI not the kernel.
# This will also clear up the netbsd kludge in tripleFromSystem.
kernels = with execFormats; with kernelFamilies; setTypes types.openKernel {
# TODO(@Ericson2314): Don't want to mass-rebuild yet to keeping 'darwin' as
# the normalized name for macOS.
Expand All @@ -300,8 +309,9 @@ rec {
linux = { execFormat = elf; families = { }; };
netbsd = { execFormat = elf; families = { inherit bsd; }; };
none = { execFormat = unknown; families = { }; };
"" = { execFormat = unknown; families = { }; };
openbsd = { execFormat = elf; families = { inherit bsd; }; };
solaris = { execFormat = elf; families = { }; };
solaris2 = { execFormat = elf; families = { }; name = "solaris"; version = 2; };
wasi = { execFormat = wasm; families = { }; };
redox = { execFormat = elf; families = { }; };
windows = { execFormat = pe; families = { }; };
Expand All @@ -324,23 +334,23 @@ rec {
merge = mergeOneOption;
};

types.abi = enum (attrValues abis);
types.abi = enum (attrValues (builtins.removeAttrs abis ["unknown"]));

abis = setTypes types.openAbi {
cygnus = {};
msvc = {};
abis = setTypes types.openAbi rec {
cygnus = { kernels = [ "windows" ]; };
msvc = { kernels = [ "windows" ]; };

# Note: eabi is specific to ARM and PowerPC.
# On PowerPC, this corresponds to PPCEABI.
# On ARM, this corresponds to ARMEABI.
eabi = { float = "soft"; };
eabihf = { float = "hard"; };
eabi = { float = "soft"; kernels = builtins.attrNames kernels; };
eabihf = { float = "hard"; kernels = builtins.attrNames kernels; };

# Other architectures should use ELF in embedded situations.
elf = {};
elf = { kernels = [ "none" "" ]; };

androideabi = {};
android = {
androideabi = { inherit (android) kernels; };
android = { kernels = [ "linux" ];
assertions = [
{ assertion = platform: !platform.isAarch32;
message = ''
Expand All @@ -350,9 +360,9 @@ rec {
];
};

gnueabi = { float = "soft"; };
gnueabihf = { float = "hard"; };
gnu = {
gnueabi = { float = "soft"; inherit (gnu) kernels; };
gnueabihf = { float = "hard"; inherit (gnu) kernels; };
gnu = { kernels = [ "freebsd12" "freebsd13" "linux" "windows" ];
assertions = [
{ assertion = platform: !platform.isAarch32;
message = ''
Expand All @@ -366,27 +376,34 @@ rec {
}
];
};
gnuabi64 = { abi = "64"; };
muslabi64 = { abi = "64"; };
gnuabi64 = { abi = "64"; inherit (gnu) kernels; };
muslabi64 = { abi = "64"; kernels = [ "linux" ]; };

# NOTE: abi=n32 requires a 64-bit MIPS chip! That is not a typo.
# It is basically the 64-bit abi with 32-bit pointers. Details:
# https://www.linux-mips.org/pub/linux/mips/doc/ABI/MIPS-N32-ABI-Handbook.pdf
gnuabin32 = { abi = "n32"; };
muslabin32 = { abi = "n32"; };
gnuabin32 = { abi = "n32"; inherit (gnu) kernels; };
muslabin32 = { abi = "n32"; inherit (musl) kernels; };

gnuabielfv2 = { abi = "elfv2"; };
gnuabielfv1 = { abi = "elfv1"; };
gnuabielfv2 = { abi = "elfv2"; kernels = [ "linux" ]; };
gnuabielfv1 = { abi = "elfv1"; kernels = [ "linux" ]; };

musleabi = { float = "soft"; };
musleabihf = { float = "hard"; };
musl = {};
musleabi = { float = "soft"; inherit (musl) kernels; };
musleabihf = { float = "hard"; inherit (musl) kernels; };
musl = { kernels = [ "linux" ]; };

uclibceabi = { float = "soft"; };
uclibceabihf = { float = "hard"; };
uclibc = {};
uclibceabi = { float = "soft"; inherit (uclibc) kernels; };
uclibceabihf = { float = "hard"; inherit (uclibc) kernels; };
uclibc = { kernels = [ "linux" ]; };

unknown = {};
"" = { kernels = [ "darwin" "freebsd12" "freebsd13" "freebsd" "genode" "solaris2" "solaris" "ghcjs" "mmixware" "netbsd" "none" "" "openbsd" "redox" "wasi" ]; };

# in gnu-config triples, this abi is actually the empty string "" rather than "-unknown"
unknown =
# Added 2023-08-18. When removing, please also remove the
# `removeAttrs ["unknown"]` in lib.tests.triples and
# lib.systems.types.abi
abis."" // { assertions = lib.warn "please use abis.\"\" instead; \"unknown\" is not a valid ABI." [ ]; };
};

################################################################################
Expand All @@ -406,11 +423,40 @@ rec {

mkSystem = components:
assert types.parsedPlatform.check components;
assert with components;
(kernel == kernels.ghcjs) != (cpu == cpuTypes.javascript)
-> throw ''
cpu "javascript" and kernel "ghcjs" are valid only with each other;
you attempted to use cpu "${components.cpu.name}" with kernel
"${components.kernel.name}"
'';
assert with components;
!(lib.elem kernel.name (abi.kernels or [ kernel.name ])) &&
!(isVc4 components)
-> throw ''
kernel ${components.kernel.name} does not allow abi ${components.abi.name}
'';
assert with components;
!(isVc4 components -> (with components; vendor.name == "" && kernel.name == "" && abi.name == "elf"))
-> throw ''
Broadcom VC4 CPUs may be used only in the nonstandard triple "vc4-elf".
You tried to create "${cpu.name}-${vendor.name}-${kernel.name}-${abi.name}".
'';
assert with components;
!(isJavaScript components ->
(vendor.name == "unknown" || vendor.name == "") &&
kernel == kernels.ghcjs &&
abi == abis."")
-> throw ''
The special "javascript" cpu may be used only in the nonstandard triple
"javascript-unknown-ghcjs". You tried to create
"${cpu.name}-${vendor.name}-${kernel.name}-${abi.name}"
'';
setType "system" components;

mkSkeletonFromList = l: {
"1" = if elemAt l 0 == "avr"
then { cpu = elemAt l 0; kernel = "none"; abi = "unknown"; }
then { cpu = elemAt l 0; kernel = "none"; abi = ""; }
else throw "Target specification with 1 components is ambiguous";
"2" = # We only do 2-part hacks for things Nix already supports
if elemAt l 1 == "cygwin"
Expand All @@ -422,20 +468,29 @@ rec {
else if elemAt l 1 == "windows"
then { cpu = elemAt l 0; kernel = "windows"; abi = "msvc"; }
else if (elemAt l 1) == "elf"
then { cpu = elemAt l 0; vendor = "unknown"; kernel = "none"; abi = elemAt l 1; }
then { cpu = elemAt l 0; kernel = ""; abi = elemAt l 1; }
else { cpu = elemAt l 0; kernel = elemAt l 1; };
"3" =
# cpu-vendor-""-abi
if elemAt l 1 == "unknown" && elemAt l 2 == "elf"
then {
cpu = elemAt l 0;
vendor = elemAt l 1;
kernel = "";
abi = elemAt l 2;
}
# cpu-kernel-environment
if elemAt l 1 == "linux" ||
elem (elemAt l 2) ["eabi" "eabihf" "elf" "gnu"]
else if elemAt l 1 == "linux" ||
elemAt l 1 == "none" ||
elem (elemAt l 2) ["eabi" "eabihf" "elf" "gnu"]
then {
cpu = elemAt l 0;
kernel = elemAt l 1;
abi = elemAt l 2;
vendor = "unknown";
}
# cpu-vendor-os
else if elemAt l 1 == "apple" ||
elemAt l 1 == "solo5" ||
elem (elemAt l 2) [ "wasi" "redox" "mmixware" "ghcjs" "mingw32" ] ||
hasPrefix "freebsd" (elemAt l 2) ||
hasPrefix "netbsd" (elemAt l 2) ||
Expand All @@ -454,39 +509,61 @@ rec {

# This should revert the job done by config.guess from the gcc compiler.
mkSystemFromSkeleton = { cpu
, # Optional, but fallback too complex for here.
# Inferred below instead.
vendor ? assert false; null
, vendor ? ""
, kernel
, # Also inferred below
abi ? assert false; null
abi ? null
} @ args: let
getCpu = name: cpuTypes.${name} or (throw "Unknown CPU type: ${name}");
getVendor = name: vendors.${name} or (throw "Unknown vendor: ${name}");
getKernel = name: kernels.${name} or (throw "Unknown kernel: ${name}");
getAbi = name: abis.${name} or (throw "Unknown ABI: ${name}");

vendor_ = getVendor vendor;

# These the three CPUs for which gnu-config will sometimes
# clobber an explicitly-specified `-unknown` vendor with
# something else.
clobberedVendor =
if isS390 parsed then vendors.ibm
else if isMicroBlaze parsed then vendors.xilinx
else if isMmix parsed then vendors.knuth
else if isVc4 parsed then vendors."" # hack for nonstandard triple
else vendors.unknown;

parsed = {
cpu = getCpu args.cpu;
vendor =
/**/ if args ? vendor then getVendor args.vendor
else if isDarwin parsed then vendors.apple
else if isWindows parsed then vendors.pc
else vendors.unknown;
if vendor_ == vendors.unknown then clobberedVendor
else if vendor_ != vendors."" then vendor_
else if (isx86_64 parsed || isi686 parsed) &&
parsed.abi == abis.gnu then
vendors.unknown # nixpkgs-specific behavior
else if (isx86_64 parsed || isAarch64 parsed) &&
isLittleEndian parsed &&
parsed.kernel == kernels.darwin &&
parsed.abi == abis."" then
vendors.apple # nixpkgs-specific behavior
else if isx86 parsed && isLinux parsed then vendors.pc
else if ((abi=="eabi" || abi=="eabihf")) && !(isLinux parsed || isNetBSD parsed) then vendor_
else if isNone parsed && vendor_ == vendors."" && abi == "elf" then vendors.""
else if isx86 parsed then vendors.pc
else clobberedVendor;

kernel = if hasPrefix "darwin" args.kernel then getKernel "darwin"
else if hasPrefix "netbsd" args.kernel then getKernel "netbsd"
else getKernel (removeAbiSuffix args.kernel);
abi =
/**/ if args ? abi then getAbi args.abi
/**/ if abi != null then getAbi abi
else if isLinux parsed || isWindows parsed then
if isAarch32 parsed then
if lib.versionAtLeast (parsed.cpu.version or "0") "6"
if parsed.vendor == vendors.apple then abis.gnu
else if isLinux parsed then abis.gnu
else if lib.versionAtLeast (parsed.cpu.version or "0") "6"
then abis.gnueabihf
else abis.gnueabi
# Default ppc64 BE to ELFv2
else if isPower64 parsed && isBigEndian parsed then abis.gnuabielfv2
else abis.gnu
else abis.unknown;
else abis."";
};

in mkSystem parsed;
Expand All @@ -496,18 +573,56 @@ rec {
kernelName = kernel:
kernel.name + toString (kernel.version or "");

doubleFromSystem = { cpu, kernel, abi, ... }:
doubleFromSystem = { cpu, kernel, abi, ... }@platform:
/**/ if abi == abis.cygnus then "${cpu.name}-cygwin"
else if kernel.families ? darwin then "${cpu.name}-darwin"
else if isVc4 platform then "${cpu.name}-${abi.name}" # hack for nonstandard triple
else "${cpu.name}-${kernelName kernel}";

# Convert a system into a string triple
tripleFromSystem = { cpu, vendor, kernel, abi, ... } @ sys: assert isSystem sys; let
optExecFormat =
lib.optionalString (kernel.name == "netbsd" &&
gnuNetBSDDefaultExecFormat cpu != kernel.execFormat)
kernel.execFormat.name;
optAbi = lib.optionalString (abi != abis.unknown) "-${abi.name}";
in "${cpu.name}-${vendor.name}-${kernelName kernel}${optExecFormat}${optAbi}";
in
tripleFromSkeleton {
cpu = cpu.name;
vendor = vendor.name;
kernel = kernelName kernel;
abi = abi.name;
};

# Convert a system into a string triple, erasing the distinction
# between vendors."" and vendors.unknown -- i.e. `mips-linux-gnu`
# and `mips-unknown-linux-gnu` both become
# `"mips-unknown-linux-gnu"`.
tripleFromSystemLossy = { cpu, vendor, kernel, abi, ... } @ sys: assert isSystem sys;
tripleFromSystem (sys // lib.optionalAttrs (sys.vendor == vendors."") {
vendor = vendors.unknown;
});

tripleFromSkeleton = { cpu, vendor, kernel, optExecFormat?"", abi }: let
optAbi = lib.optionalString (abi != "") "-${abi}";
optVendor = lib.optionalString (vendor != "") "-${vendor}";
optKernel = lib.optionalString (kernel != "") "-${kernel}";
in
# gnu-config considers "mingw32" and "cygwin" to be kernels.
# This is obviously bogus, which is why nixpkgs has historically
# parsed them differently. However for regression testing
# reasons (see lib/tests/triples.nix) we need to replicate this
# quirk when unparsing in order to round-trip correctly.
if abi == "cygnus" then "${cpu}${optVendor}-cygwin"
else if kernel == "windows" then "${cpu}${optVendor}-mingw32"
else "${cpu}${optVendor}${optKernel}${optExecFormat}${optAbi}";

# To "canonicalize" a triple is to parse it and then unparse (turn
# back into a string) it.
canonicalize = triple:
lib.pipe triple [
mkSystemFromString # parse
tripleFromSystem # unparse
];

################################################################################

Expand Down
Loading