Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
at release-18.03 299 lines 11 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 (import ./inspect.nix { inherit lib; }).predicates; 22 23let 24 inherit (lib.options) mergeOneOption; 25 26 setTypes = type: 27 mapAttrs (name: value: 28 assert type.check value; 29 setType type.name ({ inherit name; } // value)); 30 31in 32 33rec { 34 35 ################################################################################ 36 37 types.openSignifiantByte = mkOptionType { 38 name = "significant-byte"; 39 description = "Endianness"; 40 merge = mergeOneOption; 41 }; 42 43 types.significantByte = enum (attrValues significantBytes); 44 45 significantBytes = setTypes types.openSignifiantByte { 46 bigEndian = {}; 47 littleEndian = {}; 48 }; 49 50 ################################################################################ 51 52 # Reasonable power of 2 53 types.bitWidth = enum [ 8 16 32 64 128 ]; 54 55 ################################################################################ 56 57 types.openCpuType = mkOptionType { 58 name = "cpu-type"; 59 description = "instruction set architecture name and information"; 60 merge = mergeOneOption; 61 check = x: types.bitWidth.check x.bits 62 && (if 8 < x.bits 63 then types.significantByte.check x.significantByte 64 else !(x ? significantByte)); 65 }; 66 67 types.cpuType = enum (attrValues cpuTypes); 68 69 cpuTypes = with significantBytes; setTypes types.openCpuType { 70 arm = { bits = 32; significantByte = littleEndian; family = "arm"; }; 71 armv5tel = { bits = 32; significantByte = littleEndian; family = "arm"; version = "5"; }; 72 armv6m = { bits = 32; significantByte = littleEndian; family = "arm"; version = "6"; }; 73 armv6l = { bits = 32; significantByte = littleEndian; family = "arm"; version = "6"; }; 74 armv7a = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; }; 75 armv7r = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; }; 76 armv7m = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; }; 77 armv7l = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; }; 78 armv8a = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; }; 79 armv8r = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; }; 80 armv8m = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; }; 81 aarch64 = { bits = 64; significantByte = littleEndian; family = "arm"; version = "8"; }; 82 83 i686 = { bits = 32; significantByte = littleEndian; family = "x86"; }; 84 x86_64 = { bits = 64; significantByte = littleEndian; family = "x86"; }; 85 86 mips = { bits = 32; significantByte = bigEndian; family = "mips"; }; 87 mipsel = { bits = 32; significantByte = littleEndian; family = "mips"; }; 88 mips64 = { bits = 64; significantByte = bigEndian; family = "mips"; }; 89 mips64el = { bits = 64; significantByte = littleEndian; family = "mips"; }; 90 91 powerpc = { bits = 32; significantByte = bigEndian; family = "power"; }; 92 93 riscv32 = { bits = 32; significantByte = littleEndian; family = "riscv"; }; 94 riscv64 = { bits = 64; significantByte = littleEndian; family = "riscv"; }; 95 96 wasm32 = { bits = 32; significantByte = littleEndian; family = "wasm"; }; 97 wasm64 = { bits = 64; significantByte = littleEndian; family = "wasm"; }; 98 }; 99 100 ################################################################################ 101 102 types.openVendor = mkOptionType { 103 name = "vendor"; 104 description = "vendor for the platform"; 105 merge = mergeOneOption; 106 }; 107 108 types.vendor = enum (attrValues vendors); 109 110 vendors = setTypes types.openVendor { 111 apple = {}; 112 pc = {}; 113 114 unknown = {}; 115 }; 116 117 ################################################################################ 118 119 types.openExecFormat = mkOptionType { 120 name = "exec-format"; 121 description = "executable container used by the kernel"; 122 merge = mergeOneOption; 123 }; 124 125 types.execFormat = enum (attrValues execFormats); 126 127 execFormats = setTypes types.openExecFormat { 128 aout = {}; # a.out 129 elf = {}; 130 macho = {}; 131 pe = {}; 132 133 unknown = {}; 134 }; 135 136 ################################################################################ 137 138 types.openKernelFamily = mkOptionType { 139 name = "exec-format"; 140 description = "executable container used by the kernel"; 141 merge = mergeOneOption; 142 }; 143 144 types.kernelFamily = enum (attrValues kernelFamilies); 145 146 kernelFamilies = setTypes types.openKernelFamily { 147 bsd = {}; 148 }; 149 150 ################################################################################ 151 152 types.openKernel = mkOptionType { 153 name = "kernel"; 154 description = "kernel name and information"; 155 merge = mergeOneOption; 156 check = x: types.execFormat.check x.execFormat 157 && all types.kernelFamily.check (attrValues x.families); 158 }; 159 160 types.kernel = enum (attrValues kernels); 161 162 kernels = with execFormats; with kernelFamilies; setTypes types.openKernel { 163 darwin = { execFormat = macho; families = { }; }; 164 freebsd = { execFormat = elf; families = { inherit bsd; }; }; 165 hurd = { execFormat = elf; families = { }; }; 166 linux = { execFormat = elf; families = { }; }; 167 netbsd = { execFormat = elf; families = { inherit bsd; }; }; 168 none = { execFormat = unknown; families = { }; }; 169 openbsd = { execFormat = elf; families = { inherit bsd; }; }; 170 solaris = { execFormat = elf; families = { }; }; 171 windows = { execFormat = pe; families = { }; }; 172 } // { # aliases 173 # TODO(@Ericson2314): Handle these Darwin version suffixes more generally. 174 darwin10 = kernels.darwin; 175 darwin14 = kernels.darwin; 176 win32 = kernels.windows; 177 }; 178 179 ################################################################################ 180 181 types.openAbi = mkOptionType { 182 name = "abi"; 183 description = "binary interface for compiled code and syscalls"; 184 merge = mergeOneOption; 185 }; 186 187 types.abi = enum (attrValues abis); 188 189 abis = setTypes types.openAbi { 190 cygnus = {}; 191 msvc = {}; 192 eabi = {}; 193 194 androideabi = {}; 195 android = {}; 196 197 gnueabi = { float = "soft"; }; 198 gnueabihf = { float = "hard"; }; 199 gnu = {}; 200 201 musleabi = { float = "soft"; }; 202 musleabihf = { float = "hard"; }; 203 musl = {}; 204 205 uclibceabihf = { float = "soft"; }; 206 uclibceabi = { float = "hard"; }; 207 uclibc = {}; 208 209 unknown = {}; 210 }; 211 212 ################################################################################ 213 214 types.system = mkOptionType { 215 name = "system"; 216 description = "fully parsed representation of llvm- or nix-style platform tuple"; 217 merge = mergeOneOption; 218 check = { cpu, vendor, kernel, abi }: 219 types.cpuType.check cpu 220 && types.vendor.check vendor 221 && types.kernel.check kernel 222 && types.abi.check abi; 223 }; 224 225 isSystem = isType "system"; 226 227 mkSystem = components: 228 assert types.system.check components; 229 setType "system" components; 230 231 mkSkeletonFromList = l: { 232 "2" = # We only do 2-part hacks for things Nix already supports 233 if elemAt l 1 == "cygwin" 234 then { cpu = elemAt l 0; kernel = "windows"; abi = "cygnus"; } 235 else if elemAt l 1 == "gnu" 236 then { cpu = elemAt l 0; kernel = "hurd"; abi = "gnu"; } 237 else { cpu = elemAt l 0; kernel = elemAt l 1; }; 238 "3" = # Awkwards hacks, beware! 239 if elemAt l 1 == "apple" 240 then { cpu = elemAt l 0; vendor = "apple"; kernel = elemAt l 2; } 241 else if (elemAt l 1 == "linux") || (elemAt l 2 == "gnu") 242 then { cpu = elemAt l 0; kernel = elemAt l 1; abi = elemAt l 2; } 243 else if (elemAt l 2 == "mingw32") # autotools breaks on -gnu for window 244 then { cpu = elemAt l 0; vendor = elemAt l 1; kernel = "windows"; abi = "gnu"; } 245 else throw "Target specification with 3 components is ambiguous"; 246 "4" = { cpu = elemAt l 0; vendor = elemAt l 1; kernel = elemAt l 2; abi = elemAt l 3; }; 247 }.${toString (length l)} 248 or (throw "system string has invalid number of hyphen-separated components"); 249 250 # This should revert the job done by config.guess from the gcc compiler. 251 mkSystemFromSkeleton = { cpu 252 , # Optional, but fallback too complex for here. 253 # Inferred below instead. 254 vendor ? assert false; null 255 , kernel 256 , # Also inferred below 257 abi ? assert false; null 258 } @ args: let 259 getCpu = name: cpuTypes.${name} or (throw "Unknown CPU type: ${name}"); 260 getVendor = name: vendors.${name} or (throw "Unknown vendor: ${name}"); 261 getKernel = name: kernels.${name} or (throw "Unknown kernel: ${name}"); 262 getAbi = name: abis.${name} or (throw "Unknown ABI: ${name}"); 263 264 parsed = rec { 265 cpu = getCpu args.cpu; 266 vendor = 267 /**/ if args ? vendor then getVendor args.vendor 268 else if isDarwin parsed then vendors.apple 269 else if isWindows parsed then vendors.pc 270 else vendors.unknown; 271 kernel = getKernel args.kernel; 272 abi = 273 /**/ if args ? abi then getAbi args.abi 274 else if isLinux parsed then 275 if isAarch32 parsed then 276 if lib.versionAtLeast (parsed.cpu.version or "0") "6" 277 then abis.gnueabihf 278 else abis.gnueabi 279 else abis.gnu 280 else if isWindows parsed then abis.gnu 281 else abis.unknown; 282 }; 283 284 in mkSystem parsed; 285 286 mkSystemFromString = s: mkSystemFromSkeleton (mkSkeletonFromList (lib.splitString "-" s)); 287 288 doubleFromSystem = { cpu, vendor, kernel, abi, ... }: 289 if abi == abis.cygnus 290 then "${cpu.name}-cygwin" 291 else "${cpu.name}-${kernel.name}"; 292 293 tripleFromSystem = { cpu, vendor, kernel, abi, ... } @ sys: assert isSystem sys; let 294 optAbi = lib.optionalString (abi != abis.unknown) "-${abi.name}"; 295 in "${cpu.name}-${vendor.name}-${kernel.name}${optAbi}"; 296 297 ################################################################################ 298 299}