\chapter{Building and Flashing} \label{ch:build} The firmware is built with ESP-IDF; the hardware-free domain core also builds and is unit-tested on the host machine. \section{Toolchain} \begin{table}[htbp] \centering \begin{tabular}{@{}ll@{}} \drhead Item & Choice \\ \midrule Framework & ESP-IDF v5.5.x (native) \\ Language & C++23 (\texttt{-std=gnu++23}) \\ Error model & \texttt{std::expected}; exceptions off \\ Documentation & Doxygen (build must pass) \\ \bottomrule \end{tabular} \caption{Firmware toolchain.} \label{tab:build-toolchain} \end{table} \section{Device build} \begin{drcode}[Build, flash, monitor] idf.py set-target esp32s3 idf.py build idf.py -p flash monitor \end{drcode} \section{Host unit tests} The pure core is tested on the host, with no board attached. On macOS the tests need a C++23 standard library --- use a Homebrew LLVM (>= 18) or GCC~14 rather than the system Apple Clang. \begin{drcode}[Host tests] cmake -S components/core/test -B build-host \ -DCMAKE_CXX_COMPILER="$(brew --prefix llvm)/bin/clang++" cmake --build build-host ctest --test-dir build-host --output-on-failure \end{drcode} \section{Documentation} Documentation has two enforced checks, run from the \texttt{Software/} directory: \begin{enumerate} \item \textbf{Doxygen} --- C++ API reference from source doc blocks. An undocumented public class, method, or parameter fails the build. \item \textbf{Manual sync} --- every public class under an \texttt{include/} tree must have a matching \texttt{\textbackslash label\{cls:ClassName\}} section in \texttt{docs/manual/ch-classes.tex}. Design-level HTTP API documentation lives in Chapter~\ref{ch:api}. \end{enumerate} \begin{drcode}[Docs (from Software/)] doxygen Doxyfile python3 tools/check-manual-sync.py \end{drcode} \section{Continuous integration} Every push and pull request to \texttt{main} runs \texttt{.github/workflows/ci.yml} at the repository root (three parallel jobs, all from the \texttt{Software/} directory): \begin{enumerate} \item \textbf{Host tests} --- \texttt{cmake} + \texttt{ctest} on \texttt{components/core/test} (C++23, \texttt{g++-14} on Ubuntu). \item \textbf{Doxygen} --- must exit 0 with an empty \texttt{docs/api/doxygen-warnings.log}. \item \textbf{Manual sync} --- \texttt{tools/check-manual-sync.py}. \end{enumerate} To rebuild the PDF manual (requires a LaTeX installation): \begin{drcode}[Manual PDF] cd docs/manual latexmk -lualatex manual.tex \end{drcode} \begin{drcaution}[Keep it green] Both checks are part of the definition of done. A firmware change that adds or modifies a public class, a REST endpoint, or its behaviour must update the Doxygen doc blocks, \texttt{ch-classes.tex} (for classes), and \texttt{ch-api.tex} (for HTTP) in the same change. \end{drcaution}