Inspiration

When compiling a complex graphical application for an embedded system, a common solution is to just cross compile an ENTIRE OPERATING SYSTEM using programs such as buildroot, yocto, or nix. This is a total cop-out. Someone asked "how do I build a program for this machine?" and the answer of computer scientists and engineers was "we don't know, just compile the whole machine and then it will probably work."

So I set out to make a graphical application compile for both my RISCV/single-core/GPUless raspberry pi uconsole, and my x86_64 linux (NixOS) laptop. And I wanted to be able to do it with a small enough LoC count that I could reasonably read and understand the inner workings of the whole project.

What it does

The final application just opens a window which receives mouse and keyboard input, and displays a black rectangle.

The magic is that, for any platform, the compilation process looks like this: (Do note that steps 4 and 5 are equivalent to installing a package called xcbproto or xcbproto-dev and python3 on most linux distributions. So if you prefer that method, use it.)

  1. Head to ziglang.org/download and download the archive for v0.11.0
  2. Extract the tar archive.
  3. Add the resulting folder containing the zig executable to your PATH environment variable.
  4. Head to python.org/downloads and download and run the installer for your system. Make sure to check the "add python to path" box!
  5. Download the xcb specification from https://gitlab.freedesktop.org/xorg/proto/xcbproto and add the xcbgen folder to your PYTHONPATH environment variable.
  6. Download the source code for the project at github.com/the-argus/static-xcb
  7. Open a terminal and change CWD to the folder with the source code
  8. Run zig build -Dtarget=x86_64-linux-musl to get a program which will run on any x86_64 machine running linux and X11. Try using the flag -Dtarget=riscv64-linux-musl to get one for the RISCV uconsole. This executable doesn't need to be installed, just copy + paste it anywhere and run it.

Note: although a huge improvement over building a whole OS, this process is still more complex than I would like. The python scripts for generating headers could be written in zig to decrease dependencies, for example.

I'm very close to removing python as a dependency, but that will still be required to build this project as of submission time.

How I built it

I noticed that libxcb depends on libc and libXau. libXau depends on libc. I also know that making a x11 application doesnt require dynamic linking to system libraries because x11 uses IPC and IO to communicate with clients.

So I spent twelve hours writing build scripts in zig for generating the necessary headers and source files from the xorgproto XML specification. The result was a bunch of .c and .h files, which I proceeded to compile into one big static library. Last step was to write a simple Hello, World libxcb application, write scripts to link it to the static library, create the executable. Ran it on my x86_64 machine, and confirmed that it worked. Then I compiled it for RISCV with musl libc, copied it onto the SD card for the uconsole, turned on the machine, and it ran. First try!

Challenges we ran into

I discovered three actual bugs in the zig buildsystem. This build system is extremely promising and entirely responsible for what I was able to do here, but also it's not in 1.0 yet and very unstable.

Accomplishments that I'm proud of

There was no tutorial for this, which is a change for me (I am usually a game developer, where I program in relatively known problem spaces like physics simulation and graphics etc). I am proud that I pieced together my knowledge of how C compilers/linkers, linux, libc, and X11 work to just think "hmm... I should probably able to do that, right?" And then I could.

What's next for Embedded Systems Toolchain in 25k LoC or Less

I need to package pthread-win32 or make a wrapper for pthread on my own (right now xcb relies on pthread, which limits the platform compatibility to unix systems).

I also want to check if it compiles for MacOS! In theory, it should.

Finally, when thats all done, I want to make a game that runs on the uconsole! Maybe multiple games. Maybe a game engine?

Built With

Share this project:

Updates