Skip to content

Add Guix packaging for reproducible baochip builds#795

Draft
sbellem wants to merge 7 commits intobetrusted-io:devfrom
sbellem:guix-build
Draft

Add Guix packaging for reproducible baochip builds#795
sbellem wants to merge 7 commits intobetrusted-io:devfrom
sbellem:guix-build

Conversation

@sbellem
Copy link
Copy Markdown
Contributor

@sbellem sbellem commented Jan 29, 2026

work-in-progress-but-it-works

Related to #57 and more precisely to #393, in whcih @jeandudey provides a very good explanation for the motivation to package xous with Guix. Quoting him directly here:

The main advantage of GNU Guix is that everything is built from source, even the C, and Rust compilers, from a small binary seed and a working Linux system. Packages are defined using DSL made with Guile Scheme.

Also, packages are built in an isolated environment that can't be tampered with, without network access, or access to any other part of the filesystem, so build script can run without modifications. The build stage is separate from the download stage, and the download must match the hash of the file in the source declaration.
-- @jeandudey


Tested on dabao development board for:

  • bao1x-alt-boot1 and bao1x-boot1
  • dabao-helloworld

TODO:

  • See if there can be a better way to get latest stable Rust rather than using rustup (we want a bootstrapped rust ideally) (being actively worked on ... latest efforts at https://codeberg.org/guix/guix/pulls/6101)
  • Address the sources of non-determinism (review inline patches and see if we can address them upstream)
  • Pin channels to commit hashes
  • Use guix time-machine in CI for better sandboxing and reproducibility
  • Fix semver's rev tag part as it is just zeros right now (e.g.: Semver is: v0.9.16-2692-g00000000)
  • Review and cleanup the code (bao.scm and bao-crates.scm)
  • Review how cargo vendoring is done and see whether the process can be improved
  • Figure out ways to speed up CI (takes 1+ hour)
  • use guix build --check and/or guix build --rounds=2 to verify that builds are deterministic (bit-for-bit)
  • fix the non-deterministic build troubleshooting ci step as it does not work when previous step (guix build --rounds=2) fails
  • For production releases move the guix build toolchain to a separate repository, which will fetch xous-core source code from github. The current approach using local-file yields non deterministic builds as it can pick un-tracked files, which will differ from one machine to another.

Guix Quickstart to build Baochip Firmware

Prerequisites

Install Guix and configure channels in ~/.config/guix/channels.scm:

(cons*
 (channel
  (name 'rustup)
  (url "https://github.com/sbellem/guix-rustup")
  (branch "dev")
  (introduction
   (make-channel-introduction
    "d9bcf7f979506b880a5ba25674a606a824d9c890"
    (openpgp-fingerprint
     "E39D 2B3D 0564 BA43 7BD9  2756 C38A E0EC CAB7 D5C8"))))
 (channel
  (name 'rust-xous)
  (url "https://github.com/sbellem/rust-xous-guix")
  (branch "main"))
 %default-channels)

Then run guix pull to fetch the channels.

Development Shell

Enter dev shell:

guix shell --pure --development --file=guix.scm

Build:

cargo xtask dabao --no-verify

Building Packages

From the xous-core directory:

# Build a specific target
guix build bao1x-boot0

# Build with output symlink
guix build bao1x-boot1 --root=target/guix

Available Targets

bao1x-boot0, bao1x-boot1, bao1x-alt-boot1, bao1x-baremetal-dabao, dabao-helloworld, baosec

Notes on deterministic builds

The Submitting Patches page also has practical guidance on using --rounds=2 as part of the contribution workflow: https://guix.gnu.org/manual/en/html_node/Submitting-Patches.html

@sbellem sbellem force-pushed the guix-build branch 5 times, most recently from 890b75a to 9e5a1f5 Compare January 31, 2026 03:29
@sbellem
Copy link
Copy Markdown
Contributor Author

sbellem commented Feb 2, 2026

Guix installation on Ubuntu 22.04

@bunnie I used the following script to install guix on a fresh Ubuntu 22.04 instance. You may just use it as a reference and perform the installation steps manually. Also, notice the app armor related sections which may not apply to your system.

#!/bin/bash
# setup-guix.sh
# GNU Guix install on Ubuntu 22.04 — using the official installer
#
# Follows: https://guix.gnu.org/manual/1.5.0/en/html_node/Installation.html
#          → Binary Installation (recommended method)
#
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive

LOG=/var/log/guix-setup.log
exec > >(tee -a "$LOG") 2>&1

echo "=== Guix setup started at $(date -u) ==="

# Prerequisites for guix-install.sh: bash, gpg, tar, wget, xz
apt-get update
apt-get install -y wget gpg xz-utils uidmap

# Workaround: Guix 1.5.0 ships AppArmor profiles (see manual §2.2.4)
# that require abi/4.0, but Ubuntu 22.04 has AppArmor 3.x which doesn't
# support it. The installer's sys_maybe_setup_apparmor() calls
# apparmor_parser which then fails and aborts the install.
#
# The kernel parameter apparmor_restrict_unprivileged_userns doesn't
# exist on this kernel, so the profile isn't needed at all.
# Hide apparmor_parser so the installer skips the AppArmor step.
if command -v apparmor_parser &>/dev/null; then
    dpkg-divert --local --rename --add /usr/sbin/apparmor_parser
    RESTORE_APPARMOR_PARSER=1
fi

cd /tmp
wget https://guix.gnu.org/guix-install.sh
chmod +x guix-install.sh

# Uninstall any previous Guix installation first
if [ -d /var/guix ]; then
    echo ">>> Previous Guix installation detected, uninstalling …"
    set +o pipefail
    yes '' | ./guix-install.sh --uninstall
    set -o pipefail
fi

# Run non-interactively: pipe empty newlines to auto-accept all prompts
# (all prompts default to yes on bare return)
# The pipe causes yes to receive SIGPIPE (exit 141) when the installer
# finishes, so we capture the installer's own exit code.
set +o pipefail
yes '' | ./guix-install.sh
set -o pipefail

# Restore apparmor_parser
if [ "${RESTORE_APPARMOR_PARSER:-0}" = 1 ]; then
    dpkg-divert --local --rename --remove /usr/sbin/apparmor_parser
fi

# ── Post-install: Application Setup (manual §2.4) ─────────────────────

GUIX_PROFILE="${HOME}/.config/guix/current"
. "${GUIX_PROFILE}/etc/profile"

# §2.4.2 Name Service Switch
# Guix-built programs use Guix's glibc, which resolves users/hosts via
# nscd. Without it, some programs fail to resolve hostnames or users.
echo ">>> Post-install: enabling nscd …"
apt-get install -y nscd
systemctl enable --now nscd

# §2.4.1 Locales
# Avoid "setlocale: LC_ALL: cannot change locale" warnings from
# Guix-built programs by installing glibc-locales into root's profile.
echo ">>> Post-install: installing glibc-locales …"
guix install glibc-locales

# GC timer (manual §2.1, step 5)
# Periodic garbage collection to reclaim /gnu/store disk space.
echo ">>> Post-install: enabling guix-gc timer …"
GC_SRC="${HOME}/.config/guix/current/lib/systemd/system"
if [ -f "${GC_SRC}/guix-gc.service" ]; then
    cp "${GC_SRC}/guix-gc.service" "${GC_SRC}/guix-gc.timer" \
       /etc/systemd/system/
    systemctl daemon-reload
    systemctl enable --now guix-gc.timer
fi

# ── SSL certificates for guix-daemon ──────────────────────────────────
# Without these, the daemon may fail to download from HTTPS sources
# that involve redirects (e.g., content-addressed mirrors).
echo ">>> Post-install: configuring SSL certs for guix-daemon …"
mkdir -p /etc/systemd/system/guix-daemon.service.d
cat > /etc/systemd/system/guix-daemon.service.d/ssl-certs.conf << 'EOF'
[Service]
Environment="SSL_CERT_DIR=/etc/ssl/certs"
Environment="SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt"
EOF
systemctl daemon-reload
systemctl restart guix-daemon

# ── Smoke test ────────────────────────────────────────────────────────
echo ">>> Smoke test: guix build hello …"
guix build hello
HELLO_PATH=$(guix build hello)
"${HELLO_PATH}/bin/hello"

echo "=== Guix setup completed at $(date -u) ==="

- Add GitHub Actions workflow with matrix builds for boot0, boot1,
  alt-boot1, baremetal-dabao, dabao-helloworld, baosec
- Configure Guix channels (rustup 1.93.0, rust-xous-guix) for Rust
  toolchain with riscv32imac-unknown-xous-elf target
- Upload firmware artifacts (.uf2, .img, .bin)
@sbellem
Copy link
Copy Markdown
Contributor Author

sbellem commented Feb 4, 2026

Post-installation steps

Add the following to ~/.config/guix/channels.scm:

(cons*
 (channel
  (name 'rustup)
  (url "https://github.com/sbellem/guix-rustup")
  (branch "dev")
  (introduction
   (make-channel-introduction
    "d9bcf7f979506b880a5ba25674a606a824d9c890"
    (openpgp-fingerprint
     "E39D 2B3D 0564 BA43 7BD9  2756 C38A E0EC CAB7 D5C8"))))
 (channel
  (name 'rust-xous)
  (url "https://github.com/sbellem/rust-xous-guix")
  (branch "main")
  (introduction
   (make-channel-introduction
    "bcdb7bb2b220288545114b140f5079ba4f98a157"
    (openpgp-fingerprint
     "E39D 2B3D 0564 BA43 7BD9  2756 C38A E0EC CAB7 D5C8"))))
 %default-channels)

Edit .bashrc, or some other bash profile file

export GUIX_LOCPATH=$HOME/.guix-profile/lib/locale

GUIX_PROFILE="$HOME/.guix-profile"
. "$GUIX_PROFILE/etc/profile"
GUIX_PROFILE="$HOME/.config/guix/current"
. "$GUIX_PROFILE/etc/profile"

# optional, for ncsd
export SSL_CERT_DIR="$HOME/.guix-profile/etc/ssl/certs"
export SSL_CERT_FILE="$HOME/.guix-profile/etc/ssl/certs/ca-certificates.crt"

@bunnie
Copy link
Copy Markdown
Member

bunnie commented Feb 4, 2026

Looks like I'm able to run guix on my local machine to build a version of boot0. Is there a way I can see what version of Rust the build is using to build it?

@sbellem
Copy link
Copy Markdown
Contributor Author

sbellem commented Feb 4, 2026

Looks like I'm able to run guix on my local machine to build a version of boot0. Is there a way I can see what version of Rust the build is using to build it?

You can run:

 guix graph -t bag bao1x-boot0 | grep -i rust

@bunnie bunnie changed the base branch from main to dev February 18, 2026 13:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants