GlasgowEmbedded / glasgow

Scots Army Knife for electronics

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[RFC] Use Nix instead of Docker for reproducible firmware builds

whitequark opened this issue · comments

As of revision 8bf6305 we are using Docker to build the firmware in a bit-for-bit reproducible way. An alternative way of doing this is by using Nix, suggested by @tpwrules. The advantages and disadvantages respectively are:

Docker:

  • Advantage: most people already have it and many know (begrudgingly) how to use it
  • Disadvantage: apt-get is used in the build script, requiring network access each time it is used, and potentially enabling impurity
    • While it is possible that a new upstream version of sdcc would be uploaded in the Debian package repository for the same release, this has never happened in the entire history of sdcc in debian.
    • It is possible to use https://snapshot.debian.org/ to work around that but that is not currently the case
  • Disadvantage: this particular style of using Docker is unidiomatic

Nix:

  • Advantage: unquestionably reproducible builds that are entirely offline
  • Disadvantage: less widely known and understood system
    • This is not a maintenance concern because the script being used is very straightforward (see below)
  • Disadvantage: installer in distro repositories can be outdated and potentially cause issues
    • Doesn't seem to be the case for the (seemingly widely maligned) Debian nix package

We should pick one or the other, but not both.

Nix-based replacement script (by @tpwrules):

#!/usr/bin/env nix-shell
#! nix-shell --pure -i bash -p sdcc -p git
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/5550a85a087c04ddcace7f892b0bdc9d8bb080c8.tar.gz

# Display dependency versions.
sdcc --version

# Clean all build products; they may have been built using a different compiler.
make -C vendor/libfx2/firmware/library clean
make -C firmware clean

# Build the artifact.
make -C vendor/libfx2/firmware/library all MODELS=medium
make -C firmware all

# Deploy the artifact.
cp firmware/glasgow.ihex software/glasgow/device/firmware.ihex

To move this forward we'd need to write a user guide for this and integrate it with GitHub actions. I'm not really sure if "install Nix first" is a great thing to have in our guide for firmware developers...

It was my understanding that this was only to be for the builds to be committed to the repo, which individual developers would not be generating anyway, so developers would not be required to use Nix. For what it's worth, I would have to install Docker first to use the current script.

I'd be okay with dropping this, I think it's neat and a nicer way but not mandatory. There are some minor tweaks to do for long term robustness but I haven't had this in the front of my mind. Using Nix with GHA is not a problem but I'm not really sure what an action to e.g. automatically build and commit the firmware would look like.

It was my understanding that this was only to be for the builds to be committed to the repo, which individual developers would not be generating anyway

No, you actually have to use Docker/Nix when deploying firmware. The CI checks reproducibility but doesn't commit anything on its own (which would be problematic in multiple ways).

Using Nix with GHA is not a problem but I'm not really sure what an action to e.g. automatically build and commit the firmware would look like.

We have a job that checks reproducibility with Docker, so the same thing would have to be done with Nix.

I propose we keep the current Docker-based setup and keep this in the back of our minds for if there are problems down the line. It seems pretty unlikely to cause unrecoverable reproducibility problems, I think mostly the choice would have to do with ergonomics.

Souunds good to me. Thanks for the effort! I did appreciate seeing how flexible Nix can be.