diff --git a/foundation/flake.lock b/foundation/flake.lock index 6592f75..4e69788 100644 --- a/foundation/flake.lock +++ b/foundation/flake.lock @@ -3,10 +3,10 @@ "lib": { "locked": { "dir": "lib", - "dirtyRev": "f24f0876a9103c7adb8120ce9709fb90c73f2a7c-dirty", - "dirtyShortRev": "f24f087-dirty", - "lastModified": 1718105966, - "narHash": "sha256-L68G29+bPmwZSERg3VYXdfont/w+mssmWnrs6tyBijk=", + "dirtyRev": "9c29945531c58ad81f05cd1f4958c8894a733216-dirty", + "dirtyShortRev": "9c29945-dirty", + "lastModified": 1718255029, + "narHash": "sha256-iPMsyNszFA+EzjtIpjmu9EAG7zdjLbuugLtfa64dJos=", "type": "git", "url": "file:../?dir=lib" }, diff --git a/lib/src/modules/default.nix b/lib/src/modules/default.nix index e1b7f3b..2df9967 100644 --- a/lib/src/modules/default.nix +++ b/lib/src/modules/default.nix @@ -187,7 +187,7 @@ lib: { in withFreeform (withMeta base); } - else builtins.throw "Module `${key}` has unsupported attribute(s): ${invalidKeys}"; + else builtins.throw "Module `${key}` (${file}) has unsupported attribute(s): ${invalidKeys}"; ## Convert a module that is either a function or an attribute set into ## a resolved attribute set. If the module was a function then it will @@ -428,7 +428,7 @@ lib: { matched = lib.options.run location option definitions'; unmatched = []; } - else builtins.throw "The option `${lib.options.getIdentifier location}` in module `${(builtins.head optionDeclarations).__file__}` does not support nested options." + else builtins.throw "The option `${lib.options.getIdentifier location}` in module `${(builtins.head optionDeclarations).__file__}` would be a parent of the following options, but its type `${(builtins.head optionDeclarations).options.type.description or ""}` does not support nested options." else process location declarations definitions ) declarationsByName; @@ -611,7 +611,7 @@ lib: { collected = collect (args.path or "") - (modules ++ [internal]) + ([internal] ++ modules) ( { inherit options config; @@ -625,7 +625,8 @@ lib: { // args ); in - lib.modules.combine prefix (lib.lists.reverse collected); + lib.modules.combine + prefix (lib.lists.reverse collected); options = merged.matched; diff --git a/lib/src/modules/default.test.nix b/lib/src/modules/default.test.nix index b92d74b..9b0bacc 100644 --- a/lib/src/modules/default.test.nix +++ b/lib/src/modules/default.test.nix @@ -423,5 +423,36 @@ in { }; in evaluated.config.aux.message == expected; + + "submodules" = let + expected = "Hello, World!"; + evaluated = lib.modules.run { + modules = [ + { + options = { + aux = lib.options.create { + default.value = { + message = "hi"; + }; + type = lib.types.attrs.of (lib.types.submodule ({name}: { + # freeform = lib.types.any; + options.message = lib.options.create { + type = lib.types.string; + }; + })); + }; + }; + config = { + aux = { + x = { + message = "Hello, World!"; + }; + }; + }; + } + ]; + }; + in + evaluated.config.aux.x.message == expected; }; } diff --git a/lib/src/types/default.nix b/lib/src/types/default.nix index 050d0b1..3847370 100644 --- a/lib/src/types/default.nix +++ b/lib/src/types/default.nix @@ -750,10 +750,16 @@ lib: { description ? null, }: let getModules = builtins.map ( - definition: { - __file__ = definition.__file__; - includes = [definition.value]; - } + definition: + if builtins.isAttrs definition + then { + __file__ = definition.__file__; + config = definition.value; + } + else { + __file__ = definition.__file__; + includes = [definition.value]; + } ); base = lib.modules.run { @@ -762,9 +768,6 @@ lib: { modules = [ { - options.__module__.args.dynamic.name = lib.options.create { - type = lib.types.string; - }; config.__module__.args.dynamic.name = lib.modules.overrides.default ""; } ] @@ -989,7 +992,7 @@ lib: { ## @type List Attrs -> Attrs one = types: let first = builtins.elemAt types 0; - rest = lib.lists.tail types; + rest = builtins.tail types; in if types == [] then builtins.throw "lib.types.one must be given at least one type" diff --git a/potluck/default.nix b/potluck/default.nix index c9dfa6b..2c2f8d9 100644 --- a/potluck/default.nix +++ b/potluck/default.nix @@ -10,21 +10,24 @@ ++ [ ./src/export.nix { - __file__ = ./default.nix; + __file__ = "broken"; - options.packages.aux = { - foundation = lib.options.create { - type = lib.types.attrs.of lib.types.package; - internal = true; - description = "The foundational packages used to construct the larger package set."; - }; - }; + # options.foundation = lib.options.create { + # type = lib.types.attrs.of lib.types.derivation; + # }; - config.packages.aux = { - foundation = foundation; - }; + # config.foundation = foundation; + config.packages.foundation = + builtins.mapAttrs (name: package: { + name = package.name; + + inherit package; + + meta = package.meta; + }) + foundation; } ]; }; in - result.config.exported + result.config diff --git a/potluck/flake.lock b/potluck/flake.lock index 44909b5..32c0ec0 100644 --- a/potluck/flake.lock +++ b/potluck/flake.lock @@ -8,10 +8,10 @@ }, "locked": { "dir": "foundation", - "dirtyRev": "cd12786be17a611976b44fbba3e245eca512535f-dirty", - "dirtyShortRev": "cd12786-dirty", - "lastModified": 1718199069, - "narHash": "sha256-H2Mkyp9BPDPte+E++uIG2N/vGtcS3H9Q7tM3fOOEXT0=", + "dirtyRev": "9c29945531c58ad81f05cd1f4958c8894a733216-dirty", + "dirtyShortRev": "9c29945-dirty", + "lastModified": 1718255029, + "narHash": "sha256-fmrDe4GfvVfXZ9lzaOt+tgBUMFCsyKr0Dlnm8aQwAXs=", "type": "git", "url": "file:../?dir=foundation" }, @@ -24,10 +24,10 @@ "lib": { "locked": { "dir": "lib", - "dirtyRev": "cd12786be17a611976b44fbba3e245eca512535f-dirty", - "dirtyShortRev": "cd12786-dirty", - "lastModified": 1718199069, - "narHash": "sha256-H2Mkyp9BPDPte+E++uIG2N/vGtcS3H9Q7tM3fOOEXT0=", + "dirtyRev": "9c29945531c58ad81f05cd1f4958c8894a733216-dirty", + "dirtyShortRev": "9c29945-dirty", + "lastModified": 1718255029, + "narHash": "sha256-fmrDe4GfvVfXZ9lzaOt+tgBUMFCsyKr0Dlnm8aQwAXs=", "type": "git", "url": "file:../?dir=lib" }, diff --git a/potluck/src/exports/modules.nix b/potluck/src/exports/modules.nix index ed70ee1..69f9f36 100644 --- a/potluck/src/exports/modules.nix +++ b/potluck/src/exports/modules.nix @@ -2,7 +2,7 @@ lib, config, }: let - cfg = config.exports.modules; + cfg = config.exports; type = lib.types.one [ lib.types.path diff --git a/potluck/src/exports/packages.nix b/potluck/src/exports/packages.nix index 96f6ba1..d442ed2 100644 --- a/potluck/src/exports/packages.nix +++ b/potluck/src/exports/packages.nix @@ -2,6 +2,7 @@ config, lib, }: let + lib' = config.lib; in { options = { exports.packages = lib.options.create { @@ -14,6 +15,8 @@ in { }; config = { - exported.packages = {}; + exported.packages = { + # i686-linux = config.packages.foundation; + }; }; } diff --git a/potluck/src/lib/systems.nix b/potluck/src/lib/systems.nix index 480b37f..cc12b17 100644 --- a/potluck/src/lib/systems.nix +++ b/potluck/src/lib/systems.nix @@ -16,11 +16,812 @@ if builtins.isList patterns then value: builtins.any (pattern: lib.attrs.match pattern value) patterns else lib.attrs.match patterns; + + getDoubles = predicate: + builtins.map + lib'.systems.into.double + (builtins.filter predicate lib'.systems.doubles.all); in { config = { lib.systems = { match = builtins.mapAttrs (lib.fp.const matchAnyAttrs) lib'.systems.patterns; + platforms = { + pc = { + linux-kernel = { + name = "pc"; + + baseConfig = "defconfig"; + # Build whatever possible as a module, if not stated in the extra config. + autoModules = true; + target = "bzImage"; + }; + }; + + pc_simplekernel = lib.attrs.mergeRecursive lib'.systems.platforms.pc { + linux-kernel.autoModules = false; + }; + + powernv = { + linux-kernel = { + name = "PowerNV"; + + baseConfig = "powernv_defconfig"; + target = "vmlinux"; + autoModules = true; + # avoid driver/FS trouble arising from unusual page size + extraConfig = '' + PPC_64K_PAGES n + PPC_4K_PAGES y + IPV6 y + + ATA_BMDMA y + ATA_SFF y + VIRTIO_MENU y + ''; + }; + }; + + ## + ## ARM + ## + + pogoplug4 = { + linux-kernel = { + name = "pogoplug4"; + + baseConfig = "multi_v5_defconfig"; + autoModules = false; + extraConfig = '' + # Ubi for the mtd + MTD_UBI y + UBIFS_FS y + UBIFS_FS_XATTR y + UBIFS_FS_ADVANCED_COMPR y + UBIFS_FS_LZO y + UBIFS_FS_ZLIB y + UBIFS_FS_DEBUG n + ''; + makeFlags = ["LOADADDR=0x8000"]; + target = "uImage"; + # TODO reenable once manual-config's config actually builds a .dtb and this is checked to be working + #DTB = true; + }; + gcc = { + arch = "armv5te"; + }; + }; + + sheevaplug = { + linux-kernel = { + name = "sheevaplug"; + + baseConfig = "multi_v5_defconfig"; + autoModules = false; + extraConfig = '' + BLK_DEV_RAM y + BLK_DEV_INITRD y + BLK_DEV_CRYPTOLOOP m + BLK_DEV_DM m + DM_CRYPT m + MD y + REISERFS_FS m + BTRFS_FS m + XFS_FS m + JFS_FS m + EXT4_FS m + USB_STORAGE_CYPRESS_ATACB m + + # mv cesa requires this sw fallback, for mv-sha1 + CRYPTO_SHA1 y + # Fast crypto + CRYPTO_TWOFISH y + CRYPTO_TWOFISH_COMMON y + CRYPTO_BLOWFISH y + CRYPTO_BLOWFISH_COMMON y + + IP_PNP y + IP_PNP_DHCP y + NFS_FS y + ROOT_NFS y + TUN m + NFS_V4 y + NFS_V4_1 y + NFS_FSCACHE y + NFSD m + NFSD_V2_ACL y + NFSD_V3 y + NFSD_V3_ACL y + NFSD_V4 y + NETFILTER y + IP_NF_IPTABLES y + IP_NF_FILTER y + IP_NF_MATCH_ADDRTYPE y + IP_NF_TARGET_LOG y + IP_NF_MANGLE y + IPV6 m + VLAN_8021Q m + + CIFS y + CIFS_XATTR y + CIFS_POSIX y + CIFS_FSCACHE y + CIFS_ACL y + + WATCHDOG y + WATCHDOG_CORE y + ORION_WATCHDOG m + + ZRAM m + NETCONSOLE m + + # Disable OABI to have seccomp_filter (required for systemd) + # https://github.com/raspberrypi/firmware/issues/651 + OABI_COMPAT n + + # Fail to build + DRM n + SCSI_ADVANSYS n + USB_ISP1362_HCD n + SND_SOC n + SND_ALI5451 n + FB_SAVAGE n + SCSI_NSP32 n + ATA_SFF n + SUNGEM n + IRDA n + ATM_HE n + SCSI_ACARD n + BLK_DEV_CMD640_ENHANCED n + + FUSE_FS m + + # systemd uses cgroups + CGROUPS y + + # Latencytop + LATENCYTOP y + + # Ubi for the mtd + MTD_UBI y + UBIFS_FS y + UBIFS_FS_XATTR y + UBIFS_FS_ADVANCED_COMPR y + UBIFS_FS_LZO y + UBIFS_FS_ZLIB y + UBIFS_FS_DEBUG n + + # Kdb, for kernel troubles + KGDB y + KGDB_SERIAL_CONSOLE y + KGDB_KDB y + ''; + makeFlags = ["LOADADDR=0x0200000"]; + target = "uImage"; + DTB = true; # Beyond 3.10 + }; + gcc = { + arch = "armv5te"; + }; + }; + + raspberrypi = { + linux-kernel = { + name = "raspberrypi"; + + baseConfig = "bcm2835_defconfig"; + DTB = true; + autoModules = true; + preferBuiltin = true; + extraConfig = '' + # Disable OABI to have seccomp_filter (required for systemd) + # https://github.com/raspberrypi/firmware/issues/651 + OABI_COMPAT n + ''; + target = "zImage"; + }; + gcc = { + arch = "armv6"; + fpu = "vfp"; + }; + }; + + # Legacy attribute, for compatibility with existing configs only. + raspberrypi2 = lib'.systems.platforms.armv7l-hf-multiplatform; + + # Nvidia Bluefield 2 (w. crypto support) + bluefield2 = { + gcc = { + arch = "armv8-a+fp+simd+crc+crypto"; + }; + }; + + zero-gravitas = { + linux-kernel = { + name = "zero-gravitas"; + + baseConfig = "zero-gravitas_defconfig"; + # Target verified by checking /boot on reMarkable 1 device + target = "zImage"; + autoModules = false; + DTB = true; + }; + gcc = { + fpu = "neon"; + cpu = "cortex-a9"; + }; + }; + + zero-sugar = { + linux-kernel = { + name = "zero-sugar"; + + baseConfig = "zero-sugar_defconfig"; + DTB = true; + autoModules = false; + preferBuiltin = true; + target = "zImage"; + }; + gcc = { + cpu = "cortex-a7"; + fpu = "neon-vfpv4"; + float-abi = "hard"; + }; + }; + + utilite = { + linux-kernel = { + name = "utilite"; + maseConfig = "multi_v7_defconfig"; + autoModules = false; + extraConfig = '' + # Ubi for the mtd + MTD_UBI y + UBIFS_FS y + UBIFS_FS_XATTR y + UBIFS_FS_ADVANCED_COMPR y + UBIFS_FS_LZO y + UBIFS_FS_ZLIB y + UBIFS_FS_DEBUG n + ''; + makeFlags = ["LOADADDR=0x10800000"]; + target = "uImage"; + DTB = true; + }; + gcc = { + cpu = "cortex-a9"; + fpu = "neon"; + }; + }; + + guruplug = lib.recursiveUpdate lib'.systems.platforms.sheevaplug { + # Define `CONFIG_MACH_GURUPLUG' (see + # ) + # and other GuruPlug-specific things. Requires the `guruplug-defconfig' + # patch. + linux-kernel.baseConfig = "guruplug_defconfig"; + }; + + beaglebone = lib.recursiveUpdate lib'.systems.platforms.armv7l-hf-multiplatform { + linux-kernel = { + name = "beaglebone"; + baseConfig = "bb.org_defconfig"; + autoModules = false; + extraConfig = ""; # TBD kernel config + target = "zImage"; + }; + }; + + # https://developer.android.com/ndk/guides/abis#v7a + armv7a-android = { + linux-kernel.name = "armeabi-v7a"; + gcc = { + arch = "armv7-a"; + float-abi = "softfp"; + fpu = "vfpv3-d16"; + }; + }; + + armv7l-hf-multiplatform = { + linux-kernel = { + name = "armv7l-hf-multiplatform"; + Major = "2.6"; # Using "2.6" enables 2.6 kernel syscalls in glibc. + baseConfig = "multi_v7_defconfig"; + DTB = true; + autoModules = true; + preferBuiltin = true; + target = "zImage"; + extraConfig = '' + # Serial port for Raspberry Pi 3. Wasn't included in ARMv7 defconfig + # until 4.17. + SERIAL_8250_BCM2835AUX y + SERIAL_8250_EXTENDED y + SERIAL_8250_SHARE_IRQ y + + # Hangs ODROID-XU4 + ARM_BIG_LITTLE_CPUIDLE n + + # Disable OABI to have seccomp_filter (required for systemd) + # https://github.com/raspberrypi/firmware/issues/651 + OABI_COMPAT n + + # >=5.12 fails with: + # drivers/net/ethernet/micrel/ks8851_common.o: in function `ks8851_probe_common': + # ks8851_common.c:(.text+0x179c): undefined reference to `__this_module' + # See: https://lore.kernel.org/netdev/20210116164828.40545-1-marex@denx.de/T/ + KS8851_MLL y + ''; + }; + gcc = { + # Some table about fpu flags: + # http://community.arm.com/servlet/JiveServlet/showImage/38-1981-3827/blogentry-103749-004812900+1365712953_thumb.png + # Cortex-A5: -mfpu=neon-fp16 + # Cortex-A7 (rpi2): -mfpu=neon-vfpv4 + # Cortex-A8 (beaglebone): -mfpu=neon + # Cortex-A9: -mfpu=neon-fp16 + # Cortex-A15: -mfpu=neon-vfpv4 + + # More about FPU: + # https://wiki.debian.org/ArmHardFloatPort/VfpComparison + + # vfpv3-d16 is what Debian uses and seems to be the best compromise: NEON is not supported in e.g. Scaleway or Tegra 2, + # and the above page suggests NEON is only an improvement with hand-written assembly. + arch = "armv7-a"; + fpu = "vfpv3-d16"; + + # For Raspberry Pi the 2 the best would be: + # cpu = "cortex-a7"; + # fpu = "neon-vfpv4"; + }; + }; + + aarch64-multiplatform = { + linux-kernel = { + name = "aarch64-multiplatform"; + baseConfig = "defconfig"; + DTB = true; + autoModules = true; + preferBuiltin = true; + extraConfig = '' + # Raspberry Pi 3 stuff. Not needed for s >= 4.10. + ARCH_BCM2835 y + BCM2835_MBOX y + BCM2835_WDT y + RASPBERRYPI_FIRMWARE y + RASPBERRYPI_POWER y + SERIAL_8250_BCM2835AUX y + SERIAL_8250_EXTENDED y + SERIAL_8250_SHARE_IRQ y + + # Cavium ThunderX stuff. + PCI_HOST_THUNDER_ECAM y + + # Nvidia Tegra stuff. + PCI_TEGRA y + + # The default (=y) forces us to have the XHCI firmware available in initrd, + # which our initrd builder can't currently do easily. + USB_XHCI_TEGRA m + ''; + target = "Image"; + }; + gcc = { + arch = "armv8-a"; + }; + }; + + apple-m1 = { + gcc = { + arch = "armv8.3-a+crypto+sha2+aes+crc+fp16+lse+simd+ras+rdm+rcpc"; + cpu = "apple-a13"; + }; + }; + + ## + ## MIPS + ## + + ben_nanonote = { + linux-kernel = { + name = "ben_nanonote"; + }; + gcc = { + arch = "mips32"; + float = "soft"; + }; + }; + + fuloong2f_n32 = { + linux-kernel = { + name = "fuloong2f_n32"; + baseConfig = "lemote2f_defconfig"; + autoModules = false; + extraConfig = '' + MIGRATION n + COMPACTION n + + # nixos mounts some cgroup + CGROUPS y + + BLK_DEV_RAM y + BLK_DEV_INITRD y + BLK_DEV_CRYPTOLOOP m + BLK_DEV_DM m + DM_CRYPT m + MD y + REISERFS_FS m + EXT4_FS m + USB_STORAGE_CYPRESS_ATACB m + + IP_PNP y + IP_PNP_DHCP y + IP_PNP_BOOTP y + NFS_FS y + ROOT_NFS y + TUN m + NFS_V4 y + NFS_V4_1 y + NFS_FSCACHE y + NFSD m + NFSD_V2_ACL y + NFSD_V3 y + NFSD_V3_ACL y + NFSD_V4 y + + # Fail to build + DRM n + SCSI_ADVANSYS n + USB_ISP1362_HCD n + SND_SOC n + SND_ALI5451 n + FB_SAVAGE n + SCSI_NSP32 n + ATA_SFF n + SUNGEM n + IRDA n + ATM_HE n + SCSI_ACARD n + BLK_DEV_CMD640_ENHANCED n + + FUSE_FS m + + # Needed for udev >= 150 + SYSFS_DEPRECATED_V2 n + + VGA_CONSOLE n + VT_HW_CONSOLE_BINDING y + SERIAL_8250_CONSOLE y + FRAMEBUFFER_CONSOLE y + EXT2_FS y + EXT3_FS y + REISERFS_FS y + MAGIC_SYSRQ y + + # The kernel doesn't boot at all, with FTRACE + FTRACE n + ''; + target = "vmlinux"; + }; + gcc = { + arch = "loongson2f"; + float = "hard"; + abi = "n32"; + }; + }; + + # can execute on 32bit chip + gcc_mips32r2_o32 = { + gcc = { + arch = "mips32r2"; + abi = "32"; + }; + }; + gcc_mips32r6_o32 = { + gcc = { + arch = "mips32r6"; + abi = "32"; + }; + }; + gcc_mips64r2_n32 = { + gcc = { + arch = "mips64r2"; + abi = "n32"; + }; + }; + gcc_mips64r6_n32 = { + gcc = { + arch = "mips64r6"; + abi = "n32"; + }; + }; + gcc_mips64r2_64 = { + gcc = { + arch = "mips64r2"; + abi = "64"; + }; + }; + gcc_mips64r6_64 = { + gcc = { + arch = "mips64r6"; + abi = "64"; + }; + }; + + # based on: + # https://www.mail-archive.com/qemu-discuss@nongnu.org/msg05179.html + # https://gmplib.org/~tege/qemu.html#mips64-debian + mips64el-qemu-linux-gnuabi64 = { + linux-kernel = { + name = "mips64el"; + baseConfig = "64r2el_defconfig"; + target = "vmlinuz"; + autoModules = false; + DTB = true; + # for qemu 9p passthrough filesystem + extraConfig = '' + MIPS_MALTA y + PAGE_SIZE_4KB y + CPU_LITTLE_ENDIAN y + CPU_MIPS64_R2 y + 64BIT y + CPU_MIPS64_R2 y + + NET_9P y + NET_9P_VIRTIO y + 9P_FS y + 9P_FS_POSIX_ACL y + PCI y + VIRTIO_PCI y + ''; + }; + }; + + ## + ## Other + ## + + riscv-multiplatform = { + linux-kernel = { + name = "riscv-multiplatform"; + target = "Image"; + autoModules = true; + baseConfig = "defconfig"; + DTB = true; + extraConfig = '' + SERIAL_OF_PLATFORM y + ''; + }; + }; + + mipsel-linux-gnu = + { + triple = "mipsel-unknown-linux-gnu"; + } + // lib'.systems.platforms.gcc_mips32r2_o32; + + # This function takes a minimally-valid "platform" and returns an + # attrset containing zero or more additional attrs which should be + # included in the platform in order to further elaborate it. + select = platform: + # x86 + /**/ + if platform.isx86 + then lib'.systems.platforms.pc + # ARM + else if platform.isAarch32 + then let + version = platform.system.cpu.version or null; + in + if version == null + then lib'.systems.platforms.pc + else if lib.versions.gte "6" version + then lib'.systems.platforms.sheevaplug + else if lib.versions.gte "7" version + then lib'.systems.platforms.raspberrypi + else lib'.systems.platforms.armv7l-hf-multiplatform + else if platform.isAarch64 + then + if platform.isDarwin + then lib'.systems.platforms.apple-m1 + else lib'.systems.platforms.aarch64-multiplatform + else if platform.isRiscV + then lib'.systems.platforms.riscv-multiplatform + else if platform.system.cpu == types.cpus.mipsel + then lib'.systems.platforms.mipsel-linux-gnu + else if platform.system.cpu == types.cpus.powerpc64le + then lib'.systems.platforms.powernv + else {}; + }; + + architectures = { + features = { + # x86_64 Generic + # Spec: https://gitlab.com/x86-psABIs/x86-64-ABI/ + default = []; + x86-64 = []; + x86-64-v2 = ["sse3" "ssse3" "sse4_1" "sse4_2"]; + x86-64-v3 = ["sse3" "ssse3" "sse4_1" "sse4_2" "avx" "avx2" "fma"]; + x86-64-v4 = ["sse3" "ssse3" "sse4_1" "sse4_2" "avx" "avx2" "avx512" "fma"]; + # x86_64 Intel + nehalem = ["sse3" "ssse3" "sse4_1" "sse4_2" "aes"]; + westmere = ["sse3" "ssse3" "sse4_1" "sse4_2" "aes"]; + sandybridge = ["sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx"]; + ivybridge = ["sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx"]; + haswell = ["sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "fma"]; + broadwell = ["sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "fma"]; + skylake = ["sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "fma"]; + skylake-avx512 = ["sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma"]; + cannonlake = ["sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma"]; + icelake-client = ["sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma"]; + icelake-server = ["sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma"]; + cascadelake = ["sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma"]; + cooperlake = ["sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma"]; + tigerlake = ["sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma"]; + alderlake = ["sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "fma"]; + # x86_64 AMD + btver1 = ["sse3" "ssse3" "sse4_1" "sse4_2"]; + btver2 = ["sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx"]; + bdver1 = ["sse3" "ssse3" "sse4_1" "sse4_2" "sse4a" "aes" "avx" "fma" "fma4"]; + bdver2 = ["sse3" "ssse3" "sse4_1" "sse4_2" "sse4a" "aes" "avx" "fma" "fma4"]; + bdver3 = ["sse3" "ssse3" "sse4_1" "sse4_2" "sse4a" "aes" "avx" "fma" "fma4"]; + bdver4 = ["sse3" "ssse3" "sse4_1" "sse4_2" "sse4a" "aes" "avx" "avx2" "fma" "fma4"]; + znver1 = ["sse3" "ssse3" "sse4_1" "sse4_2" "sse4a" "aes" "avx" "avx2" "fma"]; + znver2 = ["sse3" "ssse3" "sse4_1" "sse4_2" "sse4a" "aes" "avx" "avx2" "fma"]; + znver3 = ["sse3" "ssse3" "sse4_1" "sse4_2" "sse4a" "aes" "avx" "avx2" "fma"]; + znver4 = ["sse3" "ssse3" "sse4_1" "sse4_2" "sse4a" "aes" "avx" "avx2" "avx512" "fma"]; + # other + armv5te = []; + armv6 = []; + armv7-a = []; + armv8-a = []; + mips32 = []; + loongson2f = []; + }; + + # a superior CPU has all the features of an inferior and is able to build and test code for it + inferiors = { + # x86_64 Generic + default = []; + x86-64 = []; + x86-64-v2 = ["x86-64"]; + x86-64-v3 = ["x86-64-v2"] ++ lib'.systems.architectures.inferiors.x86-64-v2; + x86-64-v4 = ["x86-64-v3"] ++ lib'.systems.architectures.inferiors.x86-64-v3; + + # x86_64 Intel + # https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html + nehalem = ["x86-64-v2"] ++ lib'.systems.architectures.inferiors.x86-64-v2; + westmere = ["nehalem"] ++ lib'.systems.architectures.inferiors.nehalem; + sandybridge = ["westmere"] ++ lib'.systems.architectures.inferiors.westmere; + ivybridge = ["sandybridge"] ++ lib'.systems.architectures.inferiors.sandybridge; + + haswell = lib.unique (["ivybridge" "x86-64-v3"] ++ lib'.systems.architectures.inferiors.ivybridge ++ lib'.systems.architectures.inferiors.x86-64-v3); + broadwell = ["haswell"] ++ lib'.systems.architectures.inferiors.haswell; + skylake = ["broadwell"] ++ lib'.systems.architectures.inferiors.broadwell; + + skylake-avx512 = lib.unique (["skylake" "x86-64-v4"] ++ lib'.systems.architectures.inferiors.skylake ++ lib'.systems.architectures.inferiors.x86-64-v4); + cannonlake = ["skylake-avx512"] ++ lib'.systems.architectures.inferiors.skylake-avx512; + icelake-client = ["cannonlake"] ++ lib'.systems.architectures.inferiors.cannonlake; + icelake-server = ["icelake-client"] ++ lib'.systems.architectures.inferiors.icelake-client; + cascadelake = ["cannonlake"] ++ lib'.systems.architectures.inferiors.cannonlake; + cooperlake = ["cascadelake"] ++ lib'.systems.architectures.inferiors.cascadelake; + tigerlake = ["icelake-server"] ++ lib'.systems.architectures.inferiors.icelake-server; + + # CX16 does not exist on alderlake, while it does on nearly all other intel CPUs + alderlake = []; + + # x86_64 AMD + # TODO: fill this (need testing) + btver1 = []; + btver2 = []; + bdver1 = []; + bdver2 = []; + bdver3 = []; + bdver4 = []; + # Regarding `skylake` as inferior of `znver1`, there are reports of + # successful usage by Gentoo users and Phoronix benchmarking of different + # `-march` targets. + # + # The GCC documentation on extensions used and wikichip documentation + # regarding supperted extensions on znver1 and skylake was used to create + # this partial order. + # + # Note: + # + # - The successors of `skylake` (`cannonlake`, `icelake`, etc) use `avx512` + # which no current AMD Zen michroarch support. + # - `znver1` uses `ABM`, `CLZERO`, `CX16`, `MWAITX`, and `SSE4A` which no + # current Intel microarch support. + # + # https://www.phoronix.com/scan.php?page=article&item=amd-znver3-gcc11&num=1 + # https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html + # https://en.wikichip.org/wiki/amd/microarchitectures/zen + # https://en.wikichip.org/wiki/intel/microarchitectures/skylake + znver1 = ["skylake"] ++ lib'.systems.architectures.inferiors.skylake; # Includes haswell and x86-64-v3 + znver2 = ["znver1"] ++ lib'.systems.architectures.inferiors.znver1; + znver3 = ["znver2"] ++ lib'.systems.architectures.inferiors.znver2; + znver4 = lib.unique (["znver3" "x86-64-v4"] ++ lib'.systems.architectures.inferiors.znver3 ++ lib'.systems.architectures.inferiors.x86-64-v4); + + # other + armv5te = []; + armv6 = []; + armv7-a = []; + armv8-a = []; + mips32 = []; + loongson2f = []; + }; + }; + + validate = { + architecture = let + isSupported = feature: x: + builtins.elem feature (lib'.systems.architectures.features.${x} or []); + in { + sse3Support = isSupported "sse3"; + ssse3Support = isSupported "ssse3"; + sse4_1Support = isSupported "sse4_1"; + sse4_2Support = isSupported "sse4_2"; + sse4_aSupport = isSupported "sse4a"; + avxSupport = isSupported "avx"; + avx2Support = isSupported "avx2"; + avx512Support = isSupported "avx512"; + aesSupport = isSupported "aes"; + fmaSupport = isSupported "fma"; + fma4Support = isSupported "fma4"; + }; + + compatible = a: b: + lib.any lib.id [ + # x86 + (b == lib'.systems.types.cpus.i386 && lib'.systems.validate.compatible a lib'.systems.types.cpus.i486) + (b == lib'.systems.types.cpus.i486 && lib'.systems.validate.compatible a lib'.systems.types.cpus.i586) + (b == lib'.systems.types.cpus.i586 && lib'.systems.validate.compatible a lib'.systems.types.cpus.i686) + + # XXX: Not true in some cases. Like in WSL mode. + (b == lib'.systems.types.cpus.i686 && lib'.systems.validate.compatible a lib'.systems.types.cpus.x86_64) + + # ARMv4 + (b == lib'.systems.types.cpus.arm && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv5tel) + + # ARMv5 + (b == lib'.systems.types.cpus.armv5tel && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv6l) + + # ARMv6 + (b == lib'.systems.types.cpus.armv6l && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv6m) + (b == lib'.systems.types.cpus.armv6m && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv7l) + + # ARMv7 + (b == lib'.systems.types.cpus.armv7l && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv7a) + (b == lib'.systems.types.cpus.armv7l && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv7r) + (b == lib'.systems.types.cpus.armv7l && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv7m) + + # ARMv8 + (b == lib'.systems.types.cpus.aarch64 && a == lib'.systems.types.cpus.armv8a) + (b == lib'.systems.types.cpus.armv8a && lib'.systems.validate.compatible a lib'.systems.types.cpus.aarch64) + (b == lib'.systems.types.cpus.armv8r && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv8a) + (b == lib'.systems.types.cpus.armv8m && lib'.systems.validate.compatible a lib'.systems.types.cpus.armv8a) + + # PowerPC + (b == lib'.systems.types.cpus.powerpc && lib'.systems.validate.compatible a lib'.systems.types.cpus.powerpc64) + (b == lib'.systems.types.cpus.powerpcle && lib'.systems.validate.compatible a lib'.systems.types.cpus.powerpc64le) + + # MIPS + (b == lib'.systems.types.cpus.mips && lib'.systems.validate.compatible a lib'.systems.types.cpus.mips64) + (b == lib'.systems.types.cpus.mipsel && lib'.systems.validate.compatible a lib'.systems.types.cpus.mips64el) + + # RISCV + (b == lib'.systems.types.cpus.riscv32 && lib'.systems.validate.compatible a lib'.systems.types.cpus.riscv64) + + # SPARC + (b == lib'.systems.types.cpus.sparc && lib'.systems.validate.compatible a lib'.systems.types.cpus.sparc64) + + # WASM + (b == lib'.systems.types.cpus.wasm32 && lib'.systems.validate.compatible a lib'.systems.types.cpus.wasm64) + + # identity + (b == a) + ]; + }; + types = { generic = { endian = lib.types.create { @@ -920,6 +1721,467 @@ in { {cpu = {family = "x86";};} ]; }; + + doubles = { + resolved = builtins.map lib'.systems.from.string lib'.systems.doubles.all; + + all = [ + # Cygwin + "i686-cygwin" + "x86_64-cygwin" + + # Darwin + "x86_64-darwin" + "i686-darwin" + "aarch64-darwin" + "armv7a-darwin" + + # FreeBSD + "i686-freebsd13" + "x86_64-freebsd13" + + # Genode + "aarch64-genode" + "i686-genode" + "x86_64-genode" + + # illumos + "x86_64-solaris" + + # JS + "javascript-ghcjs" + + # Linux + "aarch64-linux" + "armv5tel-linux" + "armv6l-linux" + "armv7a-linux" + "armv7l-linux" + "i686-linux" + "loongarch64-linux" + "m68k-linux" + "microblaze-linux" + "microblazeel-linux" + "mips-linux" + "mips64-linux" + "mips64el-linux" + "mipsel-linux" + "powerpc64-linux" + "powerpc64le-linux" + "riscv32-linux" + "riscv64-linux" + "s390-linux" + "s390x-linux" + "x86_64-linux" + + # MMIXware + "mmix-mmixware" + + # NetBSD + "aarch64-netbsd" + "armv6l-netbsd" + "armv7a-netbsd" + "armv7l-netbsd" + "i686-netbsd" + "m68k-netbsd" + "mipsel-netbsd" + "powerpc-netbsd" + "riscv32-netbsd" + "riscv64-netbsd" + "x86_64-netbsd" + + # none + "aarch64_be-none" + "aarch64-none" + "arm-none" + "armv6l-none" + "avr-none" + "i686-none" + "microblaze-none" + "microblazeel-none" + "mips-none" + "mips64-none" + "msp430-none" + "or1k-none" + "m68k-none" + "powerpc-none" + "powerpcle-none" + "riscv32-none" + "riscv64-none" + "rx-none" + "s390-none" + "s390x-none" + "vc4-none" + "x86_64-none" + + # OpenBSD + "i686-openbsd" + "x86_64-openbsd" + + # Redox + "x86_64-redox" + + # WASI + "wasm64-wasi" + "wasm32-wasi" + + # Windows + "x86_64-windows" + "i686-windows" + ]; + + arm = getDoubles lib'.systems.match.isAarch32; + armv7 = getDoubles lib'.systems.match.isArmv7; + aarch64 = getDoubles lib'.systems.match.isAarch64; + x86 = getDoubles lib'.systems.match.isx86; + i686 = getDoubles lib'.systems.match.isi686; + x86_64 = getDoubles lib'.systems.match.isx86_64; + microblaze = getDoubles lib'.systems.match.isMicroBlaze; + mips = getDoubles lib'.systems.match.isMips; + mmix = getDoubles lib'.systems.match.isMmix; + power = getDoubles lib'.systems.match.isPower; + riscv = getDoubles lib'.systems.match.isRiscV; + riscv32 = getDoubles lib'.systems.match.isRiscV32; + riscv64 = getDoubles lib'.systems.match.isRiscV64; + rx = getDoubles lib'.systems.match.isRx; + vc4 = getDoubles lib'.systems.match.isVc4; + or1k = getDoubles lib'.systems.match.isOr1k; + m68k = getDoubles lib'.systems.match.isM68k; + s390 = getDoubles lib'.systems.match.isS390; + s390x = getDoubles lib'.systems.match.isS390x; + loongarch64 = getDoubles lib'.systems.match.isLoongArch64; + js = getDoubles lib'.systems.match.isJavaScript; + + bigEndian = getDoubles lib'.systems.match.isBigEndian; + littleEndian = getDoubles lib'.systems.match.isLittleEndian; + + cygwin = getDoubles lib'.systems.match.isCygwin; + darwin = getDoubles lib'.systems.match.isDarwin; + freebsd = getDoubles lib'.systems.match.isFreeBSD; + # Should be better, but MinGW is unclear. + gnu = + getDoubles (lib.attrs.match { + kernel = types.kernels.linux; + abi = types.abis.gnu; + }) + ++ getDoubles (lib.attrs.match { + kernel = types.kernels.linux; + abi = types.abis.gnueabi; + }) + ++ getDoubles (lib.attrs.match { + kernel = types.kernels.linux; + abi = types.abis.gnueabihf; + }) + ++ getDoubles (lib.attrs.match { + kernel = types.kernels.linux; + abi = types.abis.gnuabin32; + }) + ++ getDoubles (lib.attrs.match { + kernel = types.kernels.linux; + abi = types.abis.gnuabi64; + }) + ++ getDoubles (lib.attrs.match { + kernel = types.kernels.linux; + abi = types.abis.gnuabielfv1; + }) + ++ getDoubles (lib.attrs.match { + kernel = types.kernels.linux; + abi = types.abis.gnuabielfv2; + }); + illumos = getDoubles lib'.systems.match.isSunOS; + linux = getDoubles lib'.systems.match.isLinux; + netbsd = getDoubles lib'.systems.match.isNetBSD; + openbsd = getDoubles lib'.systems.match.isOpenBSD; + unix = getDoubles lib'.systems.match.isUnix; + wasi = getDoubles lib'.systems.match.isWasi; + redox = getDoubles lib'.systems.match.isRedox; + windows = getDoubles lib'.systems.match.isWindows; + genode = getDoubles lib'.systems.match.isGenode; + + embedded = getDoubles lib'.systems.match.isNone; + + mesaPlatforms = ["i686-linux" "x86_64-linux" "x86_64-darwin" "armv5tel-linux" "armv6l-linux" "armv7l-linux" "armv7a-linux" "aarch64-linux" "powerpc64-linux" "powerpc64le-linux" "aarch64-darwin" "riscv64-linux"]; + }; + + withBuildInfo = args: let + settings = + if builtins.isString args + then {system = args;} + else args; + + matchers = builtins.mapAttrs (name: match: match resolved.system) lib'.systems.match; + validators = builtins.mapAttrs (name: validate: validate (resolved.gcc.arch or "default")) lib'.systems.match.architecture; + + platformInfo = + { + linux-kernel = settings.linux-kernel or {}; + gcc = settings.gcc or {}; + rustc = settings.rustc or {}; + } + // lib'.systems.platforms.select resolved; + + resolved = + matchers + // validators + // platformInfo + // { + system = lib'.systems.from.string ( + if settings ? triple + then settings.triple + else settings.system + ); + + double = lib'.systems.into.double resolved.system; + triple = lib'.systems.into.triple resolved.system; + + isExecutable = platform: + (resolved.isAndroid == platform.isAndroid) + && resolved.system.kernel == platform.system.kernel + && lib'.systems.validate.compatible resolved.system.cpu platform.system.cpu; + + # The difference between `isStatic` and `hasSharedLibraries` is mainly the + # addition of the `staticMarker` (see make-derivation.nix). Some + # platforms, like embedded machines without a libc (e.g. arm-none-eabi) + # don't support dynamic linking, but don't get the `staticMarker`. + # `pkgsStatic` sets `isStatic=true`, so `pkgsStatic.hostPlatform` always + # has the `staticMarker`. + isStatic = resolved.isWasm || resolved.isRedox; + + # It is important that hasSharedLibraries==false when the platform has no + # dynamic library loader. Various tools (including the gcc build system) + # have knowledge of which platforms are incapable of dynamic linking, and + # will still build on/for those platforms with --enable-shared, but simply + # omit any `.so` build products such as libgcc_s.so. When that happens, + # it causes hard-to-troubleshoot build failures. + hasSharedLibraries = + !resolved.isStatic + && ( + # Linux (allows multiple libcs) + resolved.isAndroid + || resolved.isGnu + || resolved.isMusl + # BSDs + || resolved.isDarwin + || resolved.isSunOS + || resolved.isOpenBSD + || resolved.isFreeBSD + || resolved.isNetBSD + # Windows + || resolved.isCygwin + || resolved.isMinGW + ); + + libc = + if resolved.isDarwin + then "libSystem" + else if resolved.isMinGW + then "msvcrt" + else if resolved.isWasi + then "wasilibc" + else if resolved.isRedox + then "relibc" + else if resolved.isMusl + then "musl" + else if resolved.isUClibc + then "uclibc" + else if resolved.isAndroid + then "bionic" + else if resolved.isLinux + then "glibc" + else if resolved.isFreeBSD + then "fblibc" + else if resolved.isNetBSD + then "nblibc" + else if resolved.isAvr + then "avrlibc" + else if resolved.isGhcjs + then null + else if resolved.isNone + then "newlib" + else "native/impure"; + + linker = + if resolved.isDarwin + then "cctools" + else "bfd"; + + extensions = + (lib.attrs.when resolved.hasSharedLibraries { + shared = + if resolved.isDarwin + then ".dylib" + else if resolved.isWindows + then ".dll" + else ".so"; + }) + // { + static = + if resolved.isWindows + then ".lib" + else ".a"; + + library = + if resolved.isStatic + then resolved.extensions.static + else resolved.extensions.shared; + + executable = + if resolved.isWindows + then ".exe" + else ""; + }; + + uname = { + system = + if resolved.system.kernel.name == "linux" + then "Linux" + else if resolved.system.kernel.name == "windows" + then "Windows" + else if resolved.system.kernel.name == "darwin" + then "Darwin" + else if resolved.system.kernel.name == "netbsd" + then "NetBSD" + else if resolved.system.kernel.name == "freebsd" + then "FreeBSD" + else if resolved.system.kernel.name == "openbsd" + then "OpenBSD" + else if resolved.system.kernel.name == "wasi" + then "Wasi" + else if resolved.system.kernel.name == "redox" + then "Redox" + else if resolved.system.kernel.name == "redox" + then "Genode" + else null; + + processor = + if resolved.isPower64 + then "ppc64${lib.strings.when resolved.isLittleEndian "le"}" + else if resolved.isPower + then "ppc${lib.strings.when resolved.isLittleEndian "le"}" + else if resolved.isMips64 + then "mips64" + else resolved.system.cpu.name; + + release = null; + }; + + useAndroidPrebuilt = false; + useiOSPrebuilt = false; + + linux.arch = + if resolved.isAarch32 + then "arm" + else if resolved.isAarch64 + then "arm64" + else if resolved.isx86_32 + then "i386" + else if resolved.isx86_64 + then "x86_64" + # linux kernel does not distinguish microblaze/microblazeel + else if resolved.isMicroBlaze + then "microblaze" + else if resolved.isMips32 + then "mips" + else if resolved.isMips64 + then "mips" # linux kernel does not distinguish mips32/mips64 + else if resolved.isPower + then "powerpc" + else if resolved.isRiscV + then "riscv" + else if resolved.isS390 + then "s390" + else if resolved.isLoongArch64 + then "loongarch" + else resolved.system.cpu.name; + + uboot.arch = + if resolved.isx86_32 + then "x86" # not i386 + else if resolved.isMips64 + then "mips64" # uboot *does* distinguish between mips32/mips64 + else resolved.linuxArch; # other cases appear to agree with linuxArch + + qemu.arch = + if resolved.isAarch32 + then "arm" + else if resolved.isS390 && !resolved.isS390x + then null + else if resolved.isx86_64 + then "x86_64" + else if resolved.isx86 + then "i386" + else if resolved.isMips64n32 + then "mipsn32${lib.strings.when resolved.isLittleEndian "el"}" + else if resolved.isMips64 + then "mips64${lib.strings.when resolved.isLittleEndian "el"}" + else resolved.uname.processor; + + efi.arch = + if resolved.isx86_32 + then "ia32" + else if resolved.isx86_64 + then "x64" + else if resolved.isAarch32 + then "arm" + else if resolved.isAarch64 + then "aa64" + else resolved.system.cpu.name; + + darwin = { + arch = + if resolved.system.cpu.name == "armv7a" + then "armv7" + else if resolved.system.cpu.name == "aarch64" + then "arm64" + else resolved.system.cpu.name; + + platform = + if resolved.isMacOS + then "macos" + else if resolved.isiOS + then "ios" + else null; + + sdk = { + version = + resolved.darwinSdkVersion + or ( + if resolved.isAarch64 + then "11.0" + else "10.12" + ); + + min = resolved.darwin.sdk.version; + + variable = + if resolved.isMacOS + then "MACOSX_DEPLOYMENT_TARGET" + else if resolved.isiOS + then "IPHONEOS_DEPLOYMENT_TARGET" + else null; + }; + }; + } + // settings; + + assertions = + builtins.foldl' + ( + result: { + assertion, + message, + }: + if assertion resolved + then result + else builtins.throw message + ) + true + (resolved.system.abi.assertions or []); + in + assert resolved.useAndroidPrebuild -> resolved.isAndroid; + assert assertions; + # And finally, return the generated system info. + resolved; }; }; } diff --git a/potluck/src/lib/types.nix b/potluck/src/lib/types.nix index ab07b07..102694d 100644 --- a/potluck/src/lib/types.nix +++ b/potluck/src/lib/types.nix @@ -107,164 +107,354 @@ in { }; }; - package = lib.types.submodule ({config}: { - freeform = lib.types.any; + package = { + base = lib.types.submodule ({config}: { + freeform = lib.types.any; - options = { - name = lib.options.create { - type = lib.types.string; - default = { - value = "${config.pname}-${config.version or "unknown"}"; - text = "\${config.pname}-\${config.version}"; - }; - description = "The name of the package."; - }; - - pname = lib.options.create { - type = lib.types.nullish lib.types.string; - default.value = null; - description = "The name of the package."; - }; - - version = lib.options.create { - type = lib.types.nullish lib.types.string; - default.value = null; - description = "The version of the package."; - }; - - meta = lib.options.create { - type = lib'.types.meta; - default = { - text = "{ name = .pname; }"; - value = { - name = config.pname; + options = { + name = lib.options.create { + type = lib.types.string; + default = { + value = "${config.pname}-${config.version or "unknown"}"; + text = "\${config.pname}-\${config.version}"; }; - }; - description = "The metadata for the package."; - }; - - env = lib.options.create { - type = lib.types.attrs.of lib.types.string; - default.value = {}; - description = "Environment variables for the package's builder to use."; - }; - - phases = lib.options.create { - type = lib.types.dag.of ( - lib.types.either - lib.types.string - (lib.types.function lib.types.string) - ); - default.value = {}; - description = "Phases for the package's builder to use."; - }; - - platform = { - build = lib.options.create { - type = lib.types.string; - description = "The platform the package is built on."; + description = "The name of the package."; }; - host = lib.options.create { - type = lib.types.string; - description = "The platform the package is run on."; + pname = lib.options.create { + type = lib.types.nullish lib.types.string; + default.value = null; + description = "The name of the package."; }; - target = lib.options.create { - type = lib.types.string; - description = "The platform the package generates code for."; + version = lib.options.create { + type = lib.types.nullish lib.types.string; + default.value = null; + description = "The version of the package."; }; - }; - builder = lib.options.create { - type = lib'.types.builder; - description = "The builder for the package."; - }; - - package = lib.options.create { - type = lib.types.derivation; - default = { - value = config.builder.build config.builder config; - text = ""; - }; - description = "The package derivation."; - }; - - deps = { - build = { - only = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are only used in the build environment."; + meta = lib.options.create { + type = lib'.types.meta; + default = { + text = "{ name = .pname; }"; + value = { + name = config.pname; + }; }; + description = "The metadata for the package."; + }; + env = lib.options.create { + type = lib.types.attrs.of lib.types.string; + default.value = {}; + description = "Environment variables for the package's builder to use."; + }; + + phases = lib.options.create { + type = lib.types.dag.of ( + lib.types.either + lib.types.string + (lib.types.function lib.types.string) + ); + default.value = {}; + description = "Phases for the package's builder to use."; + }; + + platform = { build = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are created in the build environment and are run in the build environment."; + type = lib.types.nullish lib.types.string; + default.value = null; + description = "The platform the package is built on."; }; host = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are created in the build environment and are run in the host environment."; + type = lib.types.nullish lib.types.string; + default.value = null; + description = "The platform the package is run on."; }; target = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are created in the build environment and are run in the target environment."; + type = lib.types.nullish lib.types.string; + default.value = null; + description = "The platform the package generates code for."; }; }; - host = { - only = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are only used in the host environment."; + builder = lib.options.create { + type = lib'.types.builder; + description = "The builder for the package."; + }; + + package = lib.options.create { + type = lib.types.derivation; + default = { + value = config.builder.build config.builder config; + text = ""; + }; + description = "The package derivation."; + }; + + deps = { + build = { + only = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are only used in the build environment."; + }; + + build = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are created in the build environment and are run in the build environment."; + }; + + host = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are created in the build environment and are run in the host environment."; + }; + + target = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are created in the build environment and are run in the target environment."; + }; + }; + + host = { + only = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are only used in the host environment."; + }; + + host = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are run in the host environment."; + }; + + target = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are run in the host environment which produces code for the target environment."; + }; + }; + + target = { + only = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are only used in the target environment."; + }; + + target = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are run in the target environment."; + }; + }; + }; + + versions = lib.options.create { + type = lib.types.attrs.of lib'.types.package; + default.value = {}; + description = "Available versions of the package."; + }; + }; + }); + + targeted = lib.types.submodule ({config}: { + freeform = lib.types.any; + + options = { + name = lib.options.create { + type = lib.types.string; + default = { + value = "${config.pname}-${config.version or "unknown"}"; + text = "\${config.pname}-\${config.version}"; + }; + description = "The name of the package."; + }; + + pname = lib.options.create { + type = lib.types.nullish lib.types.string; + default.value = null; + description = "The name of the package."; + }; + + version = lib.options.create { + type = lib.types.nullish lib.types.string; + default.value = null; + description = "The version of the package."; + }; + + meta = lib.options.create { + type = lib'.types.meta; + default = { + text = "{ name = .pname; }"; + value = { + name = config.pname; + }; + }; + description = "The metadata for the package."; + }; + + env = lib.options.create { + type = lib.types.attrs.of lib.types.string; + default.value = {}; + description = "Environment variables for the package's builder to use."; + }; + + phases = lib.options.create { + type = lib.types.dag.of ( + lib.types.either + lib.types.string + (lib.types.function lib.types.string) + ); + default.value = {}; + description = "Phases for the package's builder to use."; + }; + + platform = { + build = lib.options.create { + type = lib.types.string; + description = "The platform the package is built on."; }; host = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are run in the host environment."; + type = lib.types.string; + description = "The platform the package is run on."; }; target = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are run in the host environment which produces code for the target environment."; + type = lib.types.string; + description = "The platform the package generates code for."; }; }; - target = { - only = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are only used in the target environment."; + builder = lib.options.create { + type = lib'.types.builder; + description = "The builder for the package."; + }; + + package = lib.options.create { + type = lib.types.derivation; + default = { + value = config.builder.build config.builder config; + text = ""; + }; + description = "The package derivation."; + }; + + deps = { + build = { + only = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are only used in the build environment."; + }; + + build = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are created in the build environment and are run in the build environment."; + }; + + host = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are created in the build environment and are run in the host environment."; + }; + + target = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are created in the build environment and are run in the target environment."; + }; }; - target = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are run in the target environment."; + host = { + only = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are only used in the host environment."; + }; + + host = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are run in the host environment."; + }; + + target = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are run in the host environment which produces code for the target environment."; + }; + }; + + target = { + only = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are only used in the target environment."; + }; + + target = lib.options.create { + type = lib'.types.dependencies; + default.value = {}; + description = "Dependencies which are run in the target environment."; + }; }; }; - }; - versions = lib.options.create { - type = lib.types.attrs.of lib'.types.package; - default.value = {}; - description = "Available versions of the package."; + versions = lib.options.create { + type = lib.types.attrs.of lib'.types.package; + default.value = {}; + description = "Available versions of the package."; + }; }; - }; - }); + }); + }; dependencies = lib.types.attrs.of (lib.types.nullish lib'.types.package); - packages = lib.types.attrs.of (lib.types.submodule { - freeform = lib.types.nullish lib'.types.package; - }); + packages = { + base = lib.types.attrs.of (lib.types.submodule { + freeform = lib'.types.package.base; + + # options = + # builtins.foldl' (result: system: { + # "${system}" = lib.options.create { + # type = lib'.types.packages.targeted; + # default.value = {}; + # description = "Packages for the architecture `${system}`"; + # }; + # }) {} + # lib'.systems.doubles.all; + }); + + targeted = lib.types.attrs.of (lib.types.submodule { + freeform = lib.types.nullish lib'.types.package.targeted; + + options = { + cross = lib.options.create { + type = lib'.types.packages.cross; + default.value = {}; + description = "Cross-compiled packages targeting another architecture."; + }; + }; + }); + + # Cross-compiled packages are accessed via + # packages.cross... + cross = lib.types.attrs.of (lib.types.submodule { + freeform = lib.types.attrs.of (lib.types.submodule { + freeform = lib.types.nullish lib'.types.package.targeted; + }); + }); + }; builder = lib.types.submodule { freeform = lib.types.any; diff --git a/potluck/src/modules.nix b/potluck/src/modules.nix index 3c39156..e2b06d9 100644 --- a/potluck/src/modules.nix +++ b/potluck/src/modules.nix @@ -1,4 +1,5 @@ { exports = ./exports; lib = ./lib; + packages = ./packages; } diff --git a/potluck/src/packages/default.nix b/potluck/src/packages/default.nix index 6a2b884..edb6465 100644 --- a/potluck/src/packages/default.nix +++ b/potluck/src/packages/default.nix @@ -3,19 +3,10 @@ config, }: let lib' = config.lib; - # configure = namespace: packages: - # builtins.mapAttrs - # (key: package: let - # name = - # if package.pname != null && package.version != null - # then "${package.pname}-${package.version}" - # else key; - # in { - # name = lib.modules.overrides.default name; - # package = lib.modules.overrides.default (package.builder package); - # }) - # packages; - # configs = builtins.mapAttrs configure config.packages; + + doubles = lib'.systems.doubles.all; + + generic = builtins.removeAttrs config.packages ["targeted"]; in { includes = [ # ./aux/foundation.nix @@ -23,9 +14,14 @@ in { options = { packages = lib.options.create { - type = lib'.types.packages; + default.value = {}; + type = lib.types.attrs.of (lib.types.submodule { + freeform = lib.types.any; + }); }; }; - # config = lib.modules.merge configs; + config = { + packages.targeted.i686-linux = generic; + }; }