image_pdfimage_print

Buildman is the Swiss Army knife of U-Boot development. It handles the heavy lifting of building hundreds of boards in parallel, fetching the correct toolchains, and—perhaps most importantly—analysing the impact of your patches across git history. Whether you are checking for code bloat or verifying that a refactor doesn’t break a board you don’t own, buildman is the tool that makes it possible.

However, if you have ever peered into the internals of buildman, you might have noticed that the Builder class had become… well, enormous. Over the years, it accumulated responsibilities ranging from managing threads and file I/O to formatting console output and tracking build statistics.

A recent series of 18 patches to address this technical debt. The goal: split the monolithic Builder class into smaller, more focused components.

The Problem: A Class That Did Too Much

The Builder class in tools/buildman/builder.py had grown to over 2200 lines of code. It was handling two distinct responsibilities:

  1. Orchestrating the Build: Managing threads, checking out commits, running make, and saving artifacts.
  2. Reporting Results: Processing build outcomes, calculating size deltas, tracking error lines, and formatting the summary for the user.

These two concerns were tightly coupled, making the code hard to read, test, and maintain.

The Solution: Introduce ResultHandler

This refactor extracts the result-processing logic (~900 lines) into a new class called ResultHandler. The separation is clean:

  • Builder focuses on the act of building (I/O, git operations, process management).
  • ResultHandler focuses on the presentation of the build (summaries, error reporting, bloat analysis).

How We Got There

Refactoring a core tool like buildman is risky—regressions here can break workflows for developers everywhere. We took a stepwise approach:

  1. Extract Data Structures: We moved configuration handling (Config) and build outcomes (Outcome, BoardStatus, ErrLine) into their own modules (cfgutil.py, outcome.py). This broke the circular dependencies that often plague monolithic classes.
  2. Formalise Options: Instead of passing a dozen boolean flags (like show_errors, show_bloat) around individually, we grouped them into a DisplayOptions named tuple.
  3. Create the Handler: We introduced ResultHandler and progressively moved display methods into it—starting with simple size summaries and moving up to complex error delta calculations.
  4. Clean Up: Finally, we enforced Python naming conventions by adding underscore prefixes to private members (self.col became self._col), clarifying the public API.

The Result

The Builder class is now down to ~1200 lines—a much more manageable size. The display logic lives in tools/buildman/resulthandler.py, where it can be evolved independently.

While this doesn’t change the user-facing behaviour of buildman today, it makes the codebase significantly healthier and ready for future improvements. Sometimes the most important feature is code you can actually understand!

Author

  • Simon Glass is a primary author of U-Boot, with around 10K commits. He is maintainer of driver model and various other subsystems in U-Boot.

Leave a Reply

Your email address will not be published. Required fields are marked *