at 18.03-beta 10 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"; }; 72 armv6l = { bits = 32; significantByte = littleEndian; family = "arm"; }; 73 armv7a = { bits = 32; significantByte = littleEndian; family = "arm"; }; 74 armv7l = { bits = 32; significantByte = littleEndian; family = "arm"; }; 75 aarch64 = { bits = 64; significantByte = littleEndian; family = "aarch64"; }; 76 i686 = { bits = 32; significantByte = littleEndian; family = "x86"; }; 77 x86_64 = { bits = 64; significantByte = littleEndian; family = "x86"; }; 78 mips = { bits = 32; significantByte = bigEndian; family = "mips"; }; 79 mipsel = { bits = 32; significantByte = littleEndian; family = "mips"; }; 80 mips64 = { bits = 64; significantByte = bigEndian; family = "mips"; }; 81 mips64el = { bits = 64; significantByte = littleEndian; family = "mips"; }; 82 powerpc = { bits = 32; significantByte = bigEndian; family = "power"; }; 83 riscv32 = { bits = 32; significantByte = littleEndian; family = "riscv"; }; 84 riscv64 = { bits = 64; significantByte = littleEndian; family = "riscv"; }; 85 wasm32 = { bits = 32; significantByte = littleEndian; family = "wasm"; }; 86 wasm64 = { bits = 64; significantByte = littleEndian; family = "wasm"; }; 87 }; 88 89 ################################################################################ 90 91 types.openVendor = mkOptionType { 92 name = "vendor"; 93 description = "vendor for the platform"; 94 merge = mergeOneOption; 95 }; 96 97 types.vendor = enum (attrValues vendors); 98 99 vendors = setTypes types.openVendor { 100 apple = {}; 101 pc = {}; 102 103 unknown = {}; 104 }; 105 106 ################################################################################ 107 108 types.openExecFormat = mkOptionType { 109 name = "exec-format"; 110 description = "executable container used by the kernel"; 111 merge = mergeOneOption; 112 }; 113 114 types.execFormat = enum (attrValues execFormats); 115 116 execFormats = setTypes types.openExecFormat { 117 aout = {}; # a.out 118 elf = {}; 119 macho = {}; 120 pe = {}; 121 122 unknown = {}; 123 }; 124 125 ################################################################################ 126 127 types.openKernelFamily = mkOptionType { 128 name = "exec-format"; 129 description = "executable container used by the kernel"; 130 merge = mergeOneOption; 131 }; 132 133 types.kernelFamily = enum (attrValues kernelFamilies); 134 135 kernelFamilies = setTypes types.openKernelFamily { 136 bsd = {}; 137 }; 138 139 ################################################################################ 140 141 types.openKernel = mkOptionType { 142 name = "kernel"; 143 description = "kernel name and information"; 144 merge = mergeOneOption; 145 check = x: types.execFormat.check x.execFormat 146 && all types.kernelFamily.check (attrValues x.families); 147 }; 148 149 types.kernel = enum (attrValues kernels); 150 151 kernels = with execFormats; with kernelFamilies; setTypes types.openKernel { 152 darwin = { execFormat = macho; families = { }; }; 153 freebsd = { execFormat = elf; families = { inherit bsd; }; }; 154 hurd = { execFormat = elf; families = { }; }; 155 linux = { execFormat = elf; families = { }; }; 156 netbsd = { execFormat = elf; families = { inherit bsd; }; }; 157 none = { execFormat = unknown; families = { }; }; 158 openbsd = { execFormat = elf; families = { inherit bsd; }; }; 159 solaris = { execFormat = elf; families = { }; }; 160 windows = { execFormat = pe; families = { }; }; 161 } // { # aliases 162 # TODO(@Ericson2314): Handle these Darwin version suffixes more generally. 163 darwin10 = kernels.darwin; 164 darwin14 = kernels.darwin; 165 win32 = kernels.windows; 166 }; 167 168 ################################################################################ 169 170 types.openAbi = mkOptionType { 171 name = "abi"; 172 description = "binary interface for compiled code and syscalls"; 173 merge = mergeOneOption; 174 }; 175 176 types.abi = enum (attrValues abis); 177 178 abis = setTypes types.openAbi { 179 android = {}; 180 cygnus = {}; 181 gnu = {}; 182 msvc = {}; 183 eabi = {}; 184 androideabi = {}; 185 gnueabi = {}; 186 gnueabihf = {}; 187 musleabi = {}; 188 musleabihf = {}; 189 musl = {}; 190 191 unknown = {}; 192 }; 193 194 ################################################################################ 195 196 types.system = mkOptionType { 197 name = "system"; 198 description = "fully parsed representation of llvm- or nix-style platform tuple"; 199 merge = mergeOneOption; 200 check = { cpu, vendor, kernel, abi }: 201 types.cpuType.check cpu 202 && types.vendor.check vendor 203 && types.kernel.check kernel 204 && types.abi.check abi; 205 }; 206 207 isSystem = isType "system"; 208 209 mkSystem = components: 210 assert types.system.check components; 211 setType "system" components; 212 213 mkSkeletonFromList = l: { 214 "2" = # We only do 2-part hacks for things Nix already supports 215 if elemAt l 1 == "cygwin" 216 then { cpu = elemAt l 0; kernel = "windows"; abi = "cygnus"; } 217 else if elemAt l 1 == "gnu" 218 then { cpu = elemAt l 0; kernel = "hurd"; abi = "gnu"; } 219 else { cpu = elemAt l 0; kernel = elemAt l 1; }; 220 "3" = # Awkwards hacks, beware! 221 if elemAt l 1 == "apple" 222 then { cpu = elemAt l 0; vendor = "apple"; kernel = elemAt l 2; } 223 else if (elemAt l 1 == "linux") || (elemAt l 2 == "gnu") 224 then { cpu = elemAt l 0; kernel = elemAt l 1; abi = elemAt l 2; } 225 else if (elemAt l 2 == "mingw32") # autotools breaks on -gnu for window 226 then { cpu = elemAt l 0; vendor = elemAt l 1; kernel = "windows"; abi = "gnu"; } 227 else throw "Target specification with 3 components is ambiguous"; 228 "4" = { cpu = elemAt l 0; vendor = elemAt l 1; kernel = elemAt l 2; abi = elemAt l 3; }; 229 }.${toString (length l)} 230 or (throw "system string has invalid number of hyphen-separated components"); 231 232 # This should revert the job done by config.guess from the gcc compiler. 233 mkSystemFromSkeleton = { cpu 234 , # Optional, but fallback too complex for here. 235 # Inferred below instead. 236 vendor ? assert false; null 237 , kernel 238 , # Also inferred below 239 abi ? assert false; null 240 } @ args: let 241 getCpu = name: cpuTypes.${name} or (throw "Unknown CPU type: ${name}"); 242 getVendor = name: vendors.${name} or (throw "Unknown vendor: ${name}"); 243 getKernel = name: kernels.${name} or (throw "Unknown kernel: ${name}"); 244 getAbi = name: abis.${name} or (throw "Unknown ABI: ${name}"); 245 246 parsed = rec { 247 cpu = getCpu args.cpu; 248 vendor = 249 /**/ if args ? vendor then getVendor args.vendor 250 else if isDarwin parsed then vendors.apple 251 else if isWindows parsed then vendors.pc 252 else vendors.unknown; 253 kernel = getKernel args.kernel; 254 abi = 255 /**/ if args ? abi then getAbi args.abi 256 else if isLinux parsed then abis.gnu 257 else if isWindows parsed then abis.gnu 258 else abis.unknown; 259 }; 260 261 in mkSystem parsed; 262 263 mkSystemFromString = s: mkSystemFromSkeleton (mkSkeletonFromList (lib.splitString "-" s)); 264 265 doubleFromSystem = { cpu, vendor, kernel, abi, ... }: 266 if abi == abis.cygnus 267 then "${cpu.name}-cygwin" 268 else "${cpu.name}-${kernel.name}"; 269 270 tripleFromSystem = { cpu, vendor, kernel, abi, ... } @ sys: assert isSystem sys; let 271 optAbi = lib.optionalString (abi != abis.unknown) "-${abi.name}"; 272 in "${cpu.name}-${vendor.name}-${kernel.name}${optAbi}"; 273 274 ################################################################################ 275 276}