Skip to content

C++

The C++ side of the boundary: an application that already owns its screen stack, hosting xpui screens over a C ABI. This is the repository to read if you have a firmware written in C++ and want one screen of it in Rust. Not a rewrite — a screen at a time, called through six lifecycle entry points and an opaque void*.

Every document in this repository is listed in docs/README.md.

cpp_hostThe worked example, and the only thing any gate in this organisation builds, links and runs the FreeInkUI shim through. Design an ABI change here
firmwareThe same C++ through PlatformIO, for a real ESP32. No gate invokes it, so a break surfaces when somebody builds a firmware
abiTwo of the five ABI boundaries, checked — the two that cross into the application: xpui_host.h against the Rust that calls it, and xpui_app.h against src/lib.rs and the macro that defines its factory. The other three are the backend's and are checked there

Nothing depends on this repository; it is the far end. Using it is following the tutorial with a firmware of your own, or building the worked example:

Shell
cmake -S cpp_host -B target/cpp_host -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build target/cpp_host
./target/cpp_host/xpui-host --headless --frames 30 --selftest

What it builds on is xpui and the FreeInkUI backend from xpui-backends, whose fui/cpp/ this compiles and links. That one is a sibling checkout, not a package path: nothing is published, and a git dependency lands in a cargo checkout directory with no path a CMakeLists.txt can name.

  • xpui-backends, cloned beside this repository — or named by XPUI_BACKENDS_DIR. Without it the two stages that compile C++ print skipped: and pass on a laptop, fail on CI, and all fails.
  • The FreeInk SDK's FreeInkUI headers, for those same two stages: named by FREEINK_SDK_INCLUDE, or in one of the sibling layouts freeink_include in xtask/src/cpp.rs lists. Without them both skip and pass, except on CI, where a skip is a failure. all needs no local copy: CMake fetches the revision cpp_host/freeink-sdk.rev pins, which CI reads too.
  • SDL2, for the desktop host's window.
  • clang-format 21 or newer, for the C++ format stage; an older binary ignores options it does not know and formats differently, silently.
  • CMake and Ninja, for all.
Shell
./build-and-test.sh # format, lint, test, and every snippet
./build-and-test.sh all # plus cmake, the link, and nine ctest cases

The checks themselves are in xtask/ — this repository's own list, in Rust, holding nothing it does not run. ./build-and-test.sh fix formats in place first. all is the only place in the organisation where the C ABI is compiled, linked and executed rather than syntax-checked. How a change is reviewed is in docs/contributing.md.

Every arrow is a dependency in a Cargo.toml, and they all point inward toward xpui, which depends on nothing at all. That is the rule the organisation is arranged around: a backend can be written without the framework knowing it exists, and a firmware reaches whatever it needs directly rather than through whoever happens to sit above it.

xpuithe frameworkxpui-chromecomponentsxpui-boardseight devicesxpui-backendstwo backendsxpui-simulatora windowxpui-gallerythe appxpui-rp2040firmwarexpui-esp32firmwarexpui-cppa C++ hostxpui-devthe umbrella