Skip to content

fix(metal/mlx): keep MLX's own header warnings out of our -Werror (#199) - #215

Merged
mudler merged 1 commit into
mainfrom
row/BACKEND-METAL-MLX-WERROR
Aug 9, 2026
Merged

fix(metal/mlx): keep MLX's own header warnings out of our -Werror (#199)#215
mudler merged 1 commit into
mainfrom
row/BACKEND-METAL-MLX-WERROR

Conversation

@localai-bot

Copy link
Copy Markdown
Collaborator

Closes #199.

Why the SYSTEM include we already have does not help

cmake/MLXDependency.cmake marks the MLX include directory SYSTEM, so in principle MLX's own warnings never reach us. The intent evaporates on the reporter's install prefix: CMake drops any include directory that is already one of the compiler's implicit ones, and /usr/local/include is exactly that — and exactly where common MLX installs put their headers. No -isystem is emitted at all, the headers are found through the compiler's own search, and every warning in them lands under this TU's -Werror.

Measured rather than reasoned about, on a CMake 3.28 probe with an imported target carrying INTERFACE_SYSTEM_INCLUDE_DIRECTORIES:

MLX_ROOT flag emitted
an ordinary directory -isystem <dir>/include
/usr/local none — the directory is dropped

That explains why this reproduces across MLX 0.30.6 / 0.31.2 / 0.32.0 and macOS 26.6.0 / 26.6.1 alike: it is not an MLX regression, it is our include reaching the compiler unmarked.

The change

The MLX include region already had a #pragma clang diagnostic push/ignored block for -Wgnu-folding-constant. The two reported diagnostics join it, each annotated with the MLX header that raises it so it can be retired when MLX fixes it.

Scoped to the include region on purpose — demoting them file-wide would also demote them for our code below, and -Wunused-parameter is worth keeping there.

Not fixed by forcing -isystem /usr/local/include onto the command line: an explicit -isystem on a standard search directory reorders the search and is a well-known way to break a toolchain's own headers. CMake drops those directories deliberately.

Evidence, and its limit

With headers reached the /usr/local way, an MLX-shaped allocator.h under -Wall -Wextra -Werror reproduces the reporter's three -Wunused-parameter errors exactly; behind -isystem the same headers are silent; and a push/ignored block around the include region silences them while a deliberately unused parameter after the pop still fails the build.

Run with GCC 13 — there is no clang on this box — so the warning names and the scoping are verified, the #pragma clang spelling is not. The names are Apple Clang's own, from the issue.

@flamby — could you confirm this builds on your setup? CI has no macOS+MLX lane, which is how the one file whose job is bridging a third-party dependency broke unnoticed.

A macOS MLX build fails compiling `metal_mlx_provider.mm`, on MLX 0.30.6, 0.31.2
and 0.32.0 alike and on macOS 26.6.0 and 26.6.1 alike, with four errors that are
all inside MLX's headers:

    /usr/local/include/mlx/allocator.h:39: error: unused parameter 'ptr'
    /usr/local/include/mlx/allocator.h:39: error: unused parameter 'size'
    /usr/local/include/mlx/allocator.h:42: error: unused parameter 'buffer'
    /usr/local/include/mlx/types/bf16.h:29: error: definition of implicit copy
        assignment operator for '_MLX_BFloat16' is deprecated ...

We already intend for this not to happen: cmake/MLXDependency.cmake marks the
MLX include directory SYSTEM. The reason the intent evaporates is the reporter's
install prefix. CMake removes any include directory that is already one of the
compiler's implicit ones, and `/usr/local/include` is one — so for
`-DMLX_ROOT=/usr/local` **no `-isystem` is emitted at all**, the headers are
found through the compiler's own search, and every warning in them lands under
this TU's `-Werror`.

Measured here rather than reasoned about, on a CMake 3.28 probe with an imported
target carrying INTERFACE_SYSTEM_INCLUDE_DIRECTORIES:

    MLX_ROOT=<ordinary dir>  ->  -isystem <dir>/include
    MLX_ROOT=/usr/local      ->  no include flag at all; the directory is dropped

Then, with the headers reached that way, an MLX-shaped `allocator.h` under
`-Wall -Wextra -Werror` reproduces the reporter's three `-Wunused-parameter`
errors exactly; behind `-isystem` the same headers are silent; and a
push/ignored block around the include region silences them while a deliberately
unused parameter in the code AFTER the pop still fails the build. (GCC 13 here —
no clang on this box — so the pragma spelling itself is unverified locally; the
warning names are Apple Clang's, from the issue.)

Fixed at the include region, which already had such a block for
-Wgnu-folding-constant, rather than by demoting the diagnostics for the whole
file: -Wunused-parameter is worth keeping for our own code below. Each entry
names the MLX header that raises it so it can be retired when MLX fixes it.

Not fixed by forcing `-isystem /usr/local/include` onto the command line: an
explicit -isystem on a standard search directory reorders the search and is a
well-known way to break a toolchain's own headers. CMake drops those directories
deliberately.

Reporter verification is the gate: CI has no macOS+MLX lane, which is why the
one file whose job is to bridge a third-party dependency broke unnoticed.

FOLLOWING_AGENTS_PROTOCOL
Assisted-by: Claude Code:claude-opus-5 [ClaudeCode]
@mudler
mudler merged commit 785e297 into main Aug 9, 2026
11 of 13 checks passed
@flamby

flamby commented Aug 10, 2026

Copy link
Copy Markdown

Thanks for landing #215 — that fixed the original -Werror failures in MLX headers (-Wunused-parameter / -Wdeprecated-copy) when compiling metal_mlx_provider.mm.

What I hit next

1. Linking against a static libmlx.a (environment, not the pragma fix)
With MLX_ROOT=/usr/local I only had /usr/local/lib/libmlx.a. The link then failed with many undefined Accelerate symbols (*_$NEWLAPACK, BNNSFilter*, etc.), because CMake links libmlx but does not pull in -framework Accelerate for a static archive.

Switching to the pip wheel fixed that:

# MLX from a venv → libmlx.dylib + mlx.metallib
cmake -S . -B build-metal \
  -DVLLM_CPP_MLX=ON \
  -DMLX_ROOT="$HOME/dev/mlx-venv/lib/python3.14/site-packages/mlx"

2. Full cmake --build build-metal -j still fails on macOS (this was the main remaining blocker)
After MLX linked correctly, a plain full build still died on an example that is Linux-oriented:

examples/cpu_kernel_bench/main.cpp:447:26: error: unused function 'A76Event'
  [-Werror,-Wunused-function]

A76Event is only used under #if defined(__linux__), but the function itself is defined unconditionally. On macOS it is unused, and with -Werror that breaks vllm-cpu-kernel-bench and therefore target all.

So for a contributor doing the obvious “configure + build everything” flow on Apple Silicon, the failure looks like a Metal/MLX problem, but the hard error is this Linux PMU helper in a CPU bench example.

How I compiled and tested successfully

Build only the Metal/MLX targets (avoids cpu_kernel_bench):

cmake -S . -B build-metal \
  -DVLLM_CPP_MLX=ON \
  -DMLX_ROOT="$HOME/dev/mlx-venv/lib/python3.14/site-packages/mlx" \
  -DVLLM_CPP_BUILD_EXAMPLES=ON

cmake --build build-metal --target server test_metal_backend -j

Both completed (vllm-server and test_metal_backend).

server: tool-call parser hermes, reasoning parser disabled
server: utility endpoints: /tokenize /detokenize on
server: GET /metrics enabled (PrometheusStatLogger)
server: listening on http://0.0.0.0:8000 (model 'Qwen/Qwen3-0.6B', HTTP worker pool 36 fixed)
INFO api: POST /v1/chat/completions body_bytes=113 t+59060ms
INFO Received request chatcmpl-0 endpoint=/v1/chat/completions model=Qwen/Qwen3-0.6B stream=0 max_tokens=64 msgs=1 tools=0 prompt_chars=76 roles=user(7) prompt: '<|im_start|>user\nBonjour<|im_end|>\n<|im_start|>assistant\n<think>\n\n</think>\n\n'
[vt reference-tier] op=30 device=2 has NO native kernel; running the PORTABLE CPU fallback (correct but slow)
[vt reference-tier] op=33 device=2 has NO native kernel; running the PORTABLE CPU fallback (correct but slow)
[vt reference-tier] op=35 device=2 has NO native kernel; running the PORTABLE CPU fallback (correct but slow)
INFO Finished request chatcmpl-0 prompt_tokens=13 completion_tokens=24 total_tokens=37 finish_reason=stop elapsed_s=0.940577 gen_tok_s=25.5162

Suggestion

Worth either:

  • wrapping A76Event (and any other Linux-only helpers) in #if defined(__linux__), or
  • documenting that macOS Metal+MLX users should build server / test_metal_backend rather than all,

so a clean tree doesn’t fail -Werror on Apple hosts for code that only applies on Linux.

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.

[Bug] macOS MLX build fails because warnings in MLX headers are treated as errors (-Werror)

3 participants