From 476550b876efd32cbe7417a550759934610caf5d Mon Sep 17 00:00:00 2001 From: Chris Andreae Date: Sat, 18 Sep 2021 20:38:30 +0900 Subject: [PATCH] Add build environment using Nix --- .gitattributes | 1 + README-NIX.md | 39 +++ default.nix | 51 ++++ nix/cmake-shell.nix | 17 ++ nix/generate-pin.rb | 34 +++ nix/manifest.json | 343 +++++++++++++++++++++++++ nix/pinned-nixpkgs.json | 4 + nix/pinned-nixpkgs.nix | 17 ++ nix/update-manifest/default.nix | 11 + nix/update-manifest/update-manifest.sh | 39 +++ nix/west-manifest.patch | 17 ++ nix/west-shell.nix | 50 ++++ nix/zephyr.nix | 52 ++++ nix/zmk.nix | 112 ++++++++ 14 files changed, 787 insertions(+) create mode 100644 README-NIX.md create mode 100644 default.nix create mode 100644 nix/cmake-shell.nix create mode 100755 nix/generate-pin.rb create mode 100644 nix/manifest.json create mode 100644 nix/pinned-nixpkgs.json create mode 100644 nix/pinned-nixpkgs.nix create mode 100644 nix/update-manifest/default.nix create mode 100755 nix/update-manifest/update-manifest.sh create mode 100644 nix/west-manifest.patch create mode 100644 nix/west-shell.nix create mode 100644 nix/zephyr.nix create mode 100644 nix/zmk.nix diff --git a/.gitattributes b/.gitattributes index 3d05d86d31a..af12493a041 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,3 +4,4 @@ # Docker on Windows. .bashrc text eol=lf *.sh text eol=lf +*.nix text eol=lf diff --git a/README-NIX.md b/README-NIX.md new file mode 100644 index 00000000000..a65c376a4a2 --- /dev/null +++ b/README-NIX.md @@ -0,0 +1,39 @@ +# Building Zephyrâ„¢ Mechanical Keyboard (ZMK) Firmware with Nix + +This extension is added by MoErgo for the Glove80 keyboard. + +Nix makes setup significantly easier. With this approach `west` is not needed. +You can however still choose to build using the standard Zephyr `west` toolchain +if you wish. + +# To build a target + +In ZMK root directory, + + nix-build -A *target* [-o *output_directory*] + +For example, + + nix-build -A glove80_left -o left + +The `output_directory` nix creates is a symlink. If you prefer not to rely on +symlink (perhaps because you are using WSL on Windows), you can make a copy of +the resulting `uf2` file using: + + cp -f $(nix-build -A *target* --no-out-link)/zmk.uf2 . + +# To build Glove80 + +In ZMK root directory, + + cp -f $(nix-build -A glove80_combined --no-out-link)/glove80.uf2 . + +# Adding new targets + +Edit default.nix and add an target based on zmk + +An example is: + + glove80_left = zmk.override { + board = "glove80_lh"; + }; diff --git a/default.nix b/default.nix new file mode 100644 index 00000000000..2a9f766e226 --- /dev/null +++ b/default.nix @@ -0,0 +1,51 @@ +{ pkgs ? (import ./nix/pinned-nixpkgs.nix {}) }: +let + inherit (pkgs) newScope; + inherit (pkgs.lib) makeScope; +in + +makeScope newScope (self: with self; { + west = pkgs.python3Packages.west.overrideAttrs(attrs: { + patches = (attrs.patches or []) ++ [./nix/west-manifest.patch]; + }); + + # To update the pinned Zephyr dependecies using west and update-manifest: + # nix shell -f . west -c west init -l app + # nix shell -f . west -c west update + # nix shell -f . update-manifest -c update-manifest > nix/manifest.json + # Note that any `group-filter` groups in west.yml need to be temporarily + # removed, as `west update-manifest` requires all dependencies to be fetched. + update-manifest = callPackage ./nix/update-manifest { inherit west; }; + + combine_uf2 = a: b: pkgs.runCommandNoCC "combined_${a.name}_${b.name}" {} + '' + mkdir -p $out + cat ${a}/zmk.uf2 ${b}/zmk.uf2 > $out/glove80.uf2 + ''; + + zephyr = callPackage ./nix/zephyr.nix { }; + + zmk = callPackage ./nix/zmk.nix { }; + + zmk_settings_reset = zmk.override { + shield = "settings_reset"; + }; + + glove80_left = zmk.override { + board = "glove80_lh"; + }; + + glove80_right = zmk.override { + board = "glove80_rh"; + }; + + glove80_combined = combine_uf2 glove80_left glove80_right; + + glove80_v0_left = zmk.override { + board = "glove80_v0_lh"; + }; + + glove80_v0_right = zmk.override { + board = "glove80_v0_rh"; + }; +}) diff --git a/nix/cmake-shell.nix b/nix/cmake-shell.nix new file mode 100644 index 00000000000..de68e6cf502 --- /dev/null +++ b/nix/cmake-shell.nix @@ -0,0 +1,17 @@ +{ pkgs ? (import ./pinned-nixpkgs.nix {}) }: + +let + zmkPkgs = (import ../default.nix { inherit pkgs; }); + inherit (zmkPkgs) zmk zephyr; + + zmkCmake = pkgs.writeShellScriptBin "zmk-cmake" '' + export PATH=${pkgs.lib.makeBinPath zmk.nativeBuildInputs}:$PATH + export CMAKE_PREFIX_PATH=${zephyr} + + cmake -G Ninja ${pkgs.lib.escapeShellArgs zmk.cmakeFlags} "-DUSER_CACHE_DIR=/tmp/.cache" "$@" + ''; +in +pkgs.stdenv.mkDerivation { + name = "zmk-cmake-shell"; + nativeBuildInputs = zmk.nativeBuildInputs ++ [zmkCmake]; +} diff --git a/nix/generate-pin.rb b/nix/generate-pin.rb new file mode 100755 index 00000000000..b6bf682dff2 --- /dev/null +++ b/nix/generate-pin.rb @@ -0,0 +1,34 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'json' +require 'net/http' +require 'shellwords' + +def get_channel_url(channel) + uri = URI("https://channels.nixos.org/#{channel}") + res = Net::HTTP.get_response(uri) + raise 'Not a redirect' unless res.is_a?(Net::HTTPRedirection) + res['location'] +end + +def fetch_tarball(url) + hash = `nix-prefetch-url --unpack #{Shellwords.escape(url)}` + raise 'Prefetch failed' unless $?.success? + hash.chomp +end + +def generate_pin(channel) + channel_url = get_channel_url(channel) + nixexprs = "#{channel_url}/nixexprs.tar.xz" + hash = fetch_tarball(nixexprs) + { url: nixexprs, sha256: hash } +end + +def main + channel = ENV.fetch('CHANNEL', 'nixpkgs-unstable') + pin = generate_pin(channel) + puts JSON.pretty_generate(pin) +end + +main diff --git a/nix/manifest.json b/nix/manifest.json new file mode 100644 index 00000000000..4a942ef6589 --- /dev/null +++ b/nix/manifest.json @@ -0,0 +1,343 @@ +[ + { + "name": "zephyr", + "url": "https://github.com/petejohanson/zephyr", + "revision": "339570e2393b108bf8f9241018ecaf5615c25469", + "clone-depth": 1, + "west-commands": "scripts/west-commands.yml", + "sha256": "0m4hcp2017zg8c637siv941976lc377hp4z5kkijxznlb4c3xi8s" + }, + { + "name": "chre", + "url": "https://github.com/zephyrproject-rtos/chre", + "revision": "ef76d3456db07e4959df555047d6962279528c8d", + "path": "modules/lib/chre", + "groups": ["optional"], + "sha256": "00jnv58slzgp4srmsamd7x34yf0hj1c6agmws4csv7w28013bwfm" + }, + { + "name": "lz4", + "url": "https://github.com/zephyrproject-rtos/lz4", + "revision": "8e303c264fc21c2116dc612658003a22e933124d", + "path": "modules/lib/lz4", + "groups": ["optional"], + "sha256": "1kqs7gxg17gvws01rir8p6gmzp54y12s1898lflhsb418122v8nf" + }, + { + "name": "nanopb", + "url": "https://github.com/zephyrproject-rtos/nanopb", + "revision": "dc4deed54fd4c7e1935e3b6387eedf21bb45dc38", + "path": "modules/lib/nanopb", + "groups": ["optional"], + "sha256": "0kmzh65hyhnl88w9x0rcdypj4nl1brbxrnzhy3flgxmhr564y05s" + }, + { + "name": "psa-arch-tests", + "url": "https://github.com/zephyrproject-rtos/psa-arch-tests", + "revision": "f4fc2442b8e29e2a03d9899e46e5a3ea3df8c2c9", + "path": "modules/tee/tf-m/psa-arch-tests", + "groups": ["optional"], + "sha256": "015qan6qfqyfc1lwpqb29zk1wxx02b6ng5wc1nfpfvknvhiwifay" + }, + { + "name": "sof", + "url": "https://github.com/zephyrproject-rtos/sof", + "revision": "c0f20b69daa44e3563f970b366e49ccfcfa1b71c", + "path": "modules/audio/sof", + "groups": ["optional"], + "sha256": "1ijad7xp9a5j5fc0sdmdrf0l2k3fc4dnw8ka3glp4ay52dhy04zx" + }, + { + "name": "tf-m-tests", + "url": "https://github.com/zephyrproject-rtos/tf-m-tests", + "revision": "c99a86b295c4887520da9d8402566d7f225c974e", + "path": "modules/tee/tf-m/tf-m-tests", + "groups": ["optional"], + "sha256": "0cc4029i9qfzq4vply9l2yjigaf9rq1zc6a44b8dc779kx31qx36" + }, + { + "name": "tflite-micro", + "url": "https://github.com/zephyrproject-rtos/tflite-micro", + "revision": "1a34dcab41e7e0e667db72d6a40999c1ec9c510c", + "path": "optional/modules/lib/tflite-micro", + "groups": ["optional"], + "sha256": "194k1wh4fx49vymc3dhmmsg8wfq4jjhsp00rsrmax5vfhy7fjsi6" + }, + { + "name": "thrift", + "url": "https://github.com/zephyrproject-rtos/thrift", + "revision": "10023645a0e6cb7ce23fcd7fd3dbac9f18df6234", + "path": "optional/modules/lib/thrift", + "groups": ["optional"], + "sha256": "1bpi64lk7sdidjqsq7rspbqk9k7z8s26mgg17c8sv6cr4h007raq" + }, + { + "name": "zscilib", + "url": "https://github.com/zephyrproject-rtos/zscilib", + "revision": "ca070ddabdaf67175a2da901d0bd62e8899371c5", + "path": "modules/lib/zscilib", + "groups": ["optional"], + "sha256": "1ss33lfz2xzz8b3fcnibz109x09lj9ajw3na8lsmhvn7mhg6zh3v" + }, + { + "name": "acpica", + "url": "https://github.com/zephyrproject-rtos/acpica", + "revision": "0333c2af13179f9b33d495cf7cb9a509f751cbb1", + "path": "modules/lib/acpica", + "sha256": "04864is6iisjfasvlwgfsmgnlihdg43cfcc3hpqkzb446x2ix4iw" + }, + { + "name": "canopennode", + "url": "https://github.com/zephyrproject-rtos/canopennode", + "revision": "dec12fa3f0d790cafa8414a4c2930ea71ab72ffd", + "path": "modules/lib/canopennode", + "sha256": "0x6l56q5zdrz78iarfwxiwc05wwq4krg9xhx1z8kjarkwf6q9f85" + }, + { + "name": "cmsis", + "url": "https://github.com/zephyrproject-rtos/cmsis", + "revision": "5a00331455dd74e31e80efa383a489faea0590e3", + "path": "modules/hal/cmsis", + "groups": ["hal"], + "sha256": "00zqyin7bn6jwp7kq51dfs7sinwj5dhx4s981gdm171mmx7rx06n" + }, + { + "name": "cmsis-dsp", + "url": "https://github.com/zephyrproject-rtos/cmsis-dsp", + "revision": "ff7b5fd1ea5f094665c090c343ec44e74dc0b193", + "path": "modules/lib/cmsis-dsp", + "sha256": "0ycznb30fmh35sz3gsg3gzdh9shk8ad90k4849lmx21jzxr6jrai" + }, + { + "name": "cmsis-nn", + "url": "https://github.com/zephyrproject-rtos/cmsis-nn", + "revision": "0c8669d81381ccf3b1a01d699f3b68b50134a99f", + "path": "modules/lib/cmsis-nn", + "sha256": "1bnlyklzlhjrx8b66y6fy9im9wipx4shkq3mla5k7iw7kn3kqs7z" + }, + { + "name": "fatfs", + "url": "https://github.com/zephyrproject-rtos/fatfs", + "revision": "427159bf95ea49b7680facffaa29ad506b42709b", + "path": "modules/fs/fatfs", + "groups": ["fs"], + "sha256": "1pj6ik1bdyn07zsm0006n818mjzpbhhpsca4cw5imw66mhjy2pg6" + }, + { + "name": "hal_ambiq", + "url": "https://github.com/zephyrproject-rtos/hal_ambiq", + "revision": "0a7c99325aa73a1ef777501da91c2c6608661e56", + "path": "modules/hal/ambiq", + "groups": ["hal"], + "sha256": "1s1xv746p7c1ccyp2j1b36hrm9pp7dlpb8v4fclpd6wl3jcdjj74" + }, + { + "name": "hal_atmel", + "url": "https://github.com/zephyrproject-rtos/hal_atmel", + "revision": "5ab43007eda3f380c125f957f03638d2e8d1144d", + "path": "modules/hal/atmel", + "groups": ["hal"], + "sha256": "0csnr0npgfraf4g11dn4f77ywm2qd80y65a12kx68f7bfm8flf9j" + }, + { + "name": "hal_ethos_u", + "url": "https://github.com/zephyrproject-rtos/hal_ethos_u", + "revision": "90ada2ea5681b2a2722a10d2898eac34c2510791", + "path": "modules/hal/ethos_u", + "groups": ["hal"], + "sha256": "12nv46xhi8v6k36l7qgmlsp58vc1d0zw5wqizv30acj5si2bz3y3" + }, + { + "name": "hal_gigadevice", + "url": "https://github.com/zephyrproject-rtos/hal_gigadevice", + "revision": "2994b7dde8b0b0fa9b9c0ccb13474b6a486cddc3", + "path": "modules/hal/gigadevice", + "groups": ["hal"], + "sha256": "16h3l09ikbb4sqql7nlnfdxqvsgcdywrwckf83r4mjs9pgxiq1qa" + }, + { + "name": "hal_intel", + "url": "https://github.com/zephyrproject-rtos/hal_intel", + "revision": "b3b43d4e3da7ba483611bbbea7ef8af92c69df31", + "path": "modules/hal/intel", + "groups": ["hal"], + "sha256": "1m2d0vwa2iip80rfzip8av41lga2p8zm0gzxhd6x11b3lq05vkb2" + }, + { + "name": "hal_nordic", + "url": "https://github.com/zephyrproject-rtos/hal_nordic", + "revision": "d054a315eb888ba70e09e5f6decd4097b0276d1f", + "path": "modules/hal/nordic", + "groups": ["hal"], + "sha256": "0ypny416ylb2w5jg4bg55xvfg0yhqlbrakzvm0w23lnamg49kd6j" + }, + { + "name": "hal_nuvoton", + "url": "https://github.com/zephyrproject-rtos/hal_nuvoton", + "revision": "3e0a4c4d3328b2f72b164219add19d5308b53cb5", + "path": "modules/hal/nuvoton", + "groups": ["hal"], + "sha256": "1xc1cr4c0d0zzmbdrfb7xr8zzq0aifki1l50wcrn9dsi9c1ww12g" + }, + { + "name": "hal_quicklogic", + "url": "https://github.com/zephyrproject-rtos/hal_quicklogic", + "revision": "b3a66fe6d04d87fd1533a5c8de51d0599fcd08d0", + "path": "modules/hal/quicklogic", + "groups": ["hal"], + "sha256": "0hk1x72kibaw3xkspy9822vh28ax3bk11b80qn8l4dwrm0wx34sy" + }, + { + "name": "hal_renesas", + "url": "https://github.com/zephyrproject-rtos/hal_renesas", + "revision": "a6cf2af9140e014fbbc48d2b6deb802231dd369f", + "path": "modules/hal/renesas", + "groups": ["hal"], + "sha256": "000dmd1z72n9blw1pdjskkpz978k3pa6fzg60lhcaj9y24kl9y6z" + }, + { + "name": "hal_rpi_pico", + "url": "https://github.com/zephyrproject-rtos/hal_rpi_pico", + "revision": "fba7162cc7bee06d0149622bbcaac4e41062d368", + "path": "modules/hal/rpi_pico", + "groups": ["hal"], + "sha256": "01q3rf427vvfl0hn3af84hmb3g78dnd8n6saddy7mljha0z0dzda" + }, + { + "name": "hal_stm32", + "url": "https://github.com/zephyrproject-rtos/hal_stm32", + "revision": "89ef0a3383edebf661073073bcdf6e2836fe90ee", + "path": "modules/hal/stm32", + "groups": ["hal"], + "sha256": "0z7q5xg1rn9c3anjvi2kl0hgik3y3r25svwf97w1cjhjx1rhqmpv" + }, + { + "name": "hal_telink", + "url": "https://github.com/zephyrproject-rtos/hal_telink", + "revision": "38573af589173259801ae6c2b34b7d4c9e626746", + "path": "modules/hal/telink", + "groups": ["hal"], + "sha256": "16lzqnzwl2ij0jvbg9x1cgh54kv76dbmpcn4xhd5m4wph3yix78z" + }, + { + "name": "hal_wurthelektronik", + "url": "https://github.com/zephyrproject-rtos/hal_wurthelektronik", + "revision": "24ca9873c3d608fad1fea0431836bc8f144c132e", + "path": "modules/hal/wurthelektronik", + "groups": ["hal"], + "sha256": "0s2b3j40b7qd85np46n4vh0zjmwymnpxd8r42nhss6xznn11g2h8" + }, + { + "name": "libmetal", + "url": "https://github.com/zephyrproject-rtos/libmetal", + "revision": "b91611a6f47dd29fb24c46e5621e797557f80ec6", + "path": "modules/hal/libmetal", + "groups": ["hal"], + "sha256": "0pj0g6zaxiylpdiizf03jil4q2sq1z9px7cfxlv95ddnbv6rjjcz" + }, + { + "name": "liblc3", + "url": "https://github.com/zephyrproject-rtos/liblc3", + "revision": "448f3de31f49a838988a162ef1e23a89ddf2d2ed", + "path": "modules/lib/liblc3", + "sha256": "07r923k1y05sq1sl9740z33cz64pqm2n7x8rr2ws460fij64aixp" + }, + { + "name": "littlefs", + "url": "https://github.com/zephyrproject-rtos/littlefs", + "revision": "ca583fd297ceb48bced3c2548600dc615d67af24", + "path": "modules/fs/littlefs", + "groups": ["fs"], + "sha256": "10xpjrnp5n1j1xbay2qwmg2w314fw9pgzv3kz1mn3pgadhckfgdn" + }, + { + "name": "lvgl", + "url": "https://github.com/zephyrproject-rtos/lvgl", + "revision": "8a6a2d1d29d17d1e4bdc94c243c146a39d635fdd", + "path": "modules/lib/gui/lvgl", + "sha256": "0rsmlh358f4g2yidak916pxhkgckfrnck2a5hcsh9larsdnsnf24" + }, + { + "name": "mbedtls", + "url": "https://github.com/zephyrproject-rtos/mbedtls", + "revision": "c38dc78d9a8dcbe43b898cc1171ab33ba3e6fc26", + "path": "modules/crypto/mbedtls", + "groups": ["crypto"], + "sha256": "0661myy0wjz38nypbyfw51x10mzg57syb5c28irblgjm2w25wbi7" + }, + { + "name": "mipi-sys-t", + "url": "https://github.com/zephyrproject-rtos/mipi-sys-t", + "revision": "a819419603a2dfcb47f7f39092e1bc112e45d1ef", + "path": "modules/debug/mipi-sys-t", + "groups": ["debug"], + "sha256": "1ba0h4p3n0ldk5pjilj7z2i62b09vjq6ma668rqpr3w2hrg6941v" + }, + { + "name": "nrf_hw_models", + "url": "https://github.com/zephyrproject-rtos/nrf_hw_models", + "revision": "f4595802d32d103718bf50b3d390b7a450895843", + "path": "modules/bsim_hw_models/nrf_hw_models", + "sha256": "04p6nfyrv38vq0dhdz0g11zqlrqhw43lydyyr06vlrijm0zja8p5" + }, + { + "name": "open-amp", + "url": "https://github.com/zephyrproject-rtos/open-amp", + "revision": "42b7c577714b8f22ce82a901e19c1814af4609a8", + "path": "modules/lib/open-amp", + "sha256": "0ch1iv4c3v3zx1l2clm4mawyd83kvxl3b5sd6m7r2sn6wpr456w9" + }, + { + "name": "percepio", + "url": "https://github.com/zephyrproject-rtos/percepio", + "revision": "a3728efccc47dd372f40e6313589ca4c5cc7d5e9", + "path": "modules/debug/percepio", + "groups": ["debug"], + "sha256": "0fhz6jwsni7s79p5pwmynxn4yzrr40yd8m51y20d8jf1ka6dh4gw" + }, + { + "name": "picolibc", + "url": "https://github.com/zephyrproject-rtos/picolibc", + "revision": "d07c38ff051386f8e09a143ea0a6c1d6d66dd1d8", + "path": "modules/lib/picolibc", + "sha256": "1pb4piwyib1mmqjyycq8xanvx9aps6mz4w2ijgrn1fjgfh5f7zpq" + }, + { + "name": "segger", + "url": "https://github.com/zephyrproject-rtos/segger", + "revision": "9d0191285956cef43daf411edc2f1a7788346def", + "path": "modules/debug/segger", + "groups": ["debug"], + "sha256": "11wbzyd2n006ygh72ixhqcmgn1yrzk3kq3c0piqvrfgqmv7p8yzn" + }, + { + "name": "tinycrypt", + "url": "https://github.com/zephyrproject-rtos/tinycrypt", + "revision": "3e9a49d2672ec01435ffbf0d788db6d95ef28de0", + "path": "modules/crypto/tinycrypt", + "groups": ["crypto"], + "sha256": "19d2q9y23yzz9i383q3cldjl3k5mryx9762cab23zy3ijdnmj2z6" + }, + { + "name": "trusted-firmware-a", + "url": "https://github.com/zephyrproject-rtos/trusted-firmware-a", + "revision": "421dc050278287839f5c70019bd6aec617f2bbdb", + "path": "modules/tee/tf-a/trusted-firmware-a", + "groups": ["tee"], + "sha256": "029sha3dpagbvfnk5h6ad69pvs5ahwps3cxkzbfrdbq2xm8x3j2y" + }, + { + "name": "uoscore-uedhoc", + "url": "https://github.com/zephyrproject-rtos/uoscore-uedhoc", + "revision": "5fe2cb613bd7e4590bd1b00c2adf181ac0229379", + "path": "modules/lib/uoscore-uedhoc", + "sha256": "0z31lbibkvhw5dfps4l7049gggfczh5qqfjb4s3csnr447m81gdd" + }, + { + "name": "zcbor", + "url": "https://github.com/zephyrproject-rtos/zcbor", + "revision": "67fd8bb88d3136738661fa8bb5f9989103f4599e", + "path": "modules/lib/zcbor", + "sha256": "16138k7xlahf63dfvplm8c2m0kxs1g17gcx1fa31y4gcfbi3b0k7" + } +] diff --git a/nix/pinned-nixpkgs.json b/nix/pinned-nixpkgs.json new file mode 100644 index 00000000000..d50315b0deb --- /dev/null +++ b/nix/pinned-nixpkgs.json @@ -0,0 +1,4 @@ +{ + "url": "https://releases.nixos.org/nixpkgs/nixpkgs-24.11pre640317.38d3352a65ac/nixexprs.tar.xz", + "sha256": "056jn02xbwdds0gwvnba6fq2lba7g5aa70qgc4by0fh4cyfa4phy" +} diff --git a/nix/pinned-nixpkgs.nix b/nix/pinned-nixpkgs.nix new file mode 100644 index 00000000000..c62cf91d1f9 --- /dev/null +++ b/nix/pinned-nixpkgs.nix @@ -0,0 +1,17 @@ +{ system ? builtins.currentSystem }: + +let + pin = builtins.fromJSON (builtins.readFile ./pinned-nixpkgs.json); + + nixpkgsSrc = builtins.fetchTarball { + inherit (pin) url sha256; + }; +in + +import nixpkgsSrc { + inherit system; + config = { + allowUnfree = true; + }; + overlays = []; # prevent impure overlays +} diff --git a/nix/update-manifest/default.nix b/nix/update-manifest/default.nix new file mode 100644 index 00000000000..eb858c16dbb --- /dev/null +++ b/nix/update-manifest/default.nix @@ -0,0 +1,11 @@ +{ runCommand, lib, makeWrapper, west, remarshal, nix-prefetch-git, jq, git }: + +runCommand "update-manifest" { + nativeBuildInputs = [ makeWrapper ]; +} '' + mkdir -p $out/bin $out/libexec + cp ${./update-manifest.sh} $out/libexec/update-manifest.sh + makeWrapper $out/libexec/update-manifest.sh $out/bin/update-manifest \ + --set PATH ${lib.makeBinPath [ west remarshal nix-prefetch-git jq git ]} + patchShebangs $out +'' diff --git a/nix/update-manifest/update-manifest.sh b/nix/update-manifest/update-manifest.sh new file mode 100755 index 00000000000..1f717a5a2b6 --- /dev/null +++ b/nix/update-manifest/update-manifest.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +set -euo pipefail + +ignored_modules=(hal_espressif sof tflite-micro thrift bsim babblesim babblesim_base \ + babblesim_ext_2G4_libPhyComv1 babblesim_ext_2G4_channel_NtNcable \ + babblesim_ext_2G4_channel_multiatt babblesim_ext_2G4_modem_magic \ + babblesim_ext_2G4_modem_BLE_simple babblesim_ext_2G4_device_burst_interferer \ + babblesim_ext_2G4_device_WLAN_actmod babblesim_ext_2G4_phy_v1 \ + babblesim_ext_2G4_device_playback babblesim_ext_libCryptov1) + +prefetch_project() { + local p=$1 + local name + name="$(jq -r .name <<< "$p")" + + if [[ " ${ignored_modules[*]} " =~ " ${name} " ]]; then + echo "Skipping: $name" >&2 + return + fi + + echo "Prefetching: $name" >&2 + + sha256=$(nix-prefetch-git \ + --quiet \ + --fetch-submodules \ + --url "$(jq -r .url <<< "$p")" \ + --rev "$(jq -r .revision <<< "$p")" \ + | jq -r .sha256) + + jq --arg sha256 "$sha256" '. + $ARGS.named' <<< "$p" +} + + +west manifest --freeze | \ + yaml2json | \ + jq -c '.manifest.projects[]' | \ + while read -r p; do prefetch_project "$p"; done | \ + jq --slurp diff --git a/nix/west-manifest.patch b/nix/west-manifest.patch new file mode 100644 index 00000000000..f6f82b75735 --- /dev/null +++ b/nix/west-manifest.patch @@ -0,0 +1,17 @@ +diff --git a/src/west/manifest.py b/src/west/manifest.py +index e28fade..f3d3784 100644 +--- a/src/west/manifest.py ++++ b/src/west/manifest.py +@@ -1618,8 +1618,10 @@ class Manifest: + ''' + def pdict(p): + if not p.is_cloned(): +- raise RuntimeError(f'cannot freeze; project {p.name} ' +- 'is uncloned') ++ # For the purposes of exporting a frozen manifest for Nix, this ++ # is sufficient, as a package whose revision is not represented ++ # as a SHA will fail the prefetch. ++ return Project.as_dict(p) + try: + sha = p.sha(QUAL_MANIFEST_REV_BRANCH) + except subprocess.CalledProcessError as e: diff --git a/nix/west-shell.nix b/nix/west-shell.nix new file mode 100644 index 00000000000..a9be5f8db62 --- /dev/null +++ b/nix/west-shell.nix @@ -0,0 +1,50 @@ +{ pkgs ? (import ./pinned-nixpkgs.nix {}) }: + +let + # from zephyr/scripts/requirements-base.txt + pythonDependencies = ps: with ps; [ + pyelftools + pyyaml + packaging + progress + anytree + intelhex + west + ]; + + requiredStdenv = + if pkgs.stdenv.hostPlatform.isLinux + then pkgs.multiStdenv + else pkgs.stdenv; +in +with pkgs; +# requires multiStdenv to build 32-bit test binaries +requiredStdenv.mkDerivation { + name = "zmk-shell"; + + buildInputs = [ + # ZMK dependencies + gitFull + wget + autoconf + automake + bzip2 + ccache + dtc # devicetree compiler + dfu-util + gcc + libtool + ninja + cmake + xz + (python3.withPackages(pythonDependencies)) + + # ARM toolchain + gcc-arm-embedded + ]; + + ZEPHYR_TOOLCHAIN_VARIANT = "gnuarmemb"; + GNUARMEMB_TOOLCHAIN_PATH = gcc-arm-embedded; + + shellHook = "if [ ! -d \"zephyr\" ]; then west init -l app/ ; west update; west zephyr-export; fi; source zephyr/zephyr-env.sh"; +} diff --git a/nix/zephyr.nix b/nix/zephyr.nix new file mode 100644 index 00000000000..d7c1bd05624 --- /dev/null +++ b/nix/zephyr.nix @@ -0,0 +1,52 @@ +{ stdenvNoCC, lib, fetchgit, runCommand }: +let + manifestJSON = builtins.fromJSON (builtins.readFile ./manifest.json); + + mkModule = { name, revision, url, sha256, ... }: + stdenvNoCC.mkDerivation (finalAttrs: { + name = "zmk-module-${name}"; + + src = fetchgit { + inherit name url sha256; + rev = revision; + }; + + dontUnpack = true; + dontBuild = true; + + installPhase = '' + mkdir $out + ln -s ${finalAttrs.src} $out/${name} + ''; + + passthru = { + modulePath = "${finalAttrs.finalPackage}/${name}"; + }; + }); + + modules = lib.listToAttrs (lib.forEach manifestJSON ({ name, ... }@args: + lib.nameValuePair name (mkModule args))); +in + + +# Zephyr with no modules, from the frozen manifest. +# For now the modules are passed through as passthru +stdenvNoCC.mkDerivation { + name = "zephyr"; + src = modules.zephyr.src; + + dontBuild = true; + + # This awkward structure is required by + # COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/../tools/uf2/utils/uf2conv.py + installPhase = '' + mkdir -p $out/zephyr + mv * $out/zephyr + + # uf2 is gone, not sure what replaced it + ''; + + passthru = { + modules = removeAttrs modules ["zephyr"]; + }; +} diff --git a/nix/zmk.nix b/nix/zmk.nix new file mode 100644 index 00000000000..c467f60fa2c --- /dev/null +++ b/nix/zmk.nix @@ -0,0 +1,112 @@ +{ stdenvNoCC, lib, buildPackages +, cmake, ninja, dtc, gcc-arm-embedded +, zephyr +, board ? "glove80_lh" +, shield ? null +, keymap ? null +, kconfig ? null +}: + + +let + # from zephyr/scripts/requirements-base.txt + packageOverrides = pyself: pysuper: { + can = pysuper.can.overrideAttrs (_: { + # horribly flaky test suite full of assertions about timing. + # > assert 0.1 <= took < inc(0.3) + # E assert 0.31151700019836426 < 0.3 + # E + where 0.3 = inc(0.3) + doCheck = false; + doInstallCheck = false; + }); + + canopen = pysuper.can.overrideAttrs (_: { + # Also has timing sensitive tests + # task = self.network.send_periodic(0x123, [1, 2, 3], 0.01) + # time.sleep(0.1) + # > self.assertTrue(9 <= bus.queue.qsize() <= 11) + # E AssertionError: False is not true + doCheck = false; + doInstallCheck = false; + }); + }; + + python = (buildPackages.python3.override { inherit packageOverrides; }).withPackages (ps: with ps; [ + pyelftools + pyyaml + canopen + packaging + progress + anytree + intelhex + + # TODO: this was required but not in shell.nix + pykwalify + ]); + + requiredZephyrModules = [ + "cmsis" "hal_nordic" "tinycrypt" "picolibc" "lvgl" "picolibc" "segger" + ]; + + zephyrModuleDeps = + let modules = lib.attrVals requiredZephyrModules zephyr.modules; + in map (x: x.modulePath) modules; +in + +stdenvNoCC.mkDerivation { + name = "zmk_${board}"; + + sourceRoot = "source/app"; + + src = builtins.path { + name = "source"; + path = ./..; + filter = path: type: + let relPath = lib.removePrefix (toString ./.. + "/") (toString path); + in (lib.cleanSourceFilter path type) && ! ( + # Meta files + relPath == "nix" || lib.hasSuffix ".nix" path || + # Transient state + relPath == "build" || relPath == ".west" || + # Fetched by west + relPath == "modules" || relPath == "tools" || relPath == "zephyr" || + # Not part of ZMK + relPath == "lambda" || relPath == ".github" + ); + }; + + preConfigure = '' + cmakeFlagsArray+=("-DUSER_CACHE_DIR=$TEMPDIR/.cache") + ''; + + cmakeFlags = [ + # "-DZephyrBuildConfiguration_ROOT=${zephyr}/zephyr" + # TODO: is this required? if not, why not? + "-DZEPHYR_BASE=${zephyr}/zephyr" + "-DBOARD_ROOT=." + "-DBOARD=${board}" + "-DZEPHYR_TOOLCHAIN_VARIANT=gnuarmemb" + "-DGNUARMEMB_TOOLCHAIN_PATH=${gcc-arm-embedded}" + # TODO: maybe just use a cross environment for this gcc + "-DCMAKE_C_COMPILER=${gcc-arm-embedded}/bin/arm-none-eabi-gcc" + "-DCMAKE_CXX_COMPILER=${gcc-arm-embedded}/bin/arm-none-eabi-g++" + "-DCMAKE_AR=${gcc-arm-embedded}/bin/arm-none-eabi-ar" + "-DCMAKE_RANLIB=${gcc-arm-embedded}/bin/arm-none-eabi-ranlib" + "-DZEPHYR_MODULES=${lib.concatStringsSep ";" zephyrModuleDeps}" + ] ++ + (lib.optional (shield != null) "-DSHIELD=${shield}") ++ + (lib.optional (keymap != null) "-DKEYMAP_FILE=${keymap}") ++ + (lib.optional (kconfig != null) "-DEXTRA_CONF_FILE=${kconfig}"); + + nativeBuildInputs = [ cmake ninja python dtc gcc-arm-embedded ]; + buildInputs = [ zephyr ]; + + installPhase = '' + mkdir $out + cp zephyr/zmk.{uf2,hex,bin,elf} $out + cp zephyr/.config $out/zmk.kconfig + cp zephyr/zephyr.dts $out/zmk.dts + ''; + + passthru = { inherit zephyrModuleDeps; }; +}