Build from source
Ubuntu 24.04 LTS on x86-64 Linux is the reference build platform. The pinned prebuilt Linux toolchain is an x86-64 Linux executable. Other Linux distributions need compatible development tools and libraries; another host architecture requires a suitable source-built toolchain. Native Windows and macOS source builds are not covered here.
Before you start building for the ESP32-S31 Linux port, make sure you have the following prerequisites.
A relatively recent Linux distribution.
Sufficient free disk for the source history, toolchain, ESP-IDF tools/download cache, and build outputs. Do not treat 10 GiB as a verified full-build minimum; usage depends on clone depth and retained toolchain/package caches. Check available space with
df -hbefore building and leave room for temporary downloads and rebuilds.RAM usage depends on the configured packages and build parallelism; no measured minimum is specified here. Reduce
JOBSif the host runs out of RAM.
1. Clone the Repository
Clone the ESP32-S31 Linux port repository and initialize its pinned submodules:
git clone --recurse-submodules https://github.com/GrieferPig/esp32-s31-linux.git
cd esp32-s31-linux
git submodule update --init --recursive
2. Install Development Tools and Libraries
The ESP-IDF environment installed below supplies esptool for image generation
and flashing. A separate global installation is not needed for a source build.
For flashing only, use the isolated installation in
Flash and first boot.
Build Essentials
These provide the essential development tools and libraries required to build and work with the ESP32-S31 Linux port. Install with
sudo apt-get update
sudo apt-get install -y \
git curl wget file python3 python3-pip python3-venv cmake \
bison bc build-essential ccache cpio device-tree-compiler flex gperf \
libffi-dev libssl-dev libncurses-dev ninja-build python3-pkg-resources python3-pyelftools \
python3-dev swig rsync unzip xz-utils mtd-utils squashfs-tools
libncurses-dev supports the Buildroot configuration menu, and mtd-utils
supplies mkfs.jffs2 for the optional make persist target.
Select the interpreter that can import the installed U-Boot host dependencies:
export HOST_PYTHON=/usr/bin/python3
"$HOST_PYTHON" -c 'import pkg_resources, elftools'
Keep this setting when activating ESP-IDF below. Its Python environment may not
include Ubuntu’s python3-pkg-resources and python3-pyelftools packages.
The build uses HOST_PYTHON for U-Boot’s Python tools, including binman scripts
with an env python3 shebang; ESP-IDF retains its own environment. If using a
different host interpreter, install those dependencies there and run the same
import check. Save the interpreter path in local.mk to reuse it in new shells.
ESP-IDF
ESP-IDF is the official development framework for the ESP32 series of chips. LP and Radio firmwares in esp32-s31-linux depend on ESP-IDF’s proprietary libraries and toolchain.
Use the exact ESP-IDF revision in configs/build-versions.mk, not a moving
master branch or a version number alone. The current pin is
a602e67b0bf9ee0806dc4e1df7afc9affedf5c33. From the project root, install it
into a new directory:
export IDF_PATH="$HOME/esp-idf"
ESP_IDF_REF=$(sed -n 's/^ESP_IDF_REF := //p' configs/build-versions.mk)
git clone --filter=blob:none https://github.com/espressif/esp-idf.git "$IDF_PATH"
git -C "$IDF_PATH" checkout "$ESP_IDF_REF"
git -C "$IDF_PATH" submodule update --init --recursive
"$IDF_PATH/install.sh" esp32s31
If you already have an ESP-IDF installation, use a separate checkout or save
its local changes before switching revisions. make idf-check rejects a
checkout that differs from the pin. S31_ALLOW_UNPINNED=1 is an explicit
experimental override, not the reproducible build path.
Espressif’s ESP32-S31 installation guide provides platform setup help; retain this project’s pinned revision when following it.
Custom Toolchains
A fork of espressif’s crosstool-ng is used to build custom toolchains for the ESP32-S31 Linux port. These custom toolchains contain optimizations specific to this port and the S31 chip.
Sources can be found on GitHub. The release binaries are built via GitHub Actions. Download them to cache/toolchains/riscv32-esp-linux-musl by
make toolchain-fetch
The default release is pinned in configs/build-versions.mk
(esp32s31-linux-gcc-15.2.0-5 at this revision). The target checks the downloaded
archive against the release’s SHA-256 file. Use TOOLCHAIN_RELEASE_TAG=local
only when deliberately testing an already installed custom toolchain.
3. Build the Project
Activate ESP-IDF in your terminal:
export IDF_PATH="$HOME/esp-idf" # Replace with the path to your ESP-IDF installation if different
. "$IDF_PATH/export.sh"
Build the complete image on the host:
make doctor
make fetch
make image
image builds the boot firmware, kernel, rootfs, radio XIP image, and combined
flash image, verifies the paired artifacts, and publishes them atomically to dist/.
all is a compatibility alias for image. It does not access a serial port or flash a board. The default is
the full board configuration with native controller drivers. Drivers for
external devices, such as a particular codec or USB device class, may require
additional kernel selections. Set JOBS, for example make JOBS=4 all, to limit parallel compilation.
See Build configuration.
To build a particular component, use
make uboot
make linux
make rootfs
To update a connected board already using the compact layout while preserving its persist partition, select the port explicitly:
make PORT=/dev/ttyUSB0 BAUD=2000000 flash-existing-all
This target verifies and writes the immutable dist/current set without rebuilding;
flash-all is its alias. Complete
make image first, before flashing. Partial update targets are disabled because the installed companion
identities are unknown. make build-flash explicitly combines build and flash. For first
installation, data backup, and release-image updates, see
Flash and first boot.
4. Build output
Path under |
Content |
|---|---|
|
SPL with its DTB |
|
ESP ROM image wrapper around SPL |
|
FIT containing OpenSBI, U-Boot proper and associated data |
|
Linux device tree |
|
Flash-XIP Linux kernel |
|
SquashFS root filesystem |
|
Prelinked flash-XIP radio payload; paired with this build’s kernel |
|
Combined installation image; overwrites persist |
|
Build-time kernel/module/payload/import binding and radio hash |
|
Source, configuration, toolchain, artifact hashes and build provenance |
|
Checksums for the release artifacts |
|
Empty JFFS2 image, produced only by |
For more build targets, see the Make reference.
Native build trees live beside images/: linux/, opensbi/, u-boot/,
idf-radio/, radio/, lp/, and buildroot/. Shared downloads and toolchains
are under cache/; make clean only removes the build output.
Host-specific settings belong in the ignored local.mk, for example:
IDF_EXPORT := /opt/esp-idf/export.sh
HOST_PYTHON := /usr/bin/python3
JOBS := 4
An explicitly requested ROOTFS_BASELINE=/absolute/path/to/rootfs.sqfs build
repackages a verified existing rootfs with the current radio module. Its manifest
records incremental provenance, validates the full runtime inventory and module
list, and rejects incomplete userspace. With explicit ROOTFS_BUSYBOX_BUILD
evidence it can restore only missing stock logging/cron init scripts from pinned
sources. Inherited binaries retain their original optimization. This is not a
clean Buildroot rebuild and does not validate unrelated rootfs source changes.