at 18.09-beta 12 kB view raw
1# Define the list of system with their properties. 2# 3# See https://clang.llvm.org/docs/CrossCompilation.html and 4# http://llvm.org/docs/doxygen/html/Triple_8cpp_source.html especially 5# Triple::normalize. Parsing should essentially act as a more conservative 6# version of that last function. 7# 8# Most of the types below come in "open" and "closed" pairs. The open ones 9# specify what information we need to know about systems in general, and the 10# closed ones are sub-types representing the whitelist of systems we support in 11# practice. 12# 13# Code in the remainder of nixpkgs shouldn't rely on the closed ones in 14# e.g. exhaustive cases. Its more a sanity check to make sure nobody defines 15# systems that overlap with existing ones and won't notice something amiss. 16# 17{ lib }: 18with lib.lists; 19with lib.types; 20with lib.attrsets; 21with lib.strings; 22with (import ./inspect.nix { inherit lib; }).predicates; 23 24let 25 inherit (lib.options) mergeOneOption; 26 27 setTypes = type: 28 mapAttrs (name: value: 29 assert type.check value; 30 setType type.name ({ inherit name; } // value)); 31 32in 33 34rec { 35 36 ################################################################################ 37 38 types.openSignificantByte = mkOptionType { 39 name = "significant-byte"; 40 description = "Endianness"; 41 merge = mergeOneOption; 42 }; 43 44 types.significantByte = enum (attrValues significantBytes); 45 46 significantBytes = setTypes types.openSignificantByte { 47 bigEndian = {}; 48 littleEndian = {}; 49 }; 50 51 ################################################################################ 52 53 # Reasonable power of 2 54 types.bitWidth = enum [ 8 16 32 64 128 ]; 55 56 ################################################################################ 57 58 types.openCpuType = mkOptionType { 59 name = "cpu-type"; 60 description = "instruction set architecture name and information"; 61 merge = mergeOneOption; 62 check = x: types.bitWidth.check x.bits 63 && (if 8 < x.bits 64 then types.significantByte.check x.significantByte 65 else !(x ? significantByte)); 66 }; 67 68 types.cpuType = enum (attrValues cpuTypes); 69 70 cpuTypes = with significantBytes; setTypes types.openCpuType { 71 arm = { bits = 32; significantByte = littleEndian; family = "arm"; }; 72 armv5tel = { bits = 32; significantByte = littleEndian; family = "arm"; version = "5"; }; 73 armv6m = { bits = 32; significantByte = littleEndian; family = "arm"; version = "6"; }; 74 armv6l = { bits = 32; significantByte = littleEndian; family = "arm"; version = "6"; }; 75 armv7a = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; }; 76 armv7r = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; }; 77 armv7m = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; }; 78 armv7l = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; }; 79 armv8a = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; }; 80 armv8r = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; }; 81 armv8m = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; }; 82 aarch64 = { bits = 64; significantByte = littleEndian; family = "arm"; version = "8"; }; 83 84 i686 = { bits = 32; significantByte = littleEndian; family = "x86"; }; 85 x86_64 = { bits = 64; significantByte = littleEndian; family = "x86"; }; 86 87 mips = { bits = 32; significantByte = bigEndian; family = "mips"; }; 88 mipsel = { bits = 32; significantByte = littleEndian; family = "mips"; }; 89 mips64 = { bits = 64; significantByte = bigEndian; family = "mips"; }; 90 mips64el = { bits = 64; significantByte = littleEndian; family = "mips"; }; 91 92 powerpc = { bits = 32; significantByte = bigEndian; family = "power"; }; 93 powerpc64 = { bits = 64; significantByte = bigEndian; family = "power"; }; 94 powerpc64le = { bits = 64; significantByte = littleEndian; family = "power"; }; 95 96 riscv32 = { bits = 32; significantByte = littleEndian; family = "riscv"; }; 97 riscv64 = { bits = 64; significantByte = littleEndian; family = "riscv"; }; 98 99 sparc = { bits = 32; significantByte = bigEndian; family = "sparc"; }; 100 sparc64 = { bits = 64; significantByte = bigEndian; family = "sparc"; }; 101 102 wasm32 = { bits = 32; significantByte = littleEndian; family = "wasm"; }; 103 wasm64 = { bits = 64; significantByte = littleEndian; family = "wasm"; }; 104 }; 105 106 ################################################################################ 107 108 types.openVendor = mkOptionType { 109 name = "vendor"; 110 description = "vendor for the platform"; 111 merge = mergeOneOption; 112 }; 113 114 types.vendor = enum (attrValues vendors); 115 116 vendors = setTypes types.openVendor { 117 apple = {}; 118 pc = {}; 119 120 unknown = {}; 121 }; 122 123 ################################################################################ 124 125 types.openExecFormat = mkOptionType { 126 name = "exec-format"; 127 description = "executable container used by the kernel"; 128 merge = mergeOneOption; 129 }; 130 131 types.execFormat = enum (attrValues execFormats); 132 133 execFormats = setTypes types.openExecFormat { 134 aout = {}; # a.out 135 elf = {}; 136 macho = {}; 137 pe = {}; 138 139 unknown = {}; 140 }; 141 142 ################################################################################ 143 144 types.openKernelFamily = mkOptionType { 145 name = "exec-format"; 146 description = "executable container used by the kernel"; 147 merge = mergeOneOption; 148 }; 149 150 types.kernelFamily = enum (attrValues kernelFamilies); 151 152 kernelFamilies = setTypes types.openKernelFamily { 153 bsd = {}; 154 darwin = {}; 155 }; 156 157 ################################################################################ 158 159 types.openKernel = mkOptionType { 160 name = "kernel"; 161 description = "kernel name and information"; 162 merge = mergeOneOption; 163 check = x: types.execFormat.check x.execFormat 164 && all types.kernelFamily.check (attrValues x.families); 165 }; 166 167 types.kernel = enum (attrValues kernels); 168 169 kernels = with execFormats; with kernelFamilies; setTypes types.openKernel { 170 # TODO(@Ericson2314): Don't want to mass-rebuild yet to keeping 'darwin' as 171 # the nnormalized name for macOS. 172 macos = { execFormat = macho; families = { inherit darwin; }; name = "darwin"; }; 173 ios = { execFormat = macho; families = { inherit darwin; }; }; 174 freebsd = { execFormat = elf; families = { inherit bsd; }; }; 175 linux = { execFormat = elf; families = { }; }; 176 netbsd = { execFormat = elf; families = { inherit bsd; }; }; 177 none = { execFormat = unknown; families = { }; }; 178 openbsd = { execFormat = elf; families = { inherit bsd; }; }; 179 solaris = { execFormat = elf; families = { }; }; 180 windows = { execFormat = pe; families = { }; }; 181 } // { # aliases 182 # 'darwin' is the kernel for all of them. We choose macOS by default. 183 darwin = kernels.macos; 184 watchos = kernels.ios; 185 tvos = kernels.ios; 186 win32 = kernels.windows; 187 }; 188 189 ################################################################################ 190 191 types.openAbi = mkOptionType { 192 name = "abi"; 193 description = "binary interface for compiled code and syscalls"; 194 merge = mergeOneOption; 195 }; 196 197 types.abi = enum (attrValues abis); 198 199 abis = setTypes types.openAbi { 200 cygnus = {}; 201 msvc = {}; 202 eabi = {}; 203 204 androideabi = {}; 205 android = { 206 assertions = [ 207 { assertion = platform: !platform.isAarch32; 208 message = '' 209 The "android" ABI is not for 32-bit ARM. Use "androideabi" instead. 210 ''; 211 } 212 ]; 213 }; 214 215 gnueabi = { float = "soft"; }; 216 gnueabihf = { float = "hard"; }; 217 gnu = { 218 assertions = [ 219 { assertion = platform: !platform.isAarch32; 220 message = '' 221 The "gnu" ABI is ambiguous on 32-bit ARM. Use "gnueabi" or "gnueabihf" instead. 222 ''; 223 } 224 ]; 225 }; 226 227 musleabi = { float = "soft"; }; 228 musleabihf = { float = "hard"; }; 229 musl = {}; 230 231 uclibceabihf = { float = "soft"; }; 232 uclibceabi = { float = "hard"; }; 233 uclibc = {}; 234 235 unknown = {}; 236 }; 237 238 ################################################################################ 239 240 types.parsedPlatform = mkOptionType { 241 name = "system"; 242 description = "fully parsed representation of llvm- or nix-style platform tuple"; 243 merge = mergeOneOption; 244 check = { cpu, vendor, kernel, abi }: 245 types.cpuType.check cpu 246 && types.vendor.check vendor 247 && types.kernel.check kernel 248 && types.abi.check abi; 249 }; 250 251 isSystem = isType "system"; 252 253 mkSystem = components: 254 assert types.parsedPlatform.check components; 255 setType "system" components; 256 257 mkSkeletonFromList = l: { 258 "2" = # We only do 2-part hacks for things Nix already supports 259 if elemAt l 1 == "cygwin" 260 then { cpu = elemAt l 0; kernel = "windows"; abi = "cygnus"; } 261 else { cpu = elemAt l 0; kernel = elemAt l 1; }; 262 "3" = # Awkwards hacks, beware! 263 if elemAt l 1 == "apple" 264 then { cpu = elemAt l 0; vendor = "apple"; kernel = elemAt l 2; } 265 else if (elemAt l 1 == "linux") || (elemAt l 2 == "gnu") 266 then { cpu = elemAt l 0; kernel = elemAt l 1; abi = elemAt l 2; } 267 else if (elemAt l 2 == "mingw32") # autotools breaks on -gnu for window 268 then { cpu = elemAt l 0; vendor = elemAt l 1; kernel = "windows"; abi = "gnu"; } 269 else if hasPrefix "netbsd" (elemAt l 2) 270 then { cpu = elemAt l 0; vendor = elemAt l 1; kernel = elemAt l 2; } 271 else throw "Target specification with 3 components is ambiguous"; 272 "4" = { cpu = elemAt l 0; vendor = elemAt l 1; kernel = elemAt l 2; abi = elemAt l 3; }; 273 }.${toString (length l)} 274 or (throw "system string has invalid number of hyphen-separated components"); 275 276 # This should revert the job done by config.guess from the gcc compiler. 277 mkSystemFromSkeleton = { cpu 278 , # Optional, but fallback too complex for here. 279 # Inferred below instead. 280 vendor ? assert false; null 281 , kernel 282 , # Also inferred below 283 abi ? assert false; null 284 } @ args: let 285 getCpu = name: cpuTypes.${name} or (throw "Unknown CPU type: ${name}"); 286 getVendor = name: vendors.${name} or (throw "Unknown vendor: ${name}"); 287 getKernel = name: kernels.${name} or (throw "Unknown kernel: ${name}"); 288 getAbi = name: abis.${name} or (throw "Unknown ABI: ${name}"); 289 290 parsed = rec { 291 cpu = getCpu args.cpu; 292 vendor = 293 /**/ if args ? vendor then getVendor args.vendor 294 else if isDarwin parsed then vendors.apple 295 else if isWindows parsed then vendors.pc 296 else vendors.unknown; 297 kernel = if hasPrefix "darwin" args.kernel then getKernel "darwin" 298 else if hasPrefix "netbsd" args.kernel then getKernel "netbsd" 299 else getKernel args.kernel; 300 abi = 301 /**/ if args ? abi then getAbi args.abi 302 else if isLinux parsed then 303 if isAarch32 parsed then 304 if lib.versionAtLeast (parsed.cpu.version or "0") "6" 305 then abis.gnueabihf 306 else abis.gnueabi 307 else abis.gnu 308 else if isWindows parsed then abis.gnu 309 else abis.unknown; 310 }; 311 312 in mkSystem parsed; 313 314 mkSystemFromString = s: mkSystemFromSkeleton (mkSkeletonFromList (lib.splitString "-" s)); 315 316 doubleFromSystem = { cpu, vendor, kernel, abi, ... }: 317 /**/ if abi == abis.cygnus then "${cpu.name}-cygwin" 318 else if kernel.families ? darwin then "${cpu.name}-darwin" 319 else "${cpu.name}-${kernel.name}"; 320 321 tripleFromSystem = { cpu, vendor, kernel, abi, ... } @ sys: assert isSystem sys; let 322 optAbi = lib.optionalString (abi != abis.unknown) "-${abi.name}"; 323 in "${cpu.name}-${vendor.name}-${kernel.name}${optAbi}"; 324 325 ################################################################################ 326 327}