Skip to content

macOS Metal build broken: CUDA-only symbols missing from metal_compat and Metal stubs (compile at 477ac13, link at a2de744) #2860

Closed as not planned

Description

@maverns

Machine: Apple M5 Max, 128 GB, macOS 27.0.1, Command Line Tools 27.0.0 (Apple clang 21.0.0), SDK 27.0.

Command: ./setup.sh --model UD-Q4_K_XL --vision no --no-browser --no-start --context 196608 --yes. It stops at step 4 with "the Metal engine did not build".

At 477ac13 (current main), the compile fails. Six symbols are missing from metal/include/metal_compat/cuda_runtime.h:

At a2de744 (parent of bc90e1a), everything compiles but the link fails. The undefined symbols are strata::kernels::gdn_step_norm_groups, qsa_block_scores_rows and qsa_decode_attn_batch_rows. They are called from verify.cpp (Verifier::record_window, capture_commit_batch), but there is no Metal definition and no entry in metal/src/engine/stubs.cpp. They were introduced by f629fb0 ("Batch decode: one launch for all rows…").

Possible fix: guard these call sites the way src/core/mtp.cpp already guards its stream-priority calls (#if … && !defined(STRATA_GPU_METAL)), or add Metal stubs.

Activity

  1. oceanio commented on Oct 17, 2026

    @oceanio

    Fix in #2895 (only metal/ changes).

    Two additions to the report, at 477ac13 on an M5 Max (128 GB, macOS 26.7.1, CLT 27.0):

    • Once the six metal_compat symbols are added, the link misses 21 entry points, not 3: gdn_step_norm_groups,
      qsa_block_scores_rows, qsa_decode_attn_batch_rows, qsa_decode_attn_split, fused_gr_persist_init,
      fused_gr_read_persist, handoff_publish, wait_handoff, wait_copy_i32_from_mapped, wait_flag_ge_stamped,
      copy_rows_from_mapped_after, native_quantize_q8_1_il, hc_q8_to_bf16, res_patch, cpu::iq256_gu_rows_exact_one,
      prefill::f16_range_read, prefill::gemm_f16_range_read, and the new f16img overloads of gr_norm, gr_norm_rs,
      gr_write_norm_rs and gr_write_cvec_norm_rs. Gemm::bf16's stub in stubs.cpp also no longer matches (x_f16).
    • Stubs that stop the engine are not enough: the Verifier constructor calls fused_gr_persist_init()
      unconditionally (verify.cpp:646), and fused_gr_read_persist() sits on the hyper-connection read path. These
      need "not available" answers, the way setup_host.cpp answers fused_gr_check().

    v0.1.44.1 builds and runs on the same Mac unchanged; the PR's output is identical to it on the prompts I tried.

  2. cuijs2026 commented on Oct 17, 2026

    @cuijs2026

    Verified #2895 on a different Mac: Apple M4 Pro, 64 GB unified memory, macOS 26.2, Apple clang 21 (17.0.0 (clang-1700.6.3.2)).

    • At 477ac13 unpatched: the same six undefined identifiers at compile (cudaDevAttrComputeCapability* Major/Minor, cudaDeviceGetStreamPriorityRange, cudaStreamCreateWithPriority in verify.cpp; cudaMemcpyPeer, cudaDeviceDisablePeerAccess in peer_experts.cpp), then Gemm::bf16's stub signature mismatch at link stage prep. Confirms maverns' and oceanio's reports.
    • With metal: the Mac engine builds and links again at 0.1.45 (#2860) #2895 applied (checked out onto a clean 0.1.45 tree): ninja -C build-metal strata builds and links clean, no undefined symbols, strata --version prints 0.1.45-metal. engine_current() (setup_mac's BUILD.json digest check) agrees after the stamp is refreshed.

    One note for the PR: before finding this issue I had locally regenerated stubs with metal/tools/gen_stubs.py (empty-first-link pass then the real one). It comes out functionally equal to stubs_145.cpp's list — 262 vs 262 matched — so the PR's hand-written stub list looks complete; the generated route may be a safety net worth mentioning in the Metal update docs, since regenerating needs a link log few will know to produce. Discarded my patch in favor of #2895.

  3. nullspeech commented on Oct 17, 2026

    @nullspeech

    Machine: Apple M2 Max (Mac14,5), 38-core GPU, 96 GB, macOS 15.8 (24H23), Command Line Tools with Apple clang 17.0.0 (clang-1700.0.13.5). Installed SDKs: MacOSX 14.5 / 15.2 / 15.5 — there is no macOS 26 or 27 SDK here, so this is the oldest-toolchain report on the thread.

    At 477ac13c (tag v0.1.45), building build-metal fails in compilation with exactly maverns' six identifiers, seven error lines:

    src/core/peer_experts.cpp:72:13: error: use of undeclared identifier 'cudaMemcpyPeer'
    src/core/peer_experts.cpp:157:29: error: use of undeclared identifier 'cudaDeviceDisablePeerAccess'
    src/core/peer_experts.cpp:158:34: error: use of undeclared identifier 'cudaDeviceDisablePeerAccess'
    src/core/verify.cpp:285:54: error: use of undeclared identifier 'cudaDevAttrComputeCapabilityMajor'
    src/core/verify.cpp:286:54: error: use of undeclared identifier 'cudaDevAttrComputeCapabilityMinor'
    src/core/verify.cpp:859:17: error: use of undeclared identifier 'cudaDeviceGetStreamPriorityRange'
    src/core/verify.cpp:860:17: error: use of undeclared identifier 'cudaStreamCreateWithPriority'
    

    So the break is not a CLT 27 regression: the same six names kill the Metal build on a 15.5 SDK too.

    One thing #2895 will not cover on this OS, which the three reports above cannot show because they all run SDK 26/27: MTLGPUFamilyMetal4 is not declared by any SDK up to macOS 15.5, so metal/src/mtl_rt.mm does not compile here at all without an enum fallback for that constant. We carry a small local patch for it. It touches no file #2895 touches (metal_compat/cuda_runtime.h, stubs.cpp, stubs_145.cpp), so the two stack cleanly — but if 0.1.46 is meant to build on the SDKs macOS 15 users still have, an __has_include / enum-fallback guard in mtl_rt.mm would save them a third patch.

    On the "3 vs 21 undefined symbols" difference: at 477ac13c the compile aborts before anything links, so this box never reaches the link stage. We can only confirm maverns' six names; oceanio's larger link-stage count and cuijs2026's clean link with #2895 are both on newer SDKs and I have no data point either way. I can build v0.1.45 + #2895 + the enum fallback here and report whether it links on a 15.5 SDK, if that's useful.

    Nothing is blocked on our side: we stayed on 0.1.44.1-metal, the updater rolled back by itself, and the server is healthy.

  4. nullspeech commented on Oct 17, 2026

    @nullspeech

    Following up on my report above: the macOS 15 half of this is already written — PR #2388 (open since 2026-10-14, +4/−1, one file).

    metal/src/mtl_rt.mm's supports_metal4() names MTLGPUFamilyMetal4, which is declared only in the macOS 26 SDK, so on macOS 15 the Metal engine does not compile even after #2895 adds the six HIP/CUDA names. The PR declares the same numeric family (5002, which the repo's own vendored metal-cpp already uses at third_party/metal-cpp/Metal/MTLDevice.hpp:193) and casts it at the single call site, leaving the @available(macOS 26.0, *) gate untouched, so a 26-SDK build emits an identical call.

    Two things worth recording for whoever merges:

    • It touches metal/src/mtl_rt.mm only — no overlap with metal: the Mac engine builds and links again at 0.1.45 (#2860) #2895's three files, so the two are independent and can go in either order. A macOS 15 build needs both.
    • This patch is what our v0.1.44.1-metal binary was built with, and that engine has served Flash-Next IQ3_S on this machine since 2026-10-14 without incident, so the change itself is exercised, not theoretical.

    Happy to build v0.1.45 + #2895 + #2388 on this 15.5 SDK and report the result here, so the thread has one data point from an old-toolchain Mac — say the word.

  5. Niko1221 commented on Oct 19, 2026

    @Niko1221
    Owner

    Thanks for taking the time to report this.

    We're resetting the tracker for 0.2.0-beta. There are more than 1,300 open issues and pull requests, too many for us to read properly, so we're closing everything that isn't being worked on right now. Closed here does not mean rejected.

    To reopen it takes about two minutes:

    1. Re-test on 0.2.0-beta. It may already be fixed. Write down what you see.
    2. Start the title with its area: [Engine], [GUI], [TUI], [Benchmark], [Docs] or [Other].
    3. Fill in the parts of the issue form: what happened, the Strata version, your graphics card, memory and system.
    4. Comment /reopen. A check runs and either reopens the issue or lists what is still missing.

    The rules are in CONTRIBUTING.md.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions