Building & tooling
Building UnoDOS pc64 from source, running it under QEMU, packing a bootable USB image, building the flashers, and regenerating this manual.
Toolchain
- Build:
x86_64-w64-mingw32-gcc(UEFI apps are PE32+ images, the mingw target's native output, so no gnu-efi or EDK2) andpython3. - USB image:
sgdisk(gptfdisk),mtools,python3. - Emulator:
qemu-system-x86+ OVMF.
On Ubuntu: sudo apt install gcc-mingw-w64-x86-64 qemu-system-x86 ovmf mtools gdisk python3
Build & run
From the pc64/ directory:
./build.sh # build the unoui desktop shell -> build/esp/
./build.sh run # build, then boot it in QEMU + OVMF
./build.sh legacy # build the older 14-app "legacy" core
UNO_DEBUG=1 ./build.sh # the debug/test harness build (adds unoautomate)
UNO_PYRT=0 ./build.sh # skip PYRT.UNO (no Python runtime; smaller image)
python3 tools/mkuefi.py 512 # pack build/esp/ into build/unodos-uefi.img (512 MiB)
python3 harness.py boot # scripted QEMU boot + screenshot
python3 nettest.py # headless network + TLS verification
The build compiles the platform, framebuffer, toolkit, ten themes, apps and drivers freestanding, and links a
single BOOTX64.EFI into a bootable ESP tree in build/esp/. That kernel is
about 3.8 MB and the whole tree about 14 MB: the rest is the
.UNO apps, the four TrueType fonts, the sample media and the SDK beside it. Two local extras grow it
if you have them, and neither is in the repository: the Wi-Fi firmware blobs in fw-blobs/ add about
7 MB, and a Doom WAD in wads/ adds its own size again. UNO_DEBUG=1 links a bigger
kernel, about 4.4 MB.
send-key + screendump), which is how the screenshots in this manual are made.Pack a real USB disk image
QEMU fakes a disk from the build/esp/ directory, but real firmware needs a partition table.
tools/mkuefi.py turns the ESP tree into a raw disk image: GPT with one FAT32 EFI System Partition
holding the whole tree. This is the image the flashers embed.
Build variants
Two environment toggles to build.sh choose what the image is:
| Toggle | Effect |
|---|---|
UNO_DEBUG=1 | The debug / test harness: crash reports, the watchdog, the conformance suites, and the whole unoautomate remote channel and on-device automation. Off by default - a production image has none of it. |
UNO_PYRT=0 | Skip PYRT.UNO, the vendored-MicroPython Python runtime, for a smaller image. On by default; without it, Python apps will not run. |
Feature flags
| Flag | Effect |
|---|---|
-DUNO_XHCI | Compile the xHCI USB host + USB-Ethernet stack (inert stubs otherwise). |
-DUNO_I2C_TRACKPAD | Enable the native I2C-HID trackpad driver (inert stubs otherwise). |
-DUNO_DBGCON | Enable the port-0x402 debug console. Off by default: it SMM-traps and hangs some real hardware. |
-DUNO_APP_SYM=... | Name a bridged app's entry symbol so multiple apps link into one binary. |
Gotchas worth knowing
- LLP64:
longis 32-bit under mingw. Useunsigned long long/uintptr_tfor addresses. - Freestanding: no host libc or CRT; use
pc64_libc.c/pc64_math.c. - Resolution: some laptop panels black out on a real
SetMode. pc64 keeps the GOP mode and scales the desktop framebuffer to fit instead. - Watchdog: disable it at startup or UEFI resets the machine after about five minutes.
- Present-on-change: only changed framebuffer rows are written to video memory; full-frame rewrites every frame ruin input smoothness on real hardware.
Build the flashers
The flashers each embed a gzipped copy of the USB image and stream it to
the raw device. Source: pc64/flash/.
| Target | Build on | Command | Output |
|---|---|---|---|
| Windows | Windows + WSL (in-box csc.exe, no SDK) | pc64\flash\build-flasher.ps1 | UnoDosFlasher.exe |
| macOS | a Mac (Swift toolchain) | pc64/flash/mac/build-app.sh | UnoDosFlasher.app (universal) |
Pass --skip-build to reuse an existing build/unodos-uefi.img (useful when the image is
built on another machine). The built binaries are published on the project's GitHub Releases.
Regenerate the manual screenshots
The desktop screenshots in this manual are produced headlessly by pc64/docs_shots.py: it boots the
real image under QEMU + OVMF and drives the desktop over QMP, capturing each scene to
pc64/shots/manual/. Because the emulated pointer does not reach the shell, every scene is driven from
the keyboard.
python3 docs_shots.py # all scenes
python3 docs_shots.py themes editor browser_docs # selected scenes
UNO_NIC=1 python3 docs_shots.py browser_http # networking scenes
Copy the PNGs you need into docs/assets/img/, then rebuild and commit.
Scenes name apps by id - A("uocalc"), never a row number - because the Start-menu
order moves whenever an app is added and a scene that counts keystrokes does not fail when it does: it opens the
next app along and files the picture under the old name. The order comes from
pc64/build/apps_roster.txt, written by a run that opened every app by id over URC and checked the
window that appeared:
UNO_DEBUG=1 ./build.sh && python3 harness.py unoapps # measure the order
./build.sh && python3 docs_shots.py # capture the figures
The figures come from a production build, where URC would want a token typed at the console, so the order is
measured on a debug build of the same tree. Before it captures anything, docs_shots.py asks the
live menu how many rows it has and stops the run if that disagrees with the roster, which is what makes borrowing
the order from the other build safe. If the Control Panel's tab order changes, that is still a hand edit.