Skip to content
Ilia Maslakov edited this page Sep 2, 2026 · 2 revisions

Local build check

make buildcheck runs the CI Ubuntu job on your own machine, in containers. It answers one question -- does this commit build and pass the tests -- without waiting for a runner, and it keeps answering it when GitHub Actions is down.

Everything below lives in maint/buildcheck.sh.

Running it

make buildcheck

That checks HEAD. Any commit-ish works:

make buildcheck REF=my-branch
make buildcheck REF=d0418075b

The script needs no build tree of its own, so it can be called directly from the sources:

maint/buildcheck.sh my-branch

It wants docker and about fifteen minutes the first time; the images stay cached afterwards.

It builds a commit, not your working tree

This is the one thing that surprises people. The script clones the repository inside the container and checks out the ref you named, so uncommitted changes are invisible to it. Commit first, then check.

Settings

variable default what it is
BUILDCHECK_IMAGE ubuntu:24.04 image of the build job
BUILDCHECK_MONGO_IMAGE ubuntu:26.04 image of the mongo plugin job
BUILDCHECK_JOBS all cores parallel make jobs

Two images because the CI uses two: the mongo plugin is built on a newer Ubuntu that carries the MongoDB C driver v2, everything else on what ubuntu-latest currently is.

BUILDCHECK_JOBS=4 maint/buildcheck.sh HEAD
BUILDCHECK_IMAGE=ubuntu:26.04 maint/buildcheck.sh HEAD

What it checks

step what runs
bootstrap ./autogen.sh
mongo plugin --enable-panel-plugin-mongo=yes, then the .so must exist
distribution archive make dist-bzip2
full --enable-mclib --enable-werror, build, test, install
ncurses --with-screen=ncurses --enable-werror, build, test
minimal everything switched off, --enable-werror, build, test

The three configurations are unpacked from the distribution archive, not from the checkout, so a file missing from EXTRA_DIST fails here the same way it fails on the runner.

--enable-werror is the part that earns its keep: a warning nobody looks at locally becomes a build failure in every one of these.

Reading the result

Every step prints one line, and the last line is the verdict:

=== configuration: full
PASS full
PASS install

=== configuration: ncurses
PASS ncurses

=== result
buildcheck: all green

A failure prints the interesting part of the log with it -- the error: lines of a build, the FAIL: lines of a test run, the tail of a failed configure. The exit code follows the verdict, so it can be used from a script.

Why it builds as an ordinary user

The extfs helper tests compare the uid and the gid of the files they list against the ones of the process, and print them symbolically when they match. Running as root changes what those tests expect, and hp48+ fails over nothing. The container therefore creates a user build and does everything as that user.

What it does not cover

It is the Ubuntu job, and only that one. The CI also builds on Fedora, Alpine, FreeBSD and Solaris, all of them with --enable-werror, and none of them are reproduced here.

Two libraries are worth knowing about. libmagic-dev is installed by no Linux CI job at all, so the code that recognises a file by its content is never compiled there -- it reaches a compiler only in the macOS release build. And libaspell-dev is no longer needed anywhere: spell checking is built whenever gmodule is present and the engine is opened at run time.

For what the panel plugins do against a real server, see QA testing. That sandbox builds your working tree; this one builds a commit.

Clone this wiki locally