Skip to content

fix(make): MacPorts libomp built every macOS engine single-threaded - #1599

Merged
JustVugg merged 3 commits into
JustVugg:devfrom
crichalchemist:macos-macports-libomp
Sep 18, 2026
Merged

JustVugg merged 3 commits into
JustVugg:devfrom
crichalchemist:macos-macports-libomp

Conversation

@crichalchemist

Copy link
Copy Markdown
Contributor

The libomp probe in c/Makefile derives -I and -L from one prefix and only knows Homebrew's layout. MacPorts (port install libomp) puts the header at include/libomp/omp.h and the library at lib/libomp/libomp.dylib, one level deeper on both sides, so no prefix can ever satisfy the check. On such a Mac every build prints libomp not found: building single-threaded and means it — the OpenMP pragmas are silently discarded across all nine engines, with nothing else to tell the user the warning is wrong.

Found while forward-merging #1338 on an x86_64 Mac with MacPorts libomp 21.1.7; kept out of that PR because it is unrelated to the Vulkan tier.

c/Makefile — the probe resolves separate OMPINC / OMPLIB directories. The Homebrew prefix check is unchanged and still comes first (including the CLT-only fallback to /opt/homebrew/opt/libomp and /usr/local/opt/libomp); MacPorts' two directories are probed directly when it fails — but only when OMPDIR was not the user's choice. An explicit OMPDIR, from the command line or the environment, is taken as given: with libomp inside it is used, without it the build is single-threaded, which tests/test_makefile_platform.py pins (OMPDIR=/colibri-test/missing-libomp must not yield -fopenmp). An environment OMPDIR used to be overwritten by the probe's own := assignment; its origin is now read before that assignment, so it counts as the choice it is. The warning names both install spellings.

c/Makefile.deepseek-v4 — carries its own copy of the probe and had already drifted from the parent block its comment claims to mirror: it lacked the CLT-only fallback. Both blocks are identical again, modulo each file's spacing.

c/qwen38_core.h — workers is read only by num_threads(workers); without OpenMP the pragma is gone and clang reports it unused. Discharged in the #else of the existing _OPENMP guard; the OpenMP build is untouched.

c/tests/test_olmoe_matmul_q.c — HAVE_FAST_DOT_I8 is defined under __ARM_NEON or __AVX2__, and the test binaries compile without -march, so on x86_64 the SKIP branch is taken with failures declared and never read. Discharged on that branch. Pre-existing and unrelated to OpenMP — simply the other warning an x86_64 Mac meets on the way to the 0-warning bar.

docs/quickstart.md — the MacPorts spelling next to the Homebrew one.

Verified on a 2017 iMac (x86_64, macOS 13, Apple clang, MacPorts libomp 21.1.7), from a clean binary each time:

check result
plain make qwen38 (no flags) probe warning gone, 0 warnings, otool -L shows /opt/local/lib/libomp/libomp.dylib
Homebrew-shaped prefix as OMPDIR, command line and environment (dry runs) -I$(OMPDIR)/include -L$(OMPDIR)/lib -lomp — the primary branch is unchanged, and the environment is honoured
OMPDIR=/nonexistent, command line and environment (dry runs) libomp not found, no -fopenmp — the explicit choice wins
forced no-OpenMP build, make qwen38 OMPC= OMPL= 0 warnings — the workers fix holds
Makefile.deepseek-v4 with UNAME_M=arm64, plain and with a bogus environment OMPDIR (dry runs) same flags and same refusal as the parent; the mirrored block behaves identically
python3 -m unittest tests.test_makefile_platform 3/3 OK
make check exit 0, 0 compiler warnings, Python suite 970 tests OK (105 skipped), OpenMP active on 43 compile lines

One thing this changed on purpose during review: my first cut let a bogus OMPDIR fall through to MacPorts, and test_darwin_portable_build_does_not_force_x86_architecture caught it. The test is right — the fallback is now gated on $(origin OMPDIR).

Not exercised here: a real Homebrew Mac (the macOS CI jobs brew install libomp, so that branch is covered there) and a linked arm64 deepseek_v4 — the file refuses x86_64 macOS, and CI deliberately does not build V4 on macOS either, so the mirrored block is verified by parse and by being identical logic to the parent's, which is verified in full.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NJcbVYkasdfXg5DEsHdSCt

The libomp probe derived -I and -L from one prefix and only knew Homebrew's
layout, so a MacPorts install (`port install libomp`) never matched: it puts
the header at include/libomp/omp.h and the library at lib/libomp/libomp.dylib,
one level deeper on both sides. Every build on such a Mac printed "libomp not
found: building single-threaded" and meant it.

The probe now resolves separate OMPINC / OMPLIB directories. The Homebrew
prefix check is unchanged and still comes first; MacPorts' two directories
are probed directly when it fails -- but only when OMPDIR was not the user's
choice. An explicit OMPDIR, from the command line or the environment, is
taken as given: with libomp inside it is used, without it the build is
single-threaded, which tests/test_makefile_platform.py pins. (An environment
OMPDIR used to be overwritten by the probe's own assignment; it is now read
before that assignment, so it counts as the choice it is.)

Verified on an x86_64 Mac with MacPorts libomp 21.1.7: a plain `make qwen38`
links /opt/local/lib/libomp/libomp.dylib with no probe warning; a
Homebrew-shaped prefix passed as OMPDIR, on the command line or exported,
yields -I$(OMPDIR)/include -L$(OMPDIR)/lib; OMPDIR=/nonexistent either way
stays single-threaded.

Makefile.deepseek-v4 carries its own copy of the probe and had already
drifted from the parent block it claims to mirror (it lacked the
Homebrew-prefix fallback for CLT-only Macs). Both blocks are identical again,
modulo each file's spacing. docs/quickstart.md names the MacPorts spelling
next to the Homebrew one.
… OpenMP

q38's fp8 range loader sizes its team into `workers` and hands it to
`num_threads(workers)`. Without OpenMP the pragma is discarded and clang
reports the variable unused. Discharge it in the #else of the existing
_OPENMP guard; the OpenMP build is untouched.
HAVE_FAST_DOT_I8 is defined under __ARM_NEON or __AVX2__, and the test
binaries compile without -march, so on x86_64 the SKIP branch is taken with
`failures` declared and never read: one -Wunused-variable on every x86_64
macOS and Linux build of the suite. Discharge it on that branch; every
increment lives in the #else.
Copilot AI lite review requested due to automatic review settings September 18, 2026 00:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@JustVugg
JustVugg merged commit f02c202 into JustVugg:dev Sep 18, 2026
28 checks passed
@crichalchemist
crichalchemist deleted the macos-macports-libomp branch September 23, 2026 19:24
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.

3 participants