diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..be781d0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +FROM docker.io/zmkfirmware/zmk-build-arm:stable + +RUN apt-get update \ + && apt-get install -y wget \ + && wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq \ + && chmod +x /usr/bin/yq + +ARG USER_ID=1000 + +RUN adduser --disabled-password --gecos '' --uid ${USER_ID} zmk + +USER zmk + +WORKDIR /app + +COPY config/west.yml config/west.yml + +RUN mkdir -p build \ + && west init -l config \ + && west update \ + && west zephyr-export + +COPY bin/build.sh ./ + +CMD ["./build.sh"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0cd3c26 --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +DOCKER := $(shell { command -v podman || command -v docker; }) + +.PHONY: all clean distclean + +all: + $(DOCKER) build --tag zmk-build-user-config --build-arg USER_ID=$(shell id -u) . + $(DOCKER) volume create zmk_build + $(DOCKER) run --rm -it --name zmk-build-user-config -u zmk \ + -v zmk_build:/app/build \ + -v $(PWD)/build.yaml:/app/build.yaml:ro \ + -v $(PWD)/config:/app/config:ro \ + -v $(PWD)/firmware:/app/firmware \ + -e OUTPUT_ZMK_CONFIG=$(OUTPUT_ZMK_CONFIG) \ + zmk-build-user-config + +clean: + rm -rf firmware/[^.]* + -$(DOCKER) volume rm zmk_build + +distclean: clean + -$(DOCKER) image rm zmk-build-user-config + -$(DOCKER) system prune diff --git a/README.md b/README.md new file mode 100644 index 0000000..084f7c9 --- /dev/null +++ b/README.md @@ -0,0 +1,66 @@ +# Unified ZMK Config + +## Modifying the keymap + +[The ZMK documentation](https://zmk.dev/docs) covers both basic and advanced functionality and has a table of OS compatibility for keycodes. + +## Building the Firmware with GitHub Actions + +### Setup + +1. Fork this repo. +2. Enable GitHub Actions on your fork. + +### Build firmware + +1. Push a commit to trigger the build. +2. Download the artifact. + +## Building the Firmware in a local container + +### Setup + +#### Software + +* Either Podman or Docker is required, Podman is preferred if both are present. +* `make` is also required + +#### Windows specific + +* If compiling on Windows use WSL2 and Docker [Docker Setup Guide](https://docs.docker.com/desktop/windows/wsl/). +* Install `make` using + ```bash + sudo apt-get install make + ```. +* The repository can be cloned directly into the WSL2 instance or accessed through the C: mount point WSL provides by default (`/mnt/c/path-to-repo`). + +### Build firmware + +1. Execute `make`. +2. Check the `firmware` directory for the latest firmware build. + +#### Output ZMK Configs +Sometimes it can be useful to output the full ZMK configs for a build. This can be achieved by executing the following: +```bash +OUTPUT_ZMK_CONFIG=1 make +``` + +The configs with then be outputted to the `firmware` directory along with the firmware files. + +#### Build Cache +A docker volume is used to cache the build artifacts, allowing subsequent builds to compile faster. + +### Cleanup + +#### Partial Cleanup +The compiled firmware files and docker volume build cache can be deleted with `make clean`. This might be necessary if you want a pristine build or to cleanup the `firmware` directory. + +### Full Cleanup + +The built docker container can be deleted with `make distclean`. This might be necessary if you want to rebuild the docker container or update the ZMK version used to compile your firmware. + +Of course, you can also use regular Docker commands to manage the image/build cache. + +## Flashing firmware + +Follow the ZMK instructions on [Flashing UF2 Files](https://zmk.dev/docs/user-setup#flashing-uf2-files) to flash the firmware. diff --git a/bin/build.sh b/bin/build.sh new file mode 100755 index 0000000..7814dd4 --- /dev/null +++ b/bin/build.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +config_dir="${PWD}/config" +timestamp=$(date -u +"%Y%m%d%H%M%S") + +while IFS=$',' read -r board shield; do + extra_cmake_args=${shield:+-DSHIELD="$shield"} + artifact_name=${shield:+${shield// /-}-}${board}-zmk + filename="${PWD}/firmware/${timestamp}-${artifact_name}" + build_dir="${PWD}/build/${artifact_name}" + + echo "" + echo "-----------------" + echo "BUILDING FIRMWARE" + echo "-----------------" + echo "Zephyr: ${ZEPHYR_VERSION}" + echo "Board: ${board}" + echo "Shield: ${shield}" + echo "" + + if [[ ! -d "$build_dir" ]]; then + west build -s zmk/app -b "$board" -d ${build_dir} -- \ + -DZMK_CONFIG="$config_dir" "${extra_cmake_args}" + else + west build -d ${build_dir} -- -DZMK_CONFIG="$config_dir" + fi + + if [[ ! -z $OUTPUT_ZMK_CONFIG ]]; then + grep -v -e "^#" -e "^$" ${build_dir}/zephyr/.config \ + | sort > "${filename}.config" + fi + + extensions="uf2 hex bin" + for extension in $extensions; do + artifact=${build_dir}/zephyr/zmk.$extension + if [[ -f $artifact ]]; then + cp $artifact "${filename}.$extension" + break + fi + done +done < <(yq ' + [{"board": .board[], "shield": .shield[] // ""}] + .include + | filter(.board) + | unique_by(.board + .shield).[] + | [.board, .shield // ""] + | @csv +' build.yaml) diff --git a/firmware/.gitignore b/firmware/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/firmware/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore