From 432d8ba9b89e495d0f0ff29f150827afe8477f47 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 10 Jul 2026 08:42:20 +0000 Subject: [PATCH 1/9] CI fix macOS FlexiBLAS build with newer CMake Newer CMake versions reject the minimum policy version bundled with FlexiBLAS v3.4.2. Set CMAKE_POLICY_VERSION_MINIMUM=3.5 so the existing FlexiBLAS pin keeps working without upgrading the library. Co-authored-by: Olivier Grisel --- continuous_integration/install_flexiblas.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/continuous_integration/install_flexiblas.sh b/continuous_integration/install_flexiblas.sh index 3d45ab54..1f50801b 100644 --- a/continuous_integration/install_flexiblas.sh +++ b/continuous_integration/install_flexiblas.sh @@ -28,6 +28,7 @@ fi # specific BLAS implementations such as MKL that cannot be installed on # arm64 hardware. cmake ../ -DCMAKE_INSTALL_PREFIX=$ABS_PATH"/flexiblas_install" \ + -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ -DBLAS_AUTO_DETECT="OFF" \ -DEXTRA="OPENBLAS_CONDA" \ -DFLEXIBLAS_DEFAULT="OPENBLAS_CONDA" \ From 595f7816918015d080d5ea63bb8c11e1b77ffe39 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 10 Jul 2026 09:42:11 +0000 Subject: [PATCH 2/9] CI drop pinned FlexiBLAS version in install script Remove the v3.4.2 checkout and its comment so CI builds the latest FlexiBLAS release from the default branch. Co-authored-by: Olivier Grisel --- continuous_integration/install_flexiblas.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/continuous_integration/install_flexiblas.sh b/continuous_integration/install_flexiblas.sh index 1f50801b..6721f71b 100644 --- a/continuous_integration/install_flexiblas.sh +++ b/continuous_integration/install_flexiblas.sh @@ -11,9 +11,6 @@ mkdir flexiblas_install git clone https://github.com/mpimd-csc/flexiblas.git pushd flexiblas -# Temporary ping Flexiblas commit to avoid openmp symbols not found at link time -git checkout v3.4.2 - mkdir build pushd build From 349e8faaa2e042dde945db703c90a8c8a30deb82 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 10 Jul 2026 09:55:55 +0000 Subject: [PATCH 3/9] CI enable ccache for FlexiBLAS builds Install ccache from conda-forge, wire it into the FlexiBLAS cmake build, and persist the cache directory across CI runs for both macOS and Linux flexiblas jobs. Co-authored-by: Olivier Grisel --- .github/workflows/test.yml | 9 +++++++++ continuous_integration/install.sh | 2 +- continuous_integration/install_flexiblas.sh | 9 +++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 39fc19e2..50238058 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -221,6 +221,15 @@ jobs: - name: Checkout code uses: actions/checkout@v3 + - name: Restore ccache + if: matrix.INSTALL_BLAS == 'flexiblas' + uses: actions/cache@v4 + with: + path: ~/.cache/ccache + key: ccache-flexiblas-${{ matrix.os }}-${{ hashFiles('continuous_integration/install_flexiblas.sh') }} + restore-keys: | + ccache-flexiblas-${{ matrix.os }}- + - name: Setup conda uses: conda-incubator/setup-miniconda@v3 with: diff --git a/continuous_integration/install.sh b/continuous_integration/install.sh index 7a958980..8e6523fc 100644 --- a/continuous_integration/install.sh +++ b/continuous_integration/install.sh @@ -106,7 +106,7 @@ elif [[ "$INSTALL_BLAS" == "blis" ]]; then source ./continuous_integration/install_blis.sh elif [[ "$INSTALL_BLAS" == "flexiblas" ]]; then - TO_INSTALL="cython openblas $PLATFORM_SPECIFIC_PACKAGES meson-python pkg-config compilers" + TO_INSTALL="ccache cython openblas $PLATFORM_SPECIFIC_PACKAGES meson-python pkg-config compilers" make_conda "conda-forge" "$TO_INSTALL" source ./continuous_integration/install_flexiblas.sh diff --git a/continuous_integration/install_flexiblas.sh b/continuous_integration/install_flexiblas.sh index 6721f71b..d9da6464 100644 --- a/continuous_integration/install_flexiblas.sh +++ b/continuous_integration/install_flexiblas.sh @@ -11,6 +11,10 @@ mkdir flexiblas_install git clone https://github.com/mpimd-csc/flexiblas.git pushd flexiblas +export CCACHE_DIR="${CCACHE_DIR:-$HOME/.cache/ccache}" +mkdir -p "$CCACHE_DIR" +ccache --max-size=500M + mkdir build pushd build @@ -26,6 +30,9 @@ fi # arm64 hardware. cmake ../ -DCMAKE_INSTALL_PREFIX=$ABS_PATH"/flexiblas_install" \ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DCMAKE_Fortran_COMPILER_LAUNCHER=ccache \ -DBLAS_AUTO_DETECT="OFF" \ -DEXTRA="OPENBLAS_CONDA" \ -DFLEXIBLAS_DEFAULT="OPENBLAS_CONDA" \ @@ -56,6 +63,8 @@ Cflags: -I\${includedir}" > flexiblas.pc PKG_CONFIG_PATH=$ABS_PATH/numpy/ pip install . -v --no-build-isolation -Csetup-args=-Dblas=flexiblas -Csetup-args=-Dlapack=flexiblas +ccache -s || true + export CFLAGS=-I$ABS_PATH/flexiblas_install/include/flexiblas \ export LDFLAGS="-L$ABS_PATH/flexiblas_install/lib -Wl,-rpath,$ABS_PATH/flexiblas_install/lib" \ From 5d72bde21b8aad73dbb7f2cf3c77c77c9dbb5bff Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 10 Jul 2026 10:14:30 +0000 Subject: [PATCH 4/9] CI fix FlexiBLAS 3.5 runtime library lookup FlexiBLAS 3.5 installs libflexiblas_mgmt as a separate shared library but does not embed a usable rpath in the flexiblas CLI. Set the install rpath during cmake configuration and export the library path for the post-install sanity check and subsequent build steps. Co-authored-by: Olivier Grisel --- continuous_integration/install_flexiblas.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/continuous_integration/install_flexiblas.sh b/continuous_integration/install_flexiblas.sh index d9da6464..47a3e798 100644 --- a/continuous_integration/install_flexiblas.sh +++ b/continuous_integration/install_flexiblas.sh @@ -28,8 +28,11 @@ fi # provided backends such as macOS' Apple/Accelerate/vecLib nor plaftorm # specific BLAS implementations such as MKL that cannot be installed on # arm64 hardware. +FLEXIBLAS_LIB=$ABS_PATH/flexiblas_install/lib cmake ../ -DCMAKE_INSTALL_PREFIX=$ABS_PATH"/flexiblas_install" \ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ + -DCMAKE_INSTALL_RPATH=$FLEXIBLAS_LIB \ + -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=TRUE \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_Fortran_COMPILER_LAUNCHER=ccache \ @@ -40,6 +43,11 @@ cmake ../ -DCMAKE_INSTALL_PREFIX=$ABS_PATH"/flexiblas_install" \ make make install +export LD_LIBRARY_PATH=$FLEXIBLAS_LIB${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} +if [[ $(uname) == "Darwin" ]]; then + export DYLD_LIBRARY_PATH=$FLEXIBLAS_LIB${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH} +fi + # Check that all 3 BLAS are listed in FlexiBLAS configuration $ABS_PATH/flexiblas_install/bin/flexiblas list popd @@ -65,8 +73,8 @@ PKG_CONFIG_PATH=$ABS_PATH/numpy/ pip install . -v --no-build-isolation -Csetup-a ccache -s || true -export CFLAGS=-I$ABS_PATH/flexiblas_install/include/flexiblas \ -export LDFLAGS="-L$ABS_PATH/flexiblas_install/lib -Wl,-rpath,$ABS_PATH/flexiblas_install/lib" \ +export CFLAGS=-I$ABS_PATH/flexiblas_install/include/flexiblas +export LDFLAGS="-L$FLEXIBLAS_LIB -Wl,-rpath,$FLEXIBLAS_LIB" popd From 1d32c61800e241475efb4cbebe2975c859a383ae Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 10 Jul 2026 12:44:35 +0000 Subject: [PATCH 5/9] CI trigger empty commit to validate ccache speedup Co-authored-by: Olivier Grisel From 748be7220f36cbd32993172cfc22cbea29370991 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 10 Jul 2026 13:35:49 +0000 Subject: [PATCH 6/9] TST drop obsolete libblas prefix from limits-by-prefix tests Windows conda-forge MKL stacks now expose MKL as mkl_rt..dll instead of libblas.dll. The mkl_rt prefix remains covered by the parametrized tests. Co-authored-by: Olivier Grisel --- tests/test_threadpoolctl.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_threadpoolctl.py b/tests/test_threadpoolctl.py index ea27cc2b..ff2d3ccd 100644 --- a/tests/test_threadpoolctl.py +++ b/tests/test_threadpoolctl.py @@ -113,7 +113,12 @@ def test_threadpool_controller_select(kwargs): ) -@pytest.mark.parametrize("prefix", _ALL_PREFIXES) +# Windows conda-forge MKL stacks expose MKL as mkl_rt..dll (e.g. +# mkl_rt.3.dll), not libblas.dll. The mkl_rt prefix is already covered below. +_PREFIXES_FOR_LIMITS_TESTS = [p for p in _ALL_PREFIXES if p != "libblas"] + + +@pytest.mark.parametrize("prefix", _PREFIXES_FOR_LIMITS_TESTS) @pytest.mark.parametrize("limit", [1, 3]) def test_threadpool_limits_by_prefix(prefix, limit): # Check that the maximum number of threads can be set by prefix From 47372e200d0b60041c10375f616bbeba94101e34 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 10 Jul 2026 13:57:54 +0000 Subject: [PATCH 7/9] TST allow libblas prefix tests to be skipped in meta_test Revert filtering libblas out of test_threadpool_limits_by_prefix and instead whitelist the parametrized libblas cases in SAFE_SKIPPED_TESTS. Document that libblas.dll handling is legacy conda-forge Windows code that current stacks no longer exercise (MKL uses mkl_rt..dll). Co-authored-by: Olivier Grisel --- .../check_no_test_skipped.py | 6 +++- tests/test_threadpoolctl.py | 7 +---- threadpoolctl.py | 30 +++++++++++-------- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/continuous_integration/check_no_test_skipped.py b/continuous_integration/check_no_test_skipped.py index 18fd6bc2..617caedc 100644 --- a/continuous_integration/check_no_test_skipped.py +++ b/continuous_integration/check_no_test_skipped.py @@ -36,7 +36,11 @@ # List of tests that we don't want to fail the CI if they are skipped in # every job. This is useful for tests that depend on specific versions of # numpy or scipy and we don't want to pin old versions of these libraries. -SAFE_SKIPPED_TESTS = ["test_multiple_shipped_openblas"] +SAFE_SKIPPED_TESTS = [ + "test_multiple_shipped_openblas", + "test_threadpool_limits_by_prefix[1-libblas]", + "test_threadpool_limits_by_prefix[3-libblas]", +] fail = False for test, skipped in always_skipped.items(): diff --git a/tests/test_threadpoolctl.py b/tests/test_threadpoolctl.py index ff2d3ccd..ea27cc2b 100644 --- a/tests/test_threadpoolctl.py +++ b/tests/test_threadpoolctl.py @@ -113,12 +113,7 @@ def test_threadpool_controller_select(kwargs): ) -# Windows conda-forge MKL stacks expose MKL as mkl_rt..dll (e.g. -# mkl_rt.3.dll), not libblas.dll. The mkl_rt prefix is already covered below. -_PREFIXES_FOR_LIMITS_TESTS = [p for p in _ALL_PREFIXES if p != "libblas"] - - -@pytest.mark.parametrize("prefix", _PREFIXES_FOR_LIMITS_TESTS) +@pytest.mark.parametrize("prefix", _ALL_PREFIXES) @pytest.mark.parametrize("limit", [1, 3]) def test_threadpool_limits_by_prefix(prefix, limit): # Check that the maximum number of threads can be set by prefix diff --git a/threadpoolctl.py b/threadpoolctl.py index ceed5b88..0423e22b 100644 --- a/threadpoolctl.py +++ b/threadpoolctl.py @@ -165,7 +165,11 @@ class OpenBLASController(LibController): user_api = "blas" internal_api = "openblas" - filename_prefixes = ("libopenblas", "libblas", "libscipy_openblas") + filename_prefixes = ( + "libopenblas", + "libblas", # legacy conda-forge Windows shim, see _make_controller_from_path + "libscipy_openblas", + ) _symbol_prefixes = ("", "scipy_") _symbol_suffixes = ("", "64_", "_64") @@ -237,7 +241,7 @@ class BLISController(LibController): user_api = "blas" internal_api = "blis" - filename_prefixes = ("libblis", "libblas") + filename_prefixes = ("libblis", "libblas") # libblas: legacy conda-forge Windows shim check_symbols = ( "bli_thread_get_num_threads", "bli_thread_set_num_threads", @@ -428,7 +432,11 @@ class MKLController(LibController): user_api = "blas" internal_api = "mkl" - filename_prefixes = ("libmkl_rt", "mkl_rt", "libblas") + filename_prefixes = ( + "libmkl_rt", + "mkl_rt", + "libblas", # legacy conda-forge Windows shim, see _make_controller_from_path + ) check_symbols = ( "MKL_Get_Max_Threads", "MKL_Set_Num_Threads", @@ -1164,10 +1172,11 @@ def _make_controller_from_path(self, filepath): if prefix is None: continue - # workaround for BLAS libraries packaged by conda-forge on windows, which - # are all renamed "libblas.dll". We thus have to check to which BLAS - # implementation it actually corresponds looking for implementation - # specific symbols. + # Legacy workaround for BLAS libraries that conda-forge used to expose + # on Windows as libblas.dll, disambiguated via implementation-specific + # symbols. Current conda-forge stacks no longer load libblas.dll (e.g. + # MKL is exposed as mkl_rt..dll instead), so this path is + # kept for older installs but cannot be exercised in today's CI. if prefix == "libblas": if filename.endswith(".dll"): libblas = ctypes.CDLL(filepath, _RTLD_NOLOAD) @@ -1177,11 +1186,8 @@ def _make_controller_from_path(self, filepath): ): continue else: - # We ignore libblas on other platforms than windows because there - # might be a libblas dso comming with openblas for instance that - # can't be used to instantiate a pertinent LibController (many - # symbols are missing) and would create confusion by making a - # duplicate entry in threadpool_info. + # Non-Windows libblas DSOs (e.g. from openblas) lack the symbols + # needed to instantiate a controller and would duplicate entries. continue # filename matches a prefix. Now we check if the library has the symbols we From 51fbb0dabf3c9d49af9e9c8feedffcfc6b16fc39 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 10 Jul 2026 14:19:03 +0000 Subject: [PATCH 8/9] MNT format threadpoolctl.py with black Co-authored-by: Olivier Grisel --- threadpoolctl.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/threadpoolctl.py b/threadpoolctl.py index 0423e22b..b03cc941 100644 --- a/threadpoolctl.py +++ b/threadpoolctl.py @@ -241,7 +241,10 @@ class BLISController(LibController): user_api = "blas" internal_api = "blis" - filename_prefixes = ("libblis", "libblas") # libblas: legacy conda-forge Windows shim + filename_prefixes = ( + "libblis", + "libblas", + ) # libblas: legacy conda-forge Windows shim check_symbols = ( "bli_thread_get_num_threads", "bli_thread_set_num_threads", From 56b9969458d0f184724d63a3d165973546553090 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 10 Jul 2026 14:39:05 +0000 Subject: [PATCH 9/9] TST accept cooperlake in OpenBLAS architecture test Windows py39_pip CI runners report Cooperlake for the shipped libscipy_openblas wheel. Co-authored-by: Olivier Grisel --- tests/test_threadpoolctl.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_threadpoolctl.py b/tests/test_threadpoolctl.py index ea27cc2b..bedca67e 100644 --- a/tests/test_threadpoolctl.py +++ b/tests/test_threadpoolctl.py @@ -613,6 +613,7 @@ def test_architecture(): expected_openblas_architectures = ( # XXX: add more as needed by CI or developer laptops "armv8", + "cooperlake", "haswell", "neoversen1", "prescott", # see: https://github.com/xianyi/OpenBLAS/pull/3485