From caa714533c0503ca7e90d73339557314908a5341 Mon Sep 17 00:00:00 2001 From: Rory Mitchell Date: Thu, 19 Mar 2026 04:23:21 -0700 Subject: [PATCH] Fix macOS wheel OpenMP dependency resolution --- cmake/FindOpenMPMacOS.cmake | 26 ++++++++++++++++++++--- ops/pipeline/build-python-wheels-macos.sh | 6 ++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/cmake/FindOpenMPMacOS.cmake b/cmake/FindOpenMPMacOS.cmake index 88c1e4cbb53c..4b156a08bb84 100644 --- a/cmake/FindOpenMPMacOS.cmake +++ b/cmake/FindOpenMPMacOS.cmake @@ -1,5 +1,5 @@ # Find OpenMP library on MacOS -# Automatically handle locating libomp from the Homebrew package manager +# Prefer libomp from the active Conda environment and fall back to Homebrew. # lint_cmake: -package/consistency @@ -7,7 +7,22 @@ macro(find_openmp_macos) if(NOT APPLE) message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION}() must only be used on MacOS") endif() - find_package(OpenMP) + + if(DEFINED ENV{CONDA_PREFIX} AND EXISTS "$ENV{CONDA_PREFIX}/lib/libomp.dylib") + set(CONDA_LIBOMP_PREFIX "$ENV{CONDA_PREFIX}") + set(OpenMP_C_FLAGS + "-Xpreprocessor -fopenmp -I${CONDA_LIBOMP_PREFIX}/include") + set(OpenMP_CXX_FLAGS + "-Xpreprocessor -fopenmp -I${CONDA_LIBOMP_PREFIX}/include") + set(OpenMP_C_LIB_NAMES omp) + set(OpenMP_CXX_LIB_NAMES omp) + set(OpenMP_omp_LIBRARY ${CONDA_LIBOMP_PREFIX}/lib/libomp.dylib) + find_package(OpenMP) + endif() + + if(NOT OpenMP_FOUND) + find_package(OpenMP) + endif() if(NOT OpenMP_FOUND) # Try again with extra path info. This step is required for libomp 15+ from Homebrew, # as libomp 15.0+ from brew is keg-only @@ -106,6 +121,7 @@ function(patch_openmp_path_macos target target_default_output_name) ) # Add RPATH entries to ensure the loader looks in the following, in the following order: # + # - $CONDA_PREFIX/lib (when building inside a Conda environment) # - /opt/homebrew/opt/libomp/lib (where 'brew install' / 'brew link' puts libomp.dylib) # - ${__OpenMP_LIBRARY_DIR} (wherever find_package(OpenMP) found OpenMP at build time) # @@ -114,11 +130,15 @@ function(patch_openmp_path_macos target target_default_output_name) execute_process(COMMAND brew --prefix libomp OUTPUT_VARIABLE HOMEBREW_LIBOMP_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE) + set(__OPENMP_RPATHS "${HOMEBREW_LIBOMP_PREFIX}/lib;${__OpenMP_LIBRARY_DIR}") + if(DEFINED ENV{CONDA_PREFIX} AND EXISTS "$ENV{CONDA_PREFIX}/lib/libomp.dylib") + set(__OPENMP_RPATHS "$ENV{CONDA_PREFIX}/lib;${__OPENMP_RPATHS}") + endif() set_target_properties( ${target} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE - INSTALL_RPATH "${HOMEBREW_LIBOMP_PREFIX}/lib;${__OpenMP_LIBRARY_DIR}" + INSTALL_RPATH "${__OPENMP_RPATHS}" INSTALL_RPATH_USE_LINK_PATH FALSE ) endfunction() diff --git a/ops/pipeline/build-python-wheels-macos.sh b/ops/pipeline/build-python-wheels-macos.sh index 9c04032d8587..7376e8199daa 100755 --- a/ops/pipeline/build-python-wheels-macos.sh +++ b/ops/pipeline/build-python-wheels-macos.sh @@ -36,6 +36,12 @@ else exit 2 fi +# Prefer Conda's OpenMP runtime for wheel builds on macOS. Homebrew's libomp can +# pull in Homebrew LLVM's libunwind, which raises the effective deployment target +# of the repaired wheel. +conda install -y llvm-openmp +export CMAKE_PREFIX_PATH="${CONDA_PREFIX}${CMAKE_PREFIX_PATH:+:${CMAKE_PREFIX_PATH}}" + # Tell delocate-wheel to not vendor libomp.dylib into the wheel export CIBW_REPAIR_WHEEL_COMMAND_MACOS="delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel} --exclude libomp.dylib"