macOS: OMP Error #15 (duplicate libomp) aborts at first parallel region
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Idoneità per principianti
- 35/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- macos, python
- Ambito
- build-system, ci-cd, operating-systems, testing-qa
Direzione di ricerca
Start by rerunning the downstream macOS job against current main and inspect the compiler/libomp diagnostic added around setup.py. Then use otool -L or DYLD_PRINT_LIBRARIES=1 and exercise sbd::tpb::diag, not just the import, to identify both runtimes. Done means the cause is confirmed and either a reproducible macOS CI test, a selected build-path fix, or documented guidance is agreed.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
On macOS, a process that loads sbd._core_cpu can abort at SBD's first parallel region:
OMP: Error #15: Initializing libomp.dylib, but found libomp.dylib already initialized.
Signal: Abort trap: 6 (6)
[ 8] libomp.dylib __kmpc_fork_call + 52
[ 9] _core_cpu.cpython-314-darwin.so sbd::GenerateExcitation...
[10] _core_cpu.cpython-314-darwin.so sbd::MakeHelpers...
[11] _core_cpu.cpython-314-darwin.so sbd::tpb::diag...
Both names are libomp.dylib — two copies of the same LLVM runtime, not the more familiar Intel libiomp5 vs LLVM libomp clash.
Root cause
Two Homebrew formulae each insist on their own OpenMP, and they arrive by different routes:
_core_cpu.so ──(-fopenmp, under Homebrew LLVM clang)──> Cellar/llvm/<ver>/lib/libomp.dylib
└─(-lopenblas)──> libopenblas.dylib ─────> Cellar/libomp/<ver>/lib/libomp.dylib
Homebrew's openblas depends on libomp (deps: ['gcc', 'libomp']) and loads that copy at run time. Homebrew's llvm builds the openmp runtime, so its clang carries a libomp.dylib of its own and -fopenmp links that one. Link both and the process holds two.
Only one of those is on SBD's link line; the other is transitive through OpenBLAS, which is why otool -L on _core_cpu.so does not show it.
Measured by enumerating loaded images through dyld after each import stage:
[baseline] 0 OpenMP image(s)
[after pyscf] 0 OpenMP image(s)
[after qiskit_addon_sqd.fermion (pulls jax)] 0 OpenMP image(s)
[after qiskit + preset passmanager] 0 OpenMP image(s)
[after importing sbd] 0 OpenMP image(s)
compiled backends: ['cpu']
[after sbd.get_backend() -- loads _core_cpu] 2 OpenMP image(s)
/opt/homebrew/Cellar/libomp/23.1.0/lib/libomp.dylib
/opt/homebrew/Cellar/llvm/23.1.0/lib/libomp.dylib
Nothing is mapped until get_backend(), because since #23 the backends load lazily, one per process, on first use. That is why the abort lands at the first parallel region rather than at import — and why a probe that only imports sbd sees nothing.
When this bites
Only when the build uses a compiler that ships its own OpenMP. Under Apple clang there is no second copy: Apple clang has no OpenMP of its own, so SBD takes libomp from the standalone Homebrew formula — the same file OpenBLAS loads. One runtime, no conflict. That is why this repo's own macOS CI has always been green.
It reproduces when CC/CXX is pinned to Homebrew LLVM, which is what Qiskit/qiskit-addon-sqd#367 did, in order to build another extension (fulqrum passes a bare -fopenmp that Apple clang rejects).
What this is not
Several plausible explanations were checked and ruled out:
pyscflinks no OpenMP at all. It was the leading suspect and is not involved.qiskit-aerships a bundledlibomp.dylib— the only bundled OpenMP in the environment — but it is never imported by the notebook in question (sys.modules has qiskit_aer: False) and its copy is not among the mapped images.ffsimuses Rust/Rayon, not OpenMP.- Not a cross-notebook effect: under
nbmakeeach notebook gets its own kernel. - Not fixable from the consumer's
LDFLAGS/CPPFLAGSalone:setup.pychose its libomp from hardcoded paths and ignored those variables. (That part is addressed on thedarwin-single-libompbranch; see below.)
Ways out
- Build with Apple clang and let the standalone
libompserve both SBD and OpenBLAS. Simplest, and what this repo's CI does. Downstream this means not pinning a compiler job-wide — #367 now builds each compiled dependency with the compiler it needs, and its macOS job is green with the released 1.6.1, so no new release is required for that. - Use a conda (or pixi) environment, where one
llvm-openmpserves the compiler and the BLAS alike. This is the only option that also covers users rather than just CI, and #23's conda-first preference already points at it. Worth stating outright in the README for macOS. - Use a BLAS not tied to a second OpenMP — Accelerate, or a conda-provided OpenBLAS. This is what would make a Homebrew-LLVM build viable at all.
Note that 1 and 2 leave a sharp edge: if two extensions in one process are built by different compilers, they can still end up with different libomps. Measured downstream — SBD under Apple clang plus fulqrum under Homebrew LLVM gives 2 images again, even though each works alone. The durable fix for that pairing is for fulqrum to accept Apple clang (-Xpreprocessor -fopenmp), after which one runtime serves everything.
Not the fix
KMP_DUPLICATE_LIB_OK=TRUE suppresses the abort, and the runtime's own hint offers it — as "an unsafe, unsupported, undocumented workaround" that "may cause crashes or silently produce incorrect results." For an eigensolver, trading a clean abort for possibly-wrong energies is the wrong trade.
Status
- Linux is unaffected throughout.
- The
darwin-single-libompbranch makessetup.pyprefer a libomp shipped beside the compiler, which removes SBD's direct second copy. It does not fix this issue — OpenBLAS still supplies one — so #34 was closed rather than merged; see that PR for the measurements. The branch is a reasonable starting point once option 3 exists. - Two incidental findings worth recording, since each cost a debugging round:
omp.hlives in the clang resource directory (lib/clang/<ver>/include), not<prefix>/include. Askclang++ -print-resource-dir.- tox discards the build backend's output at default verbosity, stdout and stderr alike, so a
setup.pythat picks the wrong OpenMP leaves no trace in CI.tox -vvshows it.
This issue body was updated by Claude Opus 5 under my guidance.
- Lingua principale
- Python
- Stelle
- 2
- Fork
- 1
- Merge medio
- 1g 10h
- PR unite (30g)
- 23
Preparare l'ambiente
Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di Qiskit/sbd-eigensolver-python
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
Qiskit/sbd-eigensolver-python#31 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 64/100
Qiskit/sbd-eigensolver-python#22 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 55/100
Qiskit/sbd-eigensolver-python#9 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
Qiskit/sbd-eigensolver-python#6 ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di Qiskit/sbd-eigensolver-python
Issue simili
-
P4: low tooling
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
jeffknupp/association#318 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
petercorke/robotics-toolbox-python#709 ·
I maintainer di solito rispondono entro 2 giorni
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
MakerYuichi/Aegis-pro#114 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
I maintainer di solito rispondono entro 2 giorni
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
mpfaffenberger/code_puppy#985 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno