Skip to content

Commit 3c9a912

Browse files
committed
Tried to fix OpenMP importing error.
1 parent 92333a9 commit 3c9a912

2 files changed

Lines changed: 60 additions & 39 deletions

File tree

.github/workflows/python-app.yml

Lines changed: 54 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -285,14 +285,12 @@ jobs:
285285
# would break the minos guarantee of macosx_10_15 / macosx_11_0 wheels).
286286
#
287287
# Previously this caused "symbol not found in flat namespace
288-
# '___kmpc_dispatch_deinit'" at import time. Root cause: that symbol is
289-
# an Intel-private OpenMP extension emitted by clang's -fopenmp when
290-
# dynamic/guided schedules are used, but the LLVM openmp *runtime* we build
291-
# from source deliberately omits it (it was removed in LLVM 13).
292-
# Fix: pass -fno-openmp-extensions at compile time so clang never emits a
293-
# reference to __kmpc_dispatch_deinit (or any other Intel-private symbol).
294-
# The resulting .so is pure OpenMP-standard and links cleanly against our
295-
# self-built libomp whose minos == the wheel deployment target.
288+
# '___kmpc_dispatch_deinit'" at import time. Root cause: Apple Clang emits
289+
# calls to __kmpc_dispatch_deinit for schedule(dynamic/guided) loops, but the
290+
# LLVM openmp runtime we build from source omits it (removed in LLVM 13).
291+
# -fno-openmp-extensions does NOT suppress this symbol on modern Apple Clang.
292+
# Fix: inject a no-op __kmpc_dispatch_deinit stub into the CI libomp build
293+
# (see build_macos_ci_libomp.sh) so bundled libomp satisfies the reference.
296294
- name: Cache CI libomp (macOS)
297295
if: runner.os == 'macOS'
298296
uses: actions/cache@v4
@@ -613,10 +611,9 @@ jobs:
613611
#
614612
# Previously this command pre-loaded Homebrew libomp via DYLD_LIBRARY_PATH,
615613
# which masked a "symbol not found in flat namespace '___kmpc_dispatch_deinit'"
616-
# bug: delocate bundles the LLVM-source libomp (no dispatch_deinit), but
617-
# clang emits a call to dispatch_deinit unless -fno-openmp-extensions is used.
618-
# The pre-load caused CI tests to pass while users hit the error locally.
619-
# Fix: test without any system-libomp fallback so the CI gate is honest.
614+
# bug: delocate bundles the LLVM-source libomp unless our dispatch_deinit stub
615+
# is present. The pre-load caused CI tests to pass while users hit the error
616+
# locally. Fix: test without any system-libomp fallback so the CI gate is honest.
620617
CIBW_TEST_COMMAND_MACOS: |
621618
echo "=== Testing macOS wheel (bundled libomp only — no DYLD_LIBRARY_PATH fallback) ==="
622619
echo "Architecture: $(uname -m)"
@@ -653,18 +650,17 @@ jobs:
653650
print(f'[ERROR] Failed to import sequenzo: {e}')
654651
sys.exit(1)
655652
656-
# clustering_c_code uses OpenMP — this is the module that previously
657-
# triggered "symbol not found in flat namespace '___kmpc_dispatch_deinit'".
658-
# If -fno-openmp-extensions was not applied at compile time, this will fail
659-
# even with the bundled libomp.
653+
# clustering_c_code uses OpenMP dynamic schedules — this module previously
654+
# triggered "symbol not found in flat namespace '___kmpc_dispatch_deinit'"
655+
# when bundled libomp lacked the dispatch_deinit compatibility stub.
660656
try:
661657
import sequenzo.clustering.clustering_c_code
662658
print('[OK] clustering_c_code loaded (bundled libomp sufficient)')
663659
except ImportError as e:
664660
print(f'[ERROR] clustering_c_code failed to load: {e}')
665661
if 'kmpc_dispatch_deinit' in str(e):
666662
print('[ERROR] ___kmpc_dispatch_deinit missing from bundled libomp.')
667-
print('[ERROR] Ensure -fno-openmp-extensions is passed at compile time.')
663+
print('[ERROR] Ensure build_macos_ci_libomp.sh injects the dispatch_deinit stub.')
668664
sys.exit(1)
669665
670666
try:
@@ -813,39 +809,65 @@ jobs:
813809
run: ls -lah dist/
814810
shell: bash
815811

816-
# Verify that macOS .so files do NOT reference ___kmpc_dispatch_deinit.
817-
# If this symbol appears as an undefined reference it means -fno-openmp-extensions
818-
# was not applied correctly; the bundled LLVM libomp built from source never exports
819-
# it (removed in LLVM 13), so any user who installs the wheel would hit a dlopen
820-
# "symbol not found in flat namespace" error at runtime.
821-
- name: Verify no Intel-private OpenMP symbols in macOS .so files
812+
# Verify macOS wheels can resolve ___kmpc_dispatch_deinit at load time.
813+
# Apple Clang emits calls to __kmpc_dispatch_deinit for schedule(dynamic/guided)
814+
# loops; -fno-openmp-extensions does NOT suppress this on modern Apple Clang.
815+
# nm -u on a linked .so lists the symbol as undefined (U) because it is resolved
816+
# from bundled libomp at dlopen time — that is expected and OK when libomp exports it.
817+
- name: Verify OpenMP dispatch_deinit resolvable in macOS wheels
822818
if: runner.os == 'macOS'
823819
run: |
824820
set -euo pipefail
825-
echo "=== Checking for ___kmpc_dispatch_deinit in built .so files ==="
821+
echo "=== Checking ___kmpc_dispatch_deinit resolution in macOS wheels ==="
826822
FOUND_BAD=0
827823
for whl in dist/*.whl; do
828824
echo "Inspecting: $whl"
829825
TMPDIR_WHL=$(mktemp -d)
830826
unzip -q "$whl" -d "$TMPDIR_WHL"
827+
828+
LIBOMP=""
829+
while IFS= read -r -d '' dylib; do
830+
case "$(basename "$dylib")" in
831+
libomp*.dylib) LIBOMP="$dylib"; break ;;
832+
esac
833+
done < <(find "$TMPDIR_WHL" -path '*/.dylibs/*.dylib' -print0)
834+
835+
if [ -z "$LIBOMP" ]; then
836+
echo "[ERROR] No bundled libomp.dylib found in $whl"
837+
FOUND_BAD=1
838+
rm -rf "$TMPDIR_WHL"
839+
continue
840+
fi
841+
842+
if nm -g "$LIBOMP" 2>/dev/null | grep -q '__kmpc_dispatch_deinit'; then
843+
echo "[OK] Bundled libomp exports __kmpc_dispatch_deinit: $LIBOMP"
844+
LIBOMP_HAS_DEINIT=1
845+
else
846+
echo "[ERROR] Bundled libomp missing __kmpc_dispatch_deinit stub: $LIBOMP"
847+
LIBOMP_HAS_DEINIT=0
848+
FOUND_BAD=1
849+
fi
850+
831851
while IFS= read -r -d '' so_file; do
832852
if nm -u "$so_file" 2>/dev/null | grep -q '___kmpc_dispatch_deinit'; then
833-
echo "[ERROR] ___kmpc_dispatch_deinit found as undefined in: $so_file"
834-
echo " This means -fno-openmp-extensions was not applied."
835-
echo " Users will see 'symbol not found in flat namespace' at import time."
836-
FOUND_BAD=1
853+
if [ "$LIBOMP_HAS_DEINIT" -eq 1 ]; then
854+
echo "[OK] $so_file references dispatch_deinit; bundled libomp provides it"
855+
else
856+
echo "[ERROR] $so_file references dispatch_deinit but libomp lacks stub"
857+
FOUND_BAD=1
858+
fi
837859
else
838-
echo "[OK] $so_file — no Intel-private OMP symbols"
860+
echo "[OK] $so_file — no dispatch_deinit reference (static OpenMP schedules)"
839861
fi
840862
done < <(find "$TMPDIR_WHL" -name "*.so" -print0)
841863
rm -rf "$TMPDIR_WHL"
842864
done
843865
if [ "$FOUND_BAD" -eq 1 ]; then
844-
echo "[FATAL] One or more .so files reference ___kmpc_dispatch_deinit."
845-
echo " Ensure -fno-openmp-extensions is passed at compile time."
866+
echo "[FATAL] macOS wheel OpenMP symbol check failed."
867+
echo " Ensure build_macos_ci_libomp.sh injects the dispatch_deinit stub."
846868
exit 1
847869
fi
848-
echo "=== All macOS .so files are clean ==="
870+
echo "=== All macOS wheels pass OpenMP symbol verification ==="
849871
shell: bash
850872

851873
- name: Check wheels

setup.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -412,13 +412,12 @@ def get_compile_args_for_file(filename, *, fast_math=True):
412412
if has_openmp_support():
413413
if sys.platform == 'darwin':
414414
# macOS: use libomp with separated compile/link flags.
415-
# -fno-openmp-extensions suppresses Intel-private OpenMP symbols
416-
# (e.g. __kmpc_dispatch_deinit) that clang emits by default but
417-
# the LLVM openmp runtime built from source does not export.
418-
# Without this flag the .so loads fine against Homebrew libomp
419-
# but fails with "symbol not found in flat namespace" against any
420-
# self-built libomp (used in CI to enforce the minos deployment
421-
# target of the wheel, e.g. 10.15 or 11.0).
415+
# -fno-openmp-extensions suppresses some Intel-private OpenMP symbols.
416+
# Note: Apple Clang still emits __kmpc_dispatch_deinit for
417+
# schedule(dynamic/guided) loops even with this flag; CI-built
418+
# libomp includes a compatibility stub (build_macos_ci_libomp.sh).
419+
# Homebrew libomp already exports the symbol; self-built LLVM libomp
420+
# needs the stub to avoid "symbol not found in flat namespace".
422421
openmp_flag = ['-Xpreprocessor', '-fopenmp', '-fno-openmp-extensions']
423422
print("[SETUP] macOS OpenMP flags: -Xpreprocessor -fopenmp -fno-openmp-extensions")
424423
else:

0 commit comments

Comments
 (0)