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 supported = import ./supported.nix { inherit lib; };
12
13 # Elaborate a `localSystem` or `crossSystem` so that it contains everything
14 # necessary.
15 #
16 # `parsed` is inferred from args, both because there are two options with one
17 # clearly prefered, and to prevent cycles. A simpler fixed point where the RHS
18 # always just used `final.*` would fail on both counts.
19 elaborate = args': let
20 args = if lib.isString args' then { system = args'; }
21 else args';
22 final = {
23 # Prefer to parse `config` as it is strictly more informative.
24 parsed = parse.mkSystemFromString (if args ? config then args.config else args.system);
25 # Either of these can be losslessly-extracted from `parsed` iff parsing succeeds.
26 system = parse.doubleFromSystem final.parsed;
27 config = parse.tripleFromSystem final.parsed;
28 # Determine whether we are compatible with the provided CPU
29 isCompatible = platform: parse.isCompatible final.parsed.cpu platform.parsed.cpu;
30 # Derived meta-data
31 libc =
32 /**/ if final.isDarwin then "libSystem"
33 else if final.isMinGW then "msvcrt"
34 else if final.isWasi then "wasilibc"
35 else if final.isRedox then "relibc"
36 else if final.isMusl then "musl"
37 else if final.isUClibc then "uclibc"
38 else if final.isAndroid then "bionic"
39 else if final.isLinux /* default */ then "glibc"
40 else if final.isAvr then "avrlibc"
41 else if final.isNone then "newlib"
42 else if final.isNetBSD then "nblibc"
43 # TODO(@Ericson2314) think more about other operating systems
44 else "native/impure";
45 # Choose what linker we wish to use by default. Someday we might also
46 # choose the C compiler, runtime library, C++ standard library, etc. in
47 # this way, nice and orthogonally, and deprecate `useLLVM`. But due to
48 # the monolithic GCC build we cannot actually make those choices
49 # independently, so we are just doing `linker` and keeping `useLLVM` for
50 # now.
51 linker =
52 /**/ if final.useLLVM or false then "lld"
53 else if final.isDarwin then "cctools"
54 # "bfd" and "gold" both come from GNU binutils. The existance of Gold
55 # is why we use the more obscure "bfd" and not "binutils" for this
56 # choice.
57 else "bfd";
58 extensions = {
59 sharedLibrary =
60 /**/ if final.isDarwin then ".dylib"
61 else if final.isWindows then ".dll"
62 else ".so";
63 executable =
64 /**/ if final.isWindows then ".exe"
65 else "";
66 };
67 # Misc boolean options
68 useAndroidPrebuilt = false;
69 useiOSPrebuilt = false;
70
71 # Output from uname
72 uname = {
73 # uname -s
74 system = {
75 linux = "Linux";
76 windows = "Windows";
77 darwin = "Darwin";
78 netbsd = "NetBSD";
79 freebsd = "FreeBSD";
80 openbsd = "OpenBSD";
81 wasi = "Wasi";
82 redox = "Redox";
83 genode = "Genode";
84 }.${final.parsed.kernel.name} or null;
85
86 # uname -p
87 processor = final.parsed.cpu.name;
88
89 # uname -r
90 release = null;
91 };
92 isStatic = final.isWasm || final.isRedox;
93
94 # Just a guess, based on `system`
95 inherit
96 ({
97 linux-kernel = args.linux-kernel or {};
98 gcc = args.gcc or {};
99 rustc = args.rust or {};
100 } // platforms.select final)
101 linux-kernel gcc rustc;
102
103 linuxArch =
104 if final.isAarch32 then "arm"
105 else if final.isAarch64 then "arm64"
106 else if final.isx86_32 then "i386"
107 else if final.isx86_64 then "x86_64"
108 else if final.isMips then "mips"
109 else if final.isPower then "powerpc"
110 else if final.isRiscV then "riscv"
111 else if final.isS390 then "s390"
112 else final.parsed.cpu.name;
113
114 qemuArch =
115 if final.isAarch32 then "arm"
116 else if final.isx86_64 then "x86_64"
117 else if final.isx86 then "i386"
118 else {
119 powerpc = "ppc";
120 powerpcle = "ppc";
121 powerpc64 = "ppc64";
122 powerpc64le = "ppc64le";
123 }.${final.parsed.cpu.name} or final.parsed.cpu.name;
124
125 darwinArch = {
126 armv7a = "armv7";
127 aarch64 = "arm64";
128 }.${final.parsed.cpu.name} or final.parsed.cpu.name;
129
130 darwinPlatform =
131 if final.isMacOS then "macos"
132 else if final.isiOS then "ios"
133 else null;
134 # The canonical name for this attribute is darwinSdkVersion, but some
135 # platforms define the old name "sdkVer".
136 darwinSdkVersion = final.sdkVer or (if final.isAarch64 then "11.0" else "10.12");
137 darwinMinVersion = final.darwinSdkVersion;
138 darwinMinVersionVariable =
139 if final.isMacOS then "MACOSX_DEPLOYMENT_TARGET"
140 else if final.isiOS then "IPHONEOS_DEPLOYMENT_TARGET"
141 else null;
142
143 emulator = pkgs: let
144 qemu-user = pkgs.qemu.override {
145 smartcardSupport = false;
146 spiceSupport = false;
147 openGLSupport = false;
148 virglSupport = false;
149 vncSupport = false;
150 gtkSupport = false;
151 sdlSupport = false;
152 pulseSupport = false;
153 smbdSupport = false;
154 seccompSupport = false;
155 hostCpuTargets = ["${final.qemuArch}-linux-user"];
156 };
157 wine-name = "wine${toString final.parsed.cpu.bits}";
158 wine = (pkgs.winePackagesFor wine-name).minimal;
159 in
160 if final.parsed.kernel.name == pkgs.stdenv.hostPlatform.parsed.kernel.name &&
161 pkgs.stdenv.hostPlatform.isCompatible final
162 then "${pkgs.runtimeShell} -c '\"$@\"' --"
163 else if final.isWindows
164 then "${wine}/bin/${wine-name}"
165 else if final.isLinux && pkgs.stdenv.hostPlatform.isLinux
166 then "${qemu-user}/bin/qemu-${final.qemuArch}"
167 else if final.isWasi
168 then "${pkgs.wasmtime}/bin/wasmtime"
169 else if final.isMmix
170 then "${pkgs.mmixware}/bin/mmix"
171 else throw "Don't know how to run ${final.config} executables.";
172
173 } // mapAttrs (n: v: v final.parsed) inspect.predicates
174 // mapAttrs (n: v: v final.gcc.arch or "default") architectures.predicates
175 // args;
176 in assert final.useAndroidPrebuilt -> final.isAndroid;
177 assert lib.foldl
178 (pass: { assertion, message }:
179 if assertion final
180 then pass
181 else throw message)
182 true
183 (final.parsed.abi.assertions or []);
184 final;
185}