# Building QEMU from source for Velxio The Velxio docker image ships with prebuilt `libqemu-xtensa` and `libqemu-riscv32` libraries so ESP32 / ESP32-S3 / ESP32-C3 simulation works out of the box. If you'd rather not use the prebuilts — whether for licensing reasons, audit requirements, or simply because you prefer to compile what you run — this guide walks you through building both libraries from the upstream [`lcgamboa/qemu`](https://github.com/lcgamboa/qemu) fork. Velxio itself is **AGPLv3**, and that includes the binary linker contract: you have the source, you can rebuild, you can verify the chain end-to-end. > The prebuilts at `velxio.dev/license/signup` and on GitHub Releases > are a convenience, not a gate. Everything in this guide produces > the exact same `.so` / `.dll` / `.dylib` files those bundles > contain, byte-for-byte modulo timestamps. ## Audience This guide assumes a Linux or macOS workstation with a working C toolchain. Windows builds are possible via MSYS2 / MinGW but are out of scope here — start from `lcgamboa/qemu`'s own README if you need them. ## What you'll produce | File | Architecture | Used for | |---|---|---| | `libqemu-xtensa.so` | Xtensa LX6 / LX7 | ESP32, ESP32-S3, ESP32-CAM, Arduino Nano ESP32 | | `libqemu-riscv32.so` | RISC-V RV32IMC | ESP32-C3, XIAO ESP32-C3, CH32V003 | The Velxio backend dlopen's these at runtime through the dynamic linker (`backend/app/services/qemu_runtime.py`). Drop the freshly built files into `/app/lib/` inside the container (or the host path that mounts to it) and Velxio will use them on the next simulation start. ## 1. Clone the fork ```bash git clone https://github.com/lcgamboa/qemu.git cd qemu git checkout 822927b6 # the commit Velxio's prebuilts are anchored to ``` The exact commit ID may move forward over time. The Velxio docker image's `Dockerfile.standalone` records the canonical SHA — `grep -E 'qemu.*checkout|QEMU_REF' Dockerfile.standalone` to read it. ## 2. Install build dependencies **Debian / Ubuntu**: ```bash sudo apt-get update sudo apt-get install -y \ git ninja-build pkg-config \ libglib2.0-dev libpixman-1-dev \ python3 python3-venv python3-pip \ flex bison ``` **Arch / Manjaro**: ```bash sudo pacman -S --needed \ git ninja pkgconf \ glib2 pixman \ python flex bison ``` **macOS** (Homebrew): ```bash brew install ninja pkg-config glib pixman ``` ## 3. Configure and build — Xtensa (ESP32 / ESP32-S3) ```bash mkdir build-xtensa && cd build-xtensa ../configure \ --target-list=xtensa-softmmu \ --disable-werror \ --enable-shared-lib \ --disable-tools \ --disable-docs ninja ``` This produces `libqemu-xtensa.so` under `build-xtensa/`. Verify: ```bash file libqemu-xtensa.so # ELF 64-bit LSB shared object, x86-64, dynamically linked ls -lh libqemu-xtensa.so # ~46 MB on Linux x86_64 ``` Go back to the repo root: ```bash cd .. ``` ## 4. Configure and build — RISC-V (ESP32-C3) ```bash mkdir build-riscv32 && cd build-riscv32 ../configure \ --target-list=riscv32-softmmu \ --disable-werror \ --enable-shared-lib \ --disable-tools \ --disable-docs ninja cd .. ``` You now have `build-riscv32/libqemu-riscv32.so`. ## 5. Drop the binaries into Velxio If you self-host Velxio via the official docker image: ```bash docker cp build-xtensa/libqemu-xtensa.so velxio:/app/lib/libqemu-xtensa.so docker cp build-riscv32/libqemu-riscv32.so velxio:/app/lib/libqemu-riscv32.so docker restart velxio ``` If you're running Velxio from source: ```bash cp build-xtensa/libqemu-xtensa.so /path/to/velxio/backend/app/lib/ cp build-riscv32/libqemu-riscv32.so /path/to/velxio/backend/app/lib/ # restart the backend ``` The next ESP32 / ESP32-C3 simulation start will use your libraries. Check the backend logs for a line like: ``` [qemu_runtime] loaded libqemu-xtensa.so build= ``` ## 6. ESP32 ROM blobs The QEMU build does not produce the ESP32 ROM dumps Velxio also needs (`esp32-v3-rom.bin`, `esp32-v3-rom-app.bin`, `esp32c3-rom.bin`). Those come straight from Espressif's open-source toolchain and are redistributable verbatim. The image already includes them at `/app/lib/`; you only need to replace them if you're working from a custom esp-idf version. ## 7. Troubleshooting **`No such file or directory: glib-2.0`** — apt missed `libglib2.0-dev`. Re-run the dependencies step. **`error: ‘CONFIG_USER_ONLY’ is not defined`** — you forgot `--target-list=`. The `softmmu` suffix is required for the system emulator Velxio uses. **Shared library is too small** (a few hundred KB) — you built without `--enable-shared-lib`. The default QEMU output is the `qemu-system-*` binary, not the library Velxio loads. **Simulation starts but the board boots into "qemu: fatal: Trying to execute code outside RAM or ROM"** — wrong commit. `lcgamboa/qemu` master moves; Velxio is pinned. Check out the commit listed in `Dockerfile.standalone`. ## License notes `lcgamboa/qemu` is **GPL-2.0** (same as upstream QEMU). Velxio is **AGPLv3**. The dlopen boundary keeps the two licenses orthogonal: QEMU stays GPL'd, Velxio stays AGPL'd, neither contaminates the other. If you distribute a modified Velxio image with self-built QEMU binaries, you owe the QEMU sources to your recipients (GPL-2.0 obligation), and you owe the Velxio modifications under AGPLv3 if the deployment is networked. ## Why use the prebuilts at all? For ~99% of self-hosters the prebuilts at [`velxio.dev/license/signup`](https://velxio.dev/license/signup) or the GitHub release are the path of least resistance — they're the same files this guide produces, signed-by-sha256 in their manifest, ready to drop in. The build itself takes 15-30 minutes on a modern laptop and ~3 GB of disk for the build tree. Building from source matters when: - You're auditing the supply chain for a regulated deployment. - You need to patch QEMU (e.g. add a peripheral the fork doesn't emulate) and want to ship the patched library. - You don't want any third-party prebuilts on your machine. - You're on a platform we don't ship a binary for (e.g. BSD, ARM on macOS Intel boxes, exotic libc). All four are legitimate. The license module on velxio.dev exists to distribute prebuilts conveniently and to detect bulk-abuse patterns; it never tries to be the only path.