Skip to content

ci: make the FreeBSD job actually build, and fail when it does not - #2213

Merged
jcelerier merged 1 commit into
masterfrom
fix/freebsd-ci
Aug 16, 2026
Merged

ci: make the FreeBSD job actually build, and fail when it does not#2213
jcelerier merged 1 commit into
masterfrom
fix/freebsd-ci

Conversation

@jcelerier

Copy link
Copy Markdown
Member

The FreeBSD job has been green since it was added, and it has never compiled score even once.

What is broken

ci/freebsd.build.sh started with:

#!/usr/bin/env bash -e

env(1) does not split its first operand, so this asks for a program literally named bash -e. On FreeBSD that is:

env: bash -e: No such file or directory

and the script exits 127 without running a single line. It is not a FreeBSD quirk either — GNU env says the same thing (use -[v]S to pass options in shebang lines). #!/bin/bash -e, which every other ci/*.build.sh uses, is not an option here: on FreeBSD bash is /usr/local/bin/bash.

Here is the whole build step of run 31948475911 on master:

13:06:10.1976660Z =============== FreeBSD Deps Success =====================
13:06:10.1977851Z =============== FreeBSD Start Build =====================
13:06:10.2000273Z env: bash -e: No such file or directory
13:06:10.2001486Z =============== FreeBSD End Build =====================

Two milliseconds, and a green checkmark.

Why CI did not notice

.github/workflows/bsd.yml ran the script as:

./ci/freebsd.build.sh && echo "=============== FreeBSD Build Success ====================="
echo "=============== FreeBSD End Build ====================="

The && turns the failure into a skipped echo, and the step's exit status is that of the last command in the block — the unconditional End Build echo, which always succeeds. So no matter what the script does, the step is green.

Adding set -e to the block is not enough on its own: errexit is specified to ignore any command of an AND-OR list other than the last one, so false && echo hi does not stop an errexit shell. The && has to go.

The change

  • ci/freebsd.build.sh: keep env (bash is not in /bin there), move the option into the script as set -e, with a comment so it does not get folded back into the shebang.
  • .github/workflows/bsd.yml: set -e in the run block, and run the build script as a plain command instead of the left-hand side of an &&.

The deps line is deliberately left alone — #2202 rewrites it along with ci/common.deps.sh, and its version of this hunk is a superset of this one, so the two converge.

How it was verified

In a FreeBSD 15.0 VM built from the same vmactions/freebsd-builder image the CI uses, with the packages this workflow installs. The workflow's build block was replayed against a cmake stub that fails on --build:

script step exit status
master, build fails env: bash -e: No such file or directory 0 (green)
this PR, build fails FAKE CMAKE: build FAILED 1 (red)
this PR, build succeeds Build Success 0 (green)

and running master's script by hand on FreeBSD gives exit status 127.

Then the real thing: ./ci/freebsd.build.sh on a full checkout with all the add-ons, which now runs and reports what it finds.

What it finds

Once the script actually runs, master does not compile on FreeBSD. One add-on is responsible: score-addon-sysinfo vendors lfreist/hwinfo, whose "unix" backend is really the Linux one — it needs <netpacket/packet.h> and _SC_AVPHYS_PAGES, neither of which FreeBSD has, and it reads /proc and /sys throughout. That is fixed in ossia/score-addon-sysinfo#3, which skips the add-on on the BSDs and explains why a real BSD backend belongs upstream rather than in a shim.

Merge that one first. ci/common.deps.sh clones the add-on from its default branch, so as soon as it lands the FreeBSD job here goes green on its own — and with this PR, green will finally mean something. Merged the other way round, this PR turns the job red until the add-on fix follows.

With the add-on out of the way, the whole of master compiles and links on FreeBSD 15.0.

ci/freebsd.build.sh started with "#!/usr/bin/env bash -e". env(1) does not
split its first operand, so it looked for a program literally named
"bash -e", printed "env: bash -e: No such file or directory" and exited 127
before a single line of the script ran. score has therefore never been
compiled by the FreeBSD job - see for instance run 31948475911, where the
whole build step is those five words between "Start Build" and "End Build".

Nothing noticed because the workflow ran the script as
"./ci/freebsd.build.sh && echo ... Success ...": the && swallows the failure,
and the step's status is that of the trailing "End Build" echo, which always
succeeds. Adding set -e to the run block is not enough on its own either -
errexit is specified to ignore any command of an AND-OR list other than the
last one.

So set the option inside the script instead, and let the workflow run it as a
plain command under set -e. Note that bash lives in /usr/local/bin on FreeBSD,
which is why this one keeps env rather than the "#!/bin/bash -e" of its
siblings.

Verified on a FreeBSD 15.0 VM with a cmake stub that fails on --build: the
workflow block exits 0 before, 1 after, and still 0 when the build succeeds.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jcelerier

Copy link
Copy Markdown
Member Author

Verification transcript, FreeBSD 15.0 VM (same vmactions/freebsd-builder image as the job, same package set).

1. master, replayed with a cmake stub that fails on --build

############ BEFORE: master shebang + master workflow block, build fails ############
=============== FreeBSD Start Build =====================
env: bash -e: No such file or directory
=============== FreeBSD End Build =====================
>>> workflow step exit status = 0

############ AFTER: fixed shebang + fixed workflow block, build fails ############
=============== FreeBSD Start Build =====================
FAKE CMAKE: configure ok
FAKE CMAKE: build FAILED
>>> workflow step exit status = 1

############ AFTER, build succeeds ############
=============== FreeBSD Build Success =====================
=============== FreeBSD End Build =====================
>>> workflow step exit status = 0

############ master shebang alone (script never runs at all) ############
>>> script exit status = 127

2. the real build, full checkout with every add-on

With score-addon-sysinfo as it is on its main:

[43/44] Building CXX object .../hwinfo/src/linux/network.cpp.o
FAILED: [code=1] .../hwinfo/src/linux/network.cpp.o
  fatal error: 'netpacket/packet.h' file not found
[44/44] Building CXX object .../hwinfo/src/linux/ram.cpp.o
FAILED: [code=1] .../hwinfo/src/linux/ram.cpp.o
  error: use of undeclared identifier '_SC_AVPHYS_PAGES'
ninja: build stopped: subcommand failed.

With ossia/score-addon-sysinfo#3 applied:

 -- score: configuring score-addon-sysinfo
-- score-addon-sysinfo: hwinfo has no FreeBSD backend, skipping
...
########## STEP 3 script exit status = 0 ##########
-- Installing: /build/install/bin/ossia-score

So the FreeBSD job on this PR is expected to go red until ossia/score-addon-sysinfo#3 lands — that red is the fix working. ci/common.deps.sh clones the add-on from its default branch, so nothing further is needed here once it is merged.

@jcelerier
jcelerier merged commit 30fe1d7 into master Aug 16, 2026
5 of 43 checks passed
@jcelerier
jcelerier deleted the fix/freebsd-ci branch August 16, 2026 13:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant