Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BLD: Set rpath for libomp on MacOS to fix compatibility with latest XGBoost version #123

Merged
merged 11 commits into from
Oct 18, 2024
5 changes: 4 additions & 1 deletion .github/workflows/nonvendored_wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,13 @@ jobs:
python-version: "3.10"

- name: Install cibuildwheel
run: python -m pip install cibuildwheel==2.18.0
run: python -m pip install cibuildwheel==2.21.3

- name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse
env:
CIBW_REPAIR_WHEEL_COMMAND_MACOS: "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}"
CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=12.0 CMAKE_ARGS="-DSDTN_ENABLE_ARCH_FLAGS=OFF -DSDTN_DISABLE_OPENMP=ON"

- name: Verify clean directory
run: git diff --exit-code
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
- name: Clone OpenMP repo
if: matrix.os == 'macos-latest' && steps.clone-openmp.outputs.cache-hit != 'true'
run: |
git clone --depth 1 --branch llvmorg-17.0.6 https://github.com/llvm/llvm-project
git clone --depth 1 --branch llvmorg-19.1.1 https://github.com/llvm/llvm-project


- name: Build OpenMP
Expand All @@ -81,7 +81,7 @@ jobs:
cmake --build openmp_build --target install --config Release

- name: Install cibuildwheel
run: python -m pip install cibuildwheel==2.21.2
run: python -m pip install cibuildwheel==2.21.3

- name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse
Expand All @@ -90,7 +90,7 @@ jobs:
CIBW_TEST_COMMAND: pytest {project}/tests && python -c "from sparse_dot_topn import _has_openmp_support;assert _has_openmp_support"
# only build for arm; x86_64 wheels are build seperately
CIBW_ARCHS_MACOS: "arm64"
CIBW_ENVIRONMENT_MACOS: PATH="$HOME/.local/:$PATH" MACOSX_DEPLOYMENT_TARGET="12.0" DYLD_LIBRARY_PATH="$HOME/.local/libomp/lib" CMAKE_ARGS="-DSDTN_ENABLE_ARCH_FLAGS=OFF -DSDTN_ENABLE_OPENMP=ON -DSDTN_DISABLE_OPENMP=OFF -DOpenMP_ROOT=$HOME/.local/libomp"
CIBW_ENVIRONMENT_MACOS: PATH="$HOME/.local/:$PATH" MACOSX_DEPLOYMENT_TARGET=12.0 DYLD_LIBRARY_PATH="$HOME/.local/libomp/lib" CMAKE_ARGS="-DSDTN_ENABLE_ARCH_FLAGS=OFF -DSDTN_VENDOR_OPENMP=ON -DSDTN_ENABLE_OPENMP=ON -DSDTN_DISABLE_OPENMP=OFF -DOpenMP_ROOT=$HOME/.local/libomp"

- name: Verify clean directory
run: git diff --exit-code
Expand Down Expand Up @@ -123,7 +123,7 @@ jobs:
- name: Clone OpenMP repo
if: steps.clone-openmp.outputs.cache-hit != 'true'
run: |
git clone --depth 1 --branch llvmorg-17.0.6 https://github.com/llvm/llvm-project
git clone --depth 1 --branch llvmorg-19.1.1 https://github.com/llvm/llvm-project

- name: Build OpenMP
shell: bash
Expand All @@ -141,11 +141,11 @@ jobs:
-DCMAKE_INSTALL_PREFIX="/usr/local"
cmake --build openmp_build --target install --config Release

- uses: pypa/cibuildwheel@v2.21.2
- uses: pypa/cibuildwheel@v2.21.3
env:
# only build for x86_64, arm wheels are build seperately
CIBW_ARCHS: "x86_64"
CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET="12.0" CMAKE_ARGS="-DSDTN_ENABLE_ARCH_FLAGS=OFF -DSDTN_ENABLE_OPENMP=ON -DSDTN_DISABLE_OPENMP=OFF -DOpenMP_ROOT=/usr/local"
CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=12.0 CMAKE_ARGS="-DSDTN_ENABLE_ARCH_FLAGS=OFF -DSDTN_VENDOR_OPENMP=ON -DSDTN_ENABLE_OPENMP=ON -DSDTN_DISABLE_OPENMP=OFF -DOpenMP_ROOT=/usr/local"

- name: Verify clean directory
run: git diff --exit-code
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ mprofile_*.dat
.python-version
.pymon
.cache
*.dylib
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Release history:

## v1.1.5

### Changes

BLD: Set rpath for libomp on MacOS to fix compatibility with latest XGBoost version

## v1.1.4

### Changes
Expand Down
7 changes: 6 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ if (NOT SKBUILD)
after editing C++ files.")
endif()

if(SDTN_MBUILD)
set(CMAKE_INSTALL_PREFIX "${PROJECT_SOURCE_DIR}/src")
endif()

set(SDTN_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/src/sparse_dot_topn_core/include")
set(SDTN_SRC_PREF "${PROJECT_SOURCE_DIR}/src/sparse_dot_topn_core/src/")
set(SDTN_SRC_FILES
Expand All @@ -49,6 +53,7 @@ include(FindDependencies)
include(ConfigureBuildType)
# -- target
nanobind_add_module(_sparse_dot_topn_core STABLE_ABI NB_STATIC LTO NOMINSIZE ${SDTN_SRC_FILES})

include(ConfigureTarget)
include(InstallTarget)
install(TARGETS _sparse_dot_topn_core LIBRARY DESTINATION "${PROJECT_NAME}/lib")
include(CleanUp)
7 changes: 3 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"

[project]
name = "sparse_dot_topn"
version = "1.1.4"
version = "1.1.5"
description = "This package boosts a sparse matrix multiplication followed by selecting the top-n multiplication"
readme = "README.md"
requires-python = ">=3.8"
Expand Down Expand Up @@ -57,7 +57,7 @@ SDTN_ENABLE_ARCH_FLAGS = true
[tool.cibuildwheel]
archs = ["auto64"]
skip = ["*-win32", "*-manylinux_i686", "*-musllinux_x86_64"]
build = ["cp38-*", "cp39-*", "cp310-*", "cp311-*", "cp312-*"]
build = ["cp38-*", "cp39-*", "cp310-*", "cp311-*", "cp312-*", "cp313-*"]

# make sure to build generic wheels
environment = {CMAKE_ARGS="-DSDTN_ENABLE_ARCH_FLAGS=OFF -DSDTN_DISABLE_OPENMP=ON"}
Expand All @@ -77,8 +77,7 @@ repair-wheel-command = "auditwheel repair -w {dest_dir} {wheel}"
[tool.cibuildwheel.macos]
archs = ["x86_64", "arm64"]
# Needed for full C++17 support
environment = { MACOSX_DEPLOYMENT_TARGET = "12.0", CMAKE_ARGS="-DSDTN_ENABLE_ARCH_FLAGS=OFF -DSDTN_DISABLE_OPENMP=ON" }
repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}"
repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel} --exclude libomp.dylib"

[tool.cibuildwheel.windows]
before-build = "pip install delvewheel"
Expand Down
138 changes: 105 additions & 33 deletions src/sparse_dot_topn_core/cmake/ConfigureTarget.cmake
Original file line number Diff line number Diff line change
@@ -1,14 +1,86 @@
target_include_directories(_sparse_dot_topn_core PUBLIC ${SDTN_INCLUDE_DIR})
if(OpenMP_CXX_FOUND)
target_link_libraries(_sparse_dot_topn_core PUBLIC OpenMP::OpenMP_CXX)
target_compile_definitions(_sparse_dot_topn_core PRIVATE SDTN_OMP_ENABLED=TRUE)
target_link_libraries(_sparse_dot_topn_core PUBLIC OpenMP::OpenMP_CXX)
target_compile_definitions(_sparse_dot_topn_core PRIVATE SDTN_OMP_ENABLED=TRUE)
if(APPLE)
# Modified implementation from LightGBM written by JamesLamb
# see https://github.com/microsoft/LightGBM/pull/6391
# store path to libomp found at build time in a variable
get_target_property(
OpenMP_LIBRARY_LOCATION
OpenMP::OpenMP_CXX
INTERFACE_LINK_LIBRARIES
)
# get just the filename of that path
# (to deal with the possibility that it might be 'libomp.dylib' or 'libgomp.dylib' or 'libiomp.dylib')
get_filename_component(
OpenMP_LIBRARY_NAME
${OpenMP_LIBRARY_LOCATION}
NAME
)
# get directory of that path
get_filename_component(
OpenMP_LIBRARY_DIR
${OpenMP_LIBRARY_LOCATION}
DIRECTORY
)

# Override the absolute path to OpenMP with a relative one using @rpath.
#
# This also ensures that if a libomp.dylib has already been loaded, it'll just use that.
add_custom_command(
TARGET _sparse_dot_topn_core
POST_BUILD
COMMAND
install_name_tool
-change
${OpenMP_LIBRARY_LOCATION}
"@rpath/${OpenMP_LIBRARY_NAME}"
$<TARGET_FILE:_sparse_dot_topn_core>
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Replacing hard-coded OpenMP install_name with '@rpath/${OpenMP_LIBRARY_NAME}'..."
)
if (SDTN_VENDOR_OPENMP)
set(OpenMP_target_location ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/.dylibs/${OpenMP_LIBRARY_NAME})

message(STATUS "Copying ${OpenMP_LIBRARY_NAME} to ${OpenMP_target_location}")
add_custom_command(
TARGET _sparse_dot_topn_core
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${OpenMP_LIBRARY_LOCATION}
${OpenMP_target_location}
)
# add RPATH entries to ensure the loader looks in the following, in the following order:
# - @loader_path/../.dylibs/ the dylib we're shipping alongside
set_target_properties(
_sparse_dot_topn_core
PROPERTIES
BUILD_WITH_INSTALL_RPATH TRUE
INSTALL_RPATH "@loader_path/../.dylibs/"
INSTALL_RPATH_USE_LINK_PATH FALSE
)
else()
# add RPATH entries to ensure the loader looks in the following, in the following order:
# - ${OpenMP_LIBRARY_DIR} (wherever find_package(OpenMP) found OpenMP at build time)
# - /opt/homebrew/opt/libomp/lib (where 'brew install' / 'brew link' puts libomp.dylib)
set_target_properties(
_sparse_dot_topn_core
PROPERTIES
BUILD_WITH_INSTALL_RPATH TRUE
INSTALL_RPATH "${OpenMP_LIBRARY_DIR};/opt/homebrew/opt/libomp/lib"
INSTALL_RPATH_USE_LINK_PATH FALSE
)

endif()
endif()
endif()

target_compile_definitions(_sparse_dot_topn_core PRIVATE VERSION_INFO=${SKBUILD_PROJECT_VERSION})

# -- Optional
if(SDTN_ENABLE_DEVMODE)
target_compile_options(_sparse_dot_topn_core PRIVATE ${SDTN_DEVMODE_OPTIONS})
target_compile_options(_sparse_dot_topn_core PRIVATE ${SDTN_DEVMODE_OPTIONS})
endif()

# -- Options & Properties
Expand All @@ -19,41 +91,41 @@ set_property(TARGET _sparse_dot_topn_core PROPERTY POSITION_INDEPENDENT_CODE ON)
include(CheckCXXCompilerFlag)

function(check_cxx_support FLAG DEST)
string(SUBSTRING ${FLAG} 1 -1 STRIPPED_FLAG)
string(REGEX REPLACE "=" "_" STRIPPED_FLAG ${STRIPPED_FLAG})
string(TOUPPER ${STRIPPED_FLAG} STRIPPED_FLAG)
set(RES_VAR "${STRIPPED_FLAG}_SUPPORTED")
check_cxx_compiler_flag("${FLAG}" ${RES_VAR})
if(${RES_VAR})
set(${DEST} "${${DEST}} ${FLAG}" PARENT_SCOPE)
endif()
string(SUBSTRING ${FLAG} 1 -1 STRIPPED_FLAG)
string(REGEX REPLACE "=" "_" STRIPPED_FLAG ${STRIPPED_FLAG})
string(TOUPPER ${STRIPPED_FLAG} STRIPPED_FLAG)
set(RES_VAR "${STRIPPED_FLAG}_SUPPORTED")
check_cxx_compiler_flag("${FLAG}" ${RES_VAR})
if(${RES_VAR})
set(${DEST} "${${DEST}} ${FLAG}" PARENT_SCOPE)
endif()
endfunction()

# -- Compiler Flags
if (SDTN_ENABLE_ARCH_FLAGS AND "${CMAKE_CXX_FLAGS}" STREQUAL "${CMAKE_CXX_FLAGS_DEFAULT}")
set(SDTN_ARCHITECTURE_FLAGS "")
if (APPLE AND (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64"))
# see https://github.com/google/highway/issues/745
check_cxx_support("-march=native" SDTN_ARCHITECTURE_FLAGS)
else()
include(FindSse)
include(FindAvx)
SDTN_CHECK_FOR_SSE()
add_definitions(${SSE_DEFINITIONS})
SDTN_CHECK_FOR_AVX()
string(APPEND SDTN_ARCHITECTURE_FLAGS "${SSE_FLAGS} ${AVX_FLAGS}")
endif()
set(SDTN_ARCHITECTURE_FLAGS "")
if (APPLE AND (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64"))
# see https://github.com/google/highway/issues/745
check_cxx_support("-march=native" SDTN_ARCHITECTURE_FLAGS)
else()
include(FindSse)
include(FindAvx)
SDTN_CHECK_FOR_SSE()
add_definitions(${SSE_DEFINITIONS})
SDTN_CHECK_FOR_AVX()
string(APPEND SDTN_ARCHITECTURE_FLAGS "${SSE_FLAGS} ${AVX_FLAGS}")
endif()

if (NOT ${SDTN_ARCHITECTURE_FLAGS} STREQUAL "")
string(STRIP ${SDTN_ARCHITECTURE_FLAGS} SDTN_ARCHITECTURE_FLAGS)
message(STATUS "sparse-dot-topn | Enabled arch flags: ${SDTN_ARCHITECTURE_FLAGS}")
if (MSVC)
separate_arguments(SDTN_ARCHITECTURE_FLAGS WINDOWS_COMMAND "${SDTN_ARCHITECTURE_FLAGS}")
else()
separate_arguments(SDTN_ARCHITECTURE_FLAGS UNIX_COMMAND "${SDTN_ARCHITECTURE_FLAGS}")
endif()
target_compile_options(_sparse_dot_topn_core PRIVATE $<$<CONFIG:RELEASE>:${SDTN_ARCHITECTURE_FLAGS}>)
if (NOT ${SDTN_ARCHITECTURE_FLAGS} STREQUAL "")
string(STRIP ${SDTN_ARCHITECTURE_FLAGS} SDTN_ARCHITECTURE_FLAGS)
message(STATUS "sparse-dot-topn | Enabled arch flags: ${SDTN_ARCHITECTURE_FLAGS}")
if (MSVC)
separate_arguments(SDTN_ARCHITECTURE_FLAGS WINDOWS_COMMAND "${SDTN_ARCHITECTURE_FLAGS}")
else()
message(STATUS "sparse-dot-topn | Architecture flags enabled but no valid flags were found")
separate_arguments(SDTN_ARCHITECTURE_FLAGS UNIX_COMMAND "${SDTN_ARCHITECTURE_FLAGS}")
endif()
target_compile_options(_sparse_dot_topn_core PRIVATE $<$<CONFIG:RELEASE>:${SDTN_ARCHITECTURE_FLAGS}>)
else()
message(STATUS "sparse-dot-topn | Architecture flags enabled but no valid flags were found")
endif()
endif()
2 changes: 1 addition & 1 deletion src/sparse_dot_topn_core/cmake/FindAvx.cmake
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
###############################################################################
# ##############################################################################
# Check for the presence of AVX and figure out the flags to use for it.
# This routine is a modified version of `PCL_CHECK_FOR_AVX`
# Reference: https://github.com/PointCloudLibrary/pcl/blob/master/cmake/pcl_find_avx.cmake
Expand Down
2 changes: 1 addition & 1 deletion src/sparse_dot_topn_core/cmake/FindSse.cmake
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
###############################################################################
# ##############################################################################
# Check for the presence of SSE and figure out the flags to use for it.
# This routine is a modified version of `PCL_CHECK_FOR_SSE`
# https://github.com/PointCloudLibrary/pcl/blob/master/cmake/pcl_find_sse.cmake
Expand Down
5 changes: 0 additions & 5 deletions src/sparse_dot_topn_core/cmake/InstallTarget.cmake

This file was deleted.

Loading