lol
1{ lib }:
2 let inherit (lib.attrsets) mapAttrs; in
3
4rec {
5 doubles = import ./doubles.nix { inherit lib; };
6 parse = import ./parse.nix { inherit lib; };
7 inspect = import ./inspect.nix { inherit lib; };
8 platforms = import ./platforms.nix { inherit lib; };
9 examples = import ./examples.nix { inherit lib; };
10 architectures = import ./architectures.nix { inherit lib; };
11
12 /* List of all Nix system doubles the nixpkgs flake will expose the package set
13 for. All systems listed here must be supported by nixpkgs as `localSystem`.
14
15 **Warning**: This attribute is considered experimental and is subject to change.
16 */
17 flakeExposed = import ./flake-systems.nix { };
18
19 # Elaborate a `localSystem` or `crossSystem` so that it contains everything
20 # necessary.
21 #
22 # `parsed` is inferred from args, both because there are two options with one
23 # clearly preferred, and to prevent cycles. A simpler fixed point where the RHS
24 # always just used `final.*` would fail on both counts.
25 elaborate = args': let
26 args = if lib.isString args' then { system = args'; }
27 else args';
28 final = {
29 # Prefer to parse `config` as it is strictly more informative.
30 parsed = parse.mkSystemFromString (if args ? config then args.config else args.system);
31 # Either of these can be losslessly-extracted from `parsed` iff parsing succeeds.
32 system = parse.doubleFromSystem final.parsed;
33 config = parse.tripleFromSystem final.parsed;
34 # Determine whether we can execute binaries built for the provided platform.
35 canExecute = platform:
36 final.isAndroid == platform.isAndroid &&
37 parse.isCompatible final.parsed.cpu platform.parsed.cpu
38 && final.parsed.kernel == platform.parsed.kernel;
39 isCompatible = _: throw "2022-05-23: isCompatible has been removed in favor of canExecute, refer to the 22.11 changelog for details";
40 # Derived meta-data
41 libc =
42 /**/ if final.isDarwin then "libSystem"
43 else if final.isMinGW then "msvcrt"
44 else if final.isWasi then "wasilibc"
45 else if final.isRedox then "relibc"
46 else if final.isMusl then "musl"
47 else if final.isUClibc then "uclibc"
48 else if final.isAndroid then "bionic"
49 else if final.isLinux /* default */ then "glibc"
50 else if final.isFreeBSD then "fblibc"
51 else if final.isNetBSD then "nblibc"
52 else if final.isAvr then "avrlibc"
53 else if final.isGhcjs then null
54 else if final.isNone then "newlib"
55 # TODO(@Ericson2314) think more about other operating systems
56 else "native/impure";
57 # Choose what linker we wish to use by default. Someday we might also
58 # choose the C compiler, runtime library, C++ standard library, etc. in
59 # this way, nice and orthogonally, and deprecate `useLLVM`. But due to
60 # the monolithic GCC build we cannot actually make those choices
61 # independently, so we are just doing `linker` and keeping `useLLVM` for
62 # now.
63 linker =
64 /**/ if final.useLLVM or false then "lld"
65 else if final.isDarwin then "cctools"
66 # "bfd" and "gold" both come from GNU binutils. The existence of Gold
67 # is why we use the more obscure "bfd" and not "binutils" for this
68 # choice.
69 else "bfd";
70 extensions = rec {
71 sharedLibrary =
72 /**/ if final.isDarwin then ".dylib"
73 else if final.isWindows then ".dll"
74 else ".so";
75 staticLibrary =
76 /**/ if final.isWindows then ".lib"
77 else ".a";
78 library =
79 /**/ if final.isStatic then staticLibrary
80 else sharedLibrary;
81 executable =
82 /**/ if final.isWindows then ".exe"
83 else "";
84 };
85 # Misc boolean options
86 useAndroidPrebuilt = false;
87 useiOSPrebuilt = false;
88
89 # Output from uname
90 uname = {
91 # uname -s
92 system = {
93 linux = "Linux";
94 windows = "Windows";
95 darwin = "Darwin";
96 netbsd = "NetBSD";
97 freebsd = "FreeBSD";
98 openbsd = "OpenBSD";
99 wasi = "Wasi";
100 redox = "Redox";
101 genode = "Genode";
102 }.${final.parsed.kernel.name} or null;
103
104 # uname -m
105 processor =
106 if final.isPower64
107 then "ppc64${lib.optionalString final.isLittleEndian "le"}"
108 else if final.isPower
109 then "ppc${lib.optionalString final.isLittleEndian "le"}"
110 else if final.isMips64
111 then "mips64" # endianness is *not* included on mips64
112 else final.parsed.cpu.name;
113
114 # uname -r
115 release = null;
116 };
117 isStatic = final.isWasm || final.isRedox;
118
119 # Just a guess, based on `system`
120 inherit
121 ({
122 linux-kernel = args.linux-kernel or {};
123 gcc = args.gcc or {};
124 rustc = args.rustc or {};
125 } // platforms.select final)
126 linux-kernel gcc rustc;
127
128 linuxArch =
129 if final.isAarch32 then "arm"
130 else if final.isAarch64 then "arm64"
131 else if final.isx86_32 then "i386"
132 else if final.isx86_64 then "x86_64"
133 # linux kernel does not distinguish microblaze/microblazeel
134 else if final.isMicroBlaze then "microblaze"
135 else if final.isMips32 then "mips"
136 else if final.isMips64 then "mips" # linux kernel does not distinguish mips32/mips64
137 else if final.isPower then "powerpc"
138 else if final.isRiscV then "riscv"
139 else if final.isS390 then "s390"
140 else if final.isLoongArch64 then "loongarch"
141 else final.parsed.cpu.name;
142
143 qemuArch =
144 if final.isAarch32 then "arm"
145 else if final.isS390 && !final.isS390x then null
146 else if final.isx86_64 then "x86_64"
147 else if final.isx86 then "i386"
148 else if final.isMips64 then "mips64${lib.optionalString final.isLittleEndian "el"}"
149 else final.uname.processor;
150
151 # Name used by UEFI for architectures.
152 efiArch =
153 if final.isx86_32 then "ia32"
154 else if final.isx86_64 then "x64"
155 else if final.isAarch32 then "arm"
156 else if final.isAarch64 then "aa64"
157 else final.parsed.cpu.name;
158
159 darwinArch = {
160 armv7a = "armv7";
161 aarch64 = "arm64";
162 }.${final.parsed.cpu.name} or final.parsed.cpu.name;
163
164 darwinPlatform =
165 if final.isMacOS then "macos"
166 else if final.isiOS then "ios"
167 else null;
168 # The canonical name for this attribute is darwinSdkVersion, but some
169 # platforms define the old name "sdkVer".
170 darwinSdkVersion = final.sdkVer or (if final.isAarch64 then "11.0" else "10.12");
171 darwinMinVersion = final.darwinSdkVersion;
172 darwinMinVersionVariable =
173 if final.isMacOS then "MACOSX_DEPLOYMENT_TARGET"
174 else if final.isiOS then "IPHONEOS_DEPLOYMENT_TARGET"
175 else null;
176 } // (
177 let
178 selectEmulator = pkgs:
179 let
180 qemu-user = pkgs.qemu.override {
181 smartcardSupport = false;
182 spiceSupport = false;
183 openGLSupport = false;
184 virglSupport = false;
185 vncSupport = false;
186 gtkSupport = false;
187 sdlSupport = false;
188 pulseSupport = false;
189 smbdSupport = false;
190 seccompSupport = false;
191 enableDocs = false;
192 hostCpuTargets = [ "${final.qemuArch}-linux-user" ];
193 };
194 wine = (pkgs.winePackagesFor "wine${toString final.parsed.cpu.bits}").minimal;
195 in
196 if final.parsed.kernel.name == pkgs.stdenv.hostPlatform.parsed.kernel.name &&
197 pkgs.stdenv.hostPlatform.canExecute final
198 then "${pkgs.runtimeShell} -c '\"$@\"' --"
199 else if final.isWindows
200 then "${wine}/bin/wine${lib.optionalString (final.parsed.cpu.bits == 64) "64"}"
201 else if final.isLinux && pkgs.stdenv.hostPlatform.isLinux && final.qemuArch != null
202 then "${qemu-user}/bin/qemu-${final.qemuArch}"
203 else if final.isWasi
204 then "${pkgs.wasmtime}/bin/wasmtime"
205 else if final.isMmix
206 then "${pkgs.mmixware}/bin/mmix"
207 else null;
208 in {
209 emulatorAvailable = pkgs: (selectEmulator pkgs) != null;
210
211 emulator = pkgs:
212 if (final.emulatorAvailable pkgs)
213 then selectEmulator pkgs
214 else throw "Don't know how to run ${final.config} executables.";
215
216 }) // mapAttrs (n: v: v final.parsed) inspect.predicates
217 // mapAttrs (n: v: v final.gcc.arch or "default") architectures.predicates
218 // args;
219 in assert final.useAndroidPrebuilt -> final.isAndroid;
220 assert lib.foldl
221 (pass: { assertion, message }:
222 if assertion final
223 then pass
224 else throw message)
225 true
226 (final.parsed.abi.assertions or []);
227 final;
228}