fix(build): make the test tree build on macOS (three portability defects) - #309
Merged
Conversation
added 3 commits
August 11, 2026 00:13
Five test translation units call ::getpid() without including <unistd.h>. glibc supplies the declaration transitively through a C++ standard header; libc++ does not, so on macOS the name is absent and three of the five fail to compile: tests/vllm/v1/test_kv_offload_fs.cpp:34:62: error: no member named 'getpid' in the global namespace The other two, tests/capi/test_capi.cpp and tests/vllm/test_gguf.cpp, build today only because a project header happens to pull <unistd.h> in for them (test_gguf.cpp via gguf_builder.h). They are the same defect one include-cleanup away from presenting, so they are repaired here rather than left to fail next. Include the header in each translation unit that uses it, as its own POSIX block, matching tests/vllm/models/test_kimi_linear_paged.cpp. The tree is otherwise include-what-you-use disciplined -- across the 369 test .cpp files, only 4% of (TU, standard header) pairs rely on a transitive include -- so these five were the exceptions, not the rule. The remaining ::getpid() call sites already include <unistd.h> directly and are untouched. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: Claude:claude-opus-5 [ClaudeCode]
POSIX allows the byte-order conversions to be macros, and the Darwin SDK
takes that option: <sys/_endian.h> defines htonl(x) as a parenthesised
conditional expression. A ::-qualified call therefore expands to `::`
followed by `(`, which is not a qualified-id, and both lmcache targets
fail to compile on macOS:
test_lmcache_client.cpp:55:30: error: expected unqualified-id
addr.sin_addr.s_addr = ::htonl(INADDR_LOOPBACK);
note: expanded from macro 'htonl'
Preprocessing runs before the qualification is considered, so no include
can rescue the ::-spelling; the qualification itself is the defect. Drop
it, which is what tests/vllm/entrypoints/openai/test_api_server.cpp
already does with the same bind/getsockname sequence. Measured on gcc 14
/ glibc 2.41: both spellings compile at -O0 and -O2, so this is a no-op
for the Linux build rather than a second fix.
Leaves every other ::-qualified libc call (::socket, ::bind, ::listen,
::getsockname) alone: those are functions on both platforms, and the
qualification is the file's deliberate style.
FOLLOWING_AGENTS_PROTOCOL
Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: Claude:claude-opus-5 [ClaudeCode]
A76Event reads /sys/bus/event_source/devices/armv8_cortex_a76/ and its only call site is inside the #if defined(__linux__) half of MakeCounterGroups. The function itself was never guarded, so off-Linux it is compiled and unreferenced, which -Werror turns into a hard failure: examples/cpu_kernel_bench/main.cpp:447:26: error: unused function 'A76Event' [-Werror,-Wunused-function] Put it under the same #if defined(__linux__) the file already uses for its PerfGroup stub, SetAffinity and ThrottlingStatus. ParsePerfEvent moves under the guard with it: its only caller is A76Event, so guarding one alone reproduces the identical error one function up. Nothing is deleted and the Linux path is byte-for-byte unchanged. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: Claude:claude-opus-5 [ClaudeCode]
filipsajdak
force-pushed
the
fix/macos-build
branch
from
August 10, 2026 22:21
a6fe142 to
a09bf87
Compare
Collaborator
Collaborator
|
Yup, looks good thanks @filipsajdak ! I don't have permission to rubber stamp the workflows though @mudler |
Collaborator
|
Landed on main as-is, one merge commit, your three commits intact. Nothing to argue with here — each of the three is a genuine portability defect with a mechanism, not a warning silenced:
Linux behavior is unchanged by construction: the added includes are already-satisfied declarations, the Reviewed and landed with Claude Code. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Row
—— no roadmap row. A portability bug fix, tracked by issue #308 (kindbug,Row
—, the same shape as #250 / #242 / #296 in the roadmap issue table).Refs #308.
Before starting
open+closed issues for
macOS build,getpid,unistd,htonl,unused function,A76, and all 18 open PRs. Nothing covered any of the threedefects and nothing was claimed. The nearest neighbour is [Bug] macOS MLX build fails because warnings in MLX headers are treated as errors (-Werror) #199 (macOS MLX
-Werroron third-party MLX headers), which is CLOSED and is a differentfailure: it is the opt-in
VLLM_CPP_MLXpreview build hitting warnings in/usr/local/include/mlx, whereas these six targets fail in the defaultcmake -S . -B buildconfiguration in first-party sources.scripts/ready-for-helper.pynot applicable —this is not a row claim.
::getpid()call sites and their includelists;
tests/vllm/entrypoints/openai/test_api_server.cpp:404/412/1620/1640(the same socket dance, already unqualified, already green in your CI); the
#if defined(__linux__)blocks already inexamples/cpu_kernel_bench/main.cpp(
SetAffinity,ThrottlingStatus, thePerfGroupstub, thea76half ofMakeCounterGroups);scripts/build-macos-release.shand themacos-15lanesin
release.yml; everyruns-oninci.yml.What changed
Three independent macOS portability defects that together prevent the test tree
from building at all on Apple clang.
<unistd.h>is now included in the fivetranslation units that call
::getpid()without it — three of which fail tocompile today, two of which compile only via a transitive include and would fail
the moment the header carrying it is tidied. The four byte-order calls in the two
lmcache mock servers are now unqualified, because POSIX permits
htonl/ntohsto be macros and the Darwin SDK defines them as parenthesised expressions that
::cannot precede. AndA76Event(withParsePerfEvent, its only caller) nowsits inside the
#if defined(__linux__)guard the file already uses, so it is nolonger dead code tripping
-Werror,-Wunused-functionoff-Linux. Nothing isdeleted, no
#ifdef __APPLE__is introduced, and the Linux build is unchanged inbehaviour.
Evidence
Three commits, one per defect class, each independently buildable.
Red, before the fix —
cmake -S . -B build && cmake --build build -j -- -kon macOS 26.5.2 / AppleClang 21.0.0, six targets failing,
EXIT=2:(
-- -kon purpose: without it the build stops at the first of the six and theother two classes stay hidden.)
Green, after the fix, macOS. The whole default configuration, not just the
six targets — which is also the evidence that there is no seventh failure
behind them:
The affected test binaries also run (the two latent ones included):
Green on Linux — gcc 14.4.0 / glibc 2.41 / aarch64, configured the way
build-test-cpudoes (-DVLLM_CPP_BUILD_TESTS=ON): the same targets build with0 errors and 0 warnings and the same 7 tests pass. This is the lane that matters
for the
A76Eventchange, because the A76 path is live there and the guard mustnot remove it.
Why the include sweep covers five files and not three. The three that fail
are the ones the build can see;
tests/capi/test_capi.cppandtests/vllm/test_gguf.cpphave the identical defect and are carried by atransitive include today. Repairing them is this tree's own convention rather
than an imported one — measured across the 369 test
.cppfiles, only 4% of(TU, standard header) pairs rely on a transitive include (
<cstring>and<thread>0%,<vector>1%,<string>4%). Happy to drop those two hunks ifyou would rather keep the diff to what the compiler currently rejects.
Gates — each run separately, exit status captured on its own (never through a
pipe), arguments as CI passes them (
--base= the currentmaintip, not thebranch point):
Both gates that could plausibly rubber-stamp this diff were checked against
known-bad input first, so their OK means something:
check-commit-trailers.pyrejects the same message with the
FOLLOWING_AGENTS_PROTOCOLparagraph removed,and rejects it again with a
Co-authored-by:naming an AI;check-pr-size.pyfails closed on an unclassified path (
unclassified repository path 'unclassified-probe.txt', rc 1) on a scratch commit.test_kv_offload_fs,test_kv_offload_tiering,test_kv_offload_connector,test_lmcache_client,test_lmcache_connector,test_capi,test_gguf(build + run) and
vllm-cpu-kernel-bench(build). The compile itself isthe regression surface here — a build failure has no assertion to write,
and the red output above is the failing-first evidence.
check-doc-checkpoint.pyagrees — nolifecycle move, no measurement, and no
USER_USAGEpath is touched.Speed claims
Honest gaps
scripts/agent-preflight.shwas not run to completion. Its role gaterequires a declared role, and
agent-role.py claim helperrequires a--row <ROW-ID>that does not exist for this bug. Inventing an ID would havewritten a false entry into records whose value is that they are true, which
seemed worse than saying this plainly. The record gates it wraps that are
relevant to this diff were run individually and are quoted above. Happy to redo
it under a row if you want one opened.
src/vllm/entrypoints/openai/server_main.cppis untouched on purpose. Itcalls
getpid()unqualified and includes<unistd.h>itself, so it is alreadycorrect; it is also under
USER_USAGE_PREFIXESincheck-doc-checkpoint.py,so editing it would owe a
docs/USAGE.mdupdate for a change that fixesnothing.
configuration other than the default — in particular the
VLLM_CPP_MLXpreviewbuild of [Bug] macOS MLX build fails because warnings in MLX headers are treated as errors (-Werror) #199 was not exercised. The three fixes are architecture-independent,
but that is reasoning, not a measurement.
with the
htonlchange without re-reading the include sweep. Say the word andI will squash them.
recurring: every build lane in
ci.ymlisubuntu-*, and themacos-15release lane builds only
--target server test_metal_backend, so the macOStest tree is built by no job at all. A
macos-15build-tests job would closethat, but it is a CI policy call with runner-cost implications rather than part
of the repair, so it is written up in the issue instead of smuggled in here.