The Font Bug That Traced Back to a Configure Flag From Months Earlier

The first time KDE Plasma actually started on this from-scratch build, the desktop came up. Windows opened, menus dropped down, dialogs drew where they were supposed to. Every piece of text in every one of them was a small square — a tofu box, the placeholder a font renderer shows when it has no glyph to draw. The bug wasn't in Plasma at all. It was a single build flag on Qt6, set implicitly, months earlier, before the package it depended on even existed.

What Qt6 actually does when Fontconfig is missing

Qt6 was built early in this system's package order, well before Fontconfig — the library that matches font requests to installed font files — was installed anywhere on the system. Qt's own build configuration auto-detects Fontconfig at build time, and when it isn't found, configuration doesn't fail. It silently disables the feature and falls back to Qt's own minimal built-in font database instead. That fallback database isn't a general font-search mechanism; it's hardcoded to look in exactly one path, /usr/lib/fonts. This system had no font files installed anywhere yet, including that directory, so the fallback found nothing either.

Finding it in the one line that actually said so

Plasma's own Wayland session writes a log for every launch attempt, and buried in it was the exact diagnosis, printed by Qt itself: QFontDatabase: Cannot find font directory /usr/lib/fonts. Note that Qt no longer ships fonts. Deploy some ... or switch to fontconfig. That single line names both the symptom and the fix in the same sentence — it just took reading the actual session log, rather than staring at square glyphs, to find it.

The fix, and its ten-second explanation

Three things had to happen. Freetype, the actual font-rendering engine, and Fontconfig, the font-matching library Freetype's own --with-harfbuzz=dynamic default doesn't require as a hard build dependency, both got built. Then three real font families — DejaVu, Liberation, and Noto Sans (Plasma's own upstream default UI font) — got installed so there was something for Fontconfig to actually match against. And Qt6 itself needed rebuilding, this time with an explicit -fontconfig flag instead of leaving it to auto-detection. That last part matters beyond just fixing the immediate bug: a flag that's implicit and silently disabled on failure can regress again exactly this quietly. A flag that's explicit and required fails the build loudly instead, the next time something upstream of it changes.

The twist: fixing one flag rebuilt almost everything

This build's dependency tracking chains each KDE Frameworks and Plasma package's build to the one built immediately before it in sequence, all the way back through Qt6 — every one of roughly 150 packages, in effect, depends transitively on Qt6's own build output. Rebuilding Qt6 to add one configure flag didn't just rebuild Qt6. It invalidated and rebuilt the entire downstream stack it sits underneath: every KDE Framework, every Plasma component, everything compiled against the Qt6 that no longer exists in its old form. A one-line configure flag turned into the second-largest rebuild this entire project has needed, after the very first pass through the whole system.

Why the fallback failing quietly is the actual lesson

Nothing about the original, unfixed build was broken in an obvious way. Qt6 compiled cleanly. Every package built on top of it compiled cleanly. The desktop launched, drew its layout correctly, and only failed at the very last step of turning text into pixels — a failure mode indistinguishable, from a build log's perspective, from success. The actual gap wasn't a bug in any one package; it was a dependency that got skipped not because anyone decided to skip it, but because the order things got built in meant it didn't exist yet when the question "should I use Fontconfig?" got asked and answered once, silently, in the negative. Finding it required getting all the way to a running desktop and reading what it actually rendered, because nothing earlier in the process — the compiler, the linker, the package's own test suite, if it had one — had any way to know a font file would eventually matter.

Related reading

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.
Please share this article on your favorite website or platform.