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