git: 9351c1129192 - main - math/py-cbcbox: New port: Python access to the CBC MILP solver

From: Yuri Victorovich <yuri_at_FreeBSD.org>
Date: Mon, 14 Sep 2026 18:52:13 UTC
The branch main has been updated by yuri:

URL: https://cgit.FreeBSD.org/ports/commit/?id=9351c1129192deae3ee165f6b127edfc923c651c

commit 9351c1129192deae3ee165f6b127edfc923c651c
Author:     Yuri Victorovich <yuri@FreeBSD.org>
AuthorDate: 2026-09-14 03:19:50 +0000
Commit:     Yuri Victorovich <yuri@FreeBSD.org>
CommitDate: 2026-09-14 18:52:04 +0000

    math/py-cbcbox: New port: Python access to the CBC MILP solver
    
    PR:             298331
    Approved by:    Baptiste Daroussin <bapt@FreeBSD.org> (on behalf of portmgr@)
---
 math/Makefile                                   |    1 +
 math/py-cbcbox/Makefile                         |   33 +
 math/py-cbcbox/distinfo                         |    3 +
 math/py-cbcbox/files/patch-pyproject.toml       |   14 +
 math/py-cbcbox/files/patch-setup.py             | 1127 +++++++++++++++++++++++
 math/py-cbcbox/files/patch-src_____init____.py  |   55 ++
 math/py-cbcbox/files/patch-tests_conftest.py    |   29 +
 math/py-cbcbox/files/patch-tests_test__solve.py |   52 ++
 math/py-cbcbox/pkg-descr                        |    9 +
 9 files changed, 1323 insertions(+)

diff --git a/math/Makefile b/math/Makefile
index 94cbe6fcf223..553bc278ca84 100644
--- a/math/Makefile
+++ b/math/Makefile
@@ -974,6 +974,7 @@
     SUBDIR += py-blis
     SUBDIR += py-bottleneck
     SUBDIR += py-brial
+    SUBDIR += py-cbcbox
     SUBDIR += py-chaospy
     SUBDIR += py-clarabel
     SUBDIR += py-claripy
diff --git a/math/py-cbcbox/Makefile b/math/py-cbcbox/Makefile
new file mode 100644
index 000000000000..ffedfc5518a8
--- /dev/null
+++ b/math/py-cbcbox/Makefile
@@ -0,0 +1,33 @@
+PORTNAME=	cbcbox
+DISTVERSION=	2.935 # not tagged on GH
+CATEGORIES=	math python
+PKGNAMEPREFIX=	${PYTHON_PKGNAMEPREFIX}
+
+MAINTAINER=	yuri@FreeBSD.org
+COMMENT=	Python access to the CBC MILP solver
+WWW=		https://github.com/h-g-s/cbcbox
+
+LICENSE=	EPL
+
+BUILD_DEPENDS=	${PYTHON_PKGNAMEPREFIX}setuptools>0:devel/py-setuptools@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}wheel>0:devel/py-wheel@${PY_FLAVOR}
+RUN_DEPENDS=	cbc:math/cbc
+
+USES=		python
+USE_PYTHON=	pep517 concurrent autoplist pytest
+
+USE_GITHUB=	yes
+GH_ACCOUNT=	h-g-s
+GH_TAGNAME=	adf09a5ea6f3d697b9a0b38831d7ad711b0cfe7a # adequate commit for 2.935 release
+
+NO_ARCH=	yes
+
+TEST_ENV=	PYTHONPATH=${WRKSRC}/build/lib
+TEST_ARGS=	--disable-plugin-autoload
+
+post-patch:
+	@${REINPLACE_CMD} -e 's|@LOCALBASE@|${LOCALBASE}|g' ${WRKSRC}/src/__init__.py
+
+# tests as of 2.935: 11 passed in 107.00s
+
+.include <bsd.port.mk>
diff --git a/math/py-cbcbox/distinfo b/math/py-cbcbox/distinfo
new file mode 100644
index 000000000000..96bd05948fbe
--- /dev/null
+++ b/math/py-cbcbox/distinfo
@@ -0,0 +1,3 @@
+TIMESTAMP = 1788910090
+SHA256 (h-g-s-cbcbox-2.935-adf09a5ea6f3d697b9a0b38831d7ad711b0cfe7a_GH0.tar.gz) = d0ccf7902cdc09550d6c8f01ac501051008905cefe53b988bc2360c6721f6c16
+SIZE (h-g-s-cbcbox-2.935-adf09a5ea6f3d697b9a0b38831d7ad711b0cfe7a_GH0.tar.gz) = 13095448
diff --git a/math/py-cbcbox/files/patch-pyproject.toml b/math/py-cbcbox/files/patch-pyproject.toml
new file mode 100644
index 000000000000..849279cfa7a1
--- /dev/null
+++ b/math/py-cbcbox/files/patch-pyproject.toml
@@ -0,0 +1,14 @@
+-- Remove the "cbc" console script so this port does not conflict with the
+-- bin/cbc executable already provided by math/cbc.
+
+--- pyproject.toml.orig	2026-09-08 23:28:23 UTC
++++ pyproject.toml
+@@ -35,8 +35,5 @@ Homepage = "https://github.com/h-g-s/cbcbox"
+ Homepage = "https://github.com/h-g-s/cbcbox"
+ "Bug Tracker" = "https://github.com/h-g-s/cbcbox/issues"
+ 
+-[project.scripts]
+-cbc = "cbcbox.__main__:main"
+-
+ [tool.cibuildwheel]
+ build-verbosity = 1
diff --git a/math/py-cbcbox/files/patch-setup.py b/math/py-cbcbox/files/patch-setup.py
new file mode 100644
index 000000000000..5d79daa3b495
--- /dev/null
+++ b/math/py-cbcbox/files/patch-setup.py
@@ -0,0 +1,1127 @@
+-- Replace the upstream setup.py with a minimal setuptools configuration.
+-- Upstream setup.py rebuilds OpenBLAS, SuiteSparse AMD and the full COIN-OR
+-- stack from git sources and bundles the resulting binaries into a wheel.
+-- FreeBSD already provides math/cbc, so this port installs only the Python
+-- wrapper and points it at the system CBC binary.
+
+--- setup.py.orig	2026-09-08 23:28:23 UTC
++++ setup.py
+@@ -1,1109 +1,15 @@
+-import glob as _glob
+-import multiprocessing
+ import os
+-import platform
+-import re
+-import shlex
+-import shutil
+-import subprocess
+-import sys
+-
+ from setuptools import setup
+-from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
+ 
++THIS_DIR = os.path.abspath(os.path.dirname(__file__))
+ 
+-# ── Wheel customisation ───────────────────────────────────────────────────────
++with open(os.path.join(THIS_DIR, "README.md"), "r", encoding="utf-8") as f:
++    long_description = f.read()
+ 
+-class genericpy_bdist_wheel(_bdist_wheel):
+-    def finalize_options(self):
+-        _bdist_wheel.finalize_options(self)
+-        self.root_is_pure = False
+-
+-    def get_tag(self):
+-        python, abi, plat = _bdist_wheel.get_tag(self)
+-        python, abi = "py3", "none"
+-        if os.environ.get("CIBUILDWHEEL", "0") == "1":
+-            if plat == "linux_x86_64":
+-                plat = "manylinux2014_x86_64"
+-            elif plat == "linux_aarch64":
+-                plat = "manylinux2014_aarch64"
+-        return python, abi, plat
+-
+-
+-cmdclass = {"bdist_wheel": genericpy_bdist_wheel}
+-
+-
+-# ── Constants ─────────────────────────────────────────────────────────────────
+-
+-THIS_DIR       = os.path.abspath(os.path.dirname(__file__))
+-DIST_DIR       = os.path.join(THIS_DIR, "cbc_dist")
+-DIST_DIR_AVX2  = os.path.join(THIS_DIR, "cbc_dist_avx2")
+-DIST_DIR_DEBUG     = os.path.join(THIS_DIR, "cbc_dist_debug")
+-DIST_DIR_DEBUG_AVX2 = os.path.join(THIS_DIR, "cbc_dist_debug_avx2")
+-LIB_DIR        = os.path.join(DIST_DIR, "lib")
+-NPROC    = str(max(1, multiprocessing.cpu_count()))
+-
+-SUITESPARSE_TAG = "v7.12.2"
+-OPENBLAS_TAG    = "v0.3.31"
+-
+-# Development of the COIN-OR stack has moved to the "next" branch of each
+-# repository (the "master" branch is now the last stable release line).
+-COIN_OR_BRANCH  = "next"
+-
+-# -ffp-contract=off disables the compiler's automatic fusion of separate
+-# multiply/add operations into a single FMA instruction. FMA computes the
+-# product with full (unrounded) intermediate precision before the final
+-# rounding, so results can differ slightly (in the last bit) from the
+-# strictly-IEEE separate multiply + add. This tiny discrepancy is enough to
+-# make CBC's numerical routines (which rely on exact reproducibility across
+-# the stack) occasionally behave inconsistently, so this flag is applied to
+-# the COIN-OR stack (CoinUtils, Osi, Clp, Cgl, Cbc) only — third-party
+-# dependencies built from source (OpenBLAS, SuiteSparse AMD) keep their
+-# default FMA-contraction behaviour.
+-FP_CONTRACT_OFF = "-ffp-contract=off"
+-
+-# Build order matters: each project depends on the ones before it.
+-COIN_REPOS = [
+-    ("CoinUtils", "https://github.com/coin-or/CoinUtils.git"),
+-    ("Osi",       "https://github.com/coin-or/Osi.git"),
+-    ("Clp",       "https://github.com/coin-or/Clp.git"),
+-    ("Cgl",       "https://github.com/coin-or/Cgl.git"),
+-    ("Cbc",       "https://github.com/coin-or/Cbc.git"),
+-]
+-
+-# Shared libraries allowed by the manylinux2014 policy (PEP 599).
+-# Anything NOT matching this pattern must be either linked statically
+-# or bundled inside the wheel.
+-_MANYLINUX_ALLOWED = re.compile(
+-    r"^lib(gcc_s|stdc\+\+|m|dl|rt|pthread|c|nsl|util|z|gomp|crypt|resolv)\."
+-    r"|^(linux-vdso|linux-gate|ld-linux)"
++setup(
++    long_description=long_description,
++    long_description_content_type="text/markdown",
++    packages=["cbcbox"],
++    package_dir={"cbcbox": "src"},
++    zip_safe=False,
+ )
+-
+-# ── Windows / MSYS2-MinGW64 constants ────────────────────────────────────────
+-
+-# MSYS2 is pre-installed on windows-latest GitHub Actions runners.
+-_MSYS2_BASH = r"C:\msys64\usr\bin\bash.exe"
+-
+-# DLLs that ship with Windows itself and must NOT be bundled.
+-_WIN_SYS_DLL = re.compile(
+-    r"^(kernel32|user32|ntdll|msvcrt|api-ms-win|ext-ms-win|advapi32|"
+-    r"shell32|ole32|oleaut32|ws2_32|mswsock|bcrypt|crypt32|secur32|"
+-    r"ucrtbase|vcruntime|hid|setupapi|cfgmgr32|imm32|version|winmm|"
+-    r"shlwapi|rpcrt4|comctl32|comdlg32|gdi32|netapi32|psapi|dbghelp)"
+-    r"\.dll$",
+-    re.IGNORECASE,
+-)
+-
+-
+-def _win_to_msys2(s: str) -> str:
+-    """Convert Windows absolute path references within *s* to MSYS2 format.
+-
+-    'C:\\foo\\bar'          →  '/c/foo/bar'
+-    '--prefix=C:/foo/bar'   →  '--prefix=/c/foo/bar'
+-    '-LC:/foo/bar'          →  '-L/c/foo/bar'  (even when preceded by a flag letter)
+-    'https://example.com'   →  unchanged
+-    Strings without drive letters pass through unchanged.
+-    """
+-    s = str(s)
+-    # Protect URL schemes (e.g. "https://") so they aren't misidentified as
+-    # Windows drive letters.  Use a lambda so Python doesn't interpret \x in
+-    # the replacement string (re.sub string replacement doesn't allow \x).
+-    placeholder = "\x00\x00"
+-    s = re.sub(r'([A-Za-z]+)://', lambda m: m.group(1) + placeholder, s)
+-    # Convert Windows drive letters to MSYS2 /x/ format.
+-    s = re.sub(r'([A-Za-z]):[/\\]', lambda m: f"/{m.group(1).lower()}/", s)
+-    # Restore URL schemes and normalise remaining back-slashes.
+-    return s.replace('\x00\x00', '://').replace('\\', '/')
+-
+-
+-# ── Generic helpers ───────────────────────────────────────────────────────────
+-
+-def run(*cmd, cwd=None, env=None):
+-    print(f">>> {' '.join(str(c) for c in cmd)}", flush=True)
+-    if platform.system() == "Windows":
+-        # Route every build command through MSYS2/MinGW64 so that autotools,
+-        # make, pkg-config, gfortran etc. are all available.
+-        parts = ["export PATH=/mingw64/bin:/usr/bin:$PATH"]
+-        if cwd:
+-            parts.append(f"cd {shlex.quote(_win_to_msys2(str(cwd)))}")
+-        parts.append(" ".join(shlex.quote(_win_to_msys2(str(c))) for c in cmd))
+-        subprocess.run([_MSYS2_BASH, "-lc", " && ".join(parts)],
+-                       check=True, env=env)
+-    else:
+-        subprocess.run(list(cmd), check=True, cwd=cwd, env=env)
+-
+-
+-def _is_x86_64() -> bool:
+-    return platform.machine().lower() in ("x86_64", "amd64")
+-
+-
+-def clone_if_missing(name, url, branch="master"):
+-    dest = os.path.join(THIS_DIR, name)
+-    if not os.path.exists(dest):
+-        # Use native git directly — avoids routing through MSYS2 where git
+-        # may not be on PATH, and avoids any path-conversion of the URL.
+-        print(f">>> git clone --depth 1 --branch {branch} {url} {dest}", flush=True)
+-        subprocess.run(
+-            ["git", "clone", "--depth", "1", "--branch", branch, url, dest],
+-            check=True,
+-        )
+-    else:
+-        # Pull the latest commits so that a stale shallow clone never causes
+-        # API-mismatch build failures (e.g. a new method added to Clp that
+-        # Cbc already calls, but the local clone predates the push).
+-        print(f">>> git -C {dest} pull --ff-only", flush=True)
+-        subprocess.run(
+-            ["git", "-C", dest, "pull", "--ff-only"],
+-            check=True,
+-        )
+-    return dest
+-
+-
+-
+-# ── Build OpenBLAS (static, with Fortran/LAPACK) ─────────────────────────────
+-
+-def build_openblas(dest_dir, *, dynamic_arch=False, target=None, extra_cflags="",
+-                   dynamic_list=None):
+-    src = clone_if_missing(
+-        "OpenBLAS",
+-        "https://github.com/xianyi/OpenBLAS.git",
+-        OPENBLAS_TAG,
+-    )
+-    # OpenBLAS builds in-tree; always clean before each build so that a
+-    # second (AVX2) pass doesn't inherit object files from the first.
+-    run("make", "clean", cwd=src)
+-
+-    make_vars = []
+-    if platform.system() == "Windows":
+-        make_vars.append("BINARY=64")
+-    if target:
+-        # Explicit CPU target (e.g. TARGET=HASWELL for AVX2 build).
+-        make_vars.append(f"TARGET={target}")
+-    elif dynamic_arch:
+-        # DYNAMIC_ARCH=1 compiles multiple kernels and dispatches at runtime.
+-        # NO_AVX512=1: AVX-512 kernels use very large stack frames (ZMM spills)
+-        # that overflow the 512 KB default pthread stack on macOS, causing
+-        # SIGSEGV inside dgetrf_single on CI runners with Ice Lake Xeons.
+-        # Our wheel targets Haswell (AVX2) as the high-water mark, so AVX-512
+-        # is never needed.
+-        # This must ALSO be applied on Windows: without DYNAMIC_ARCH/NO_AVX512,
+-        # OpenBLAS falls back to build-time CPUID auto-detection of the CI
+-        # runner's host CPU, and some GitHub-hosted Windows runners land on
+-        # AVX-512-capable hosts, which then intermittently fail to compile
+-        # OpenBLAS's SkylakeX kernel under MinGW GCC 16.2 ("inlining failed
+-        # in call to always_inline ...: target specific option mismatch").
+-        # That is the root cause of the flaky "Compile Windows *" job failures
+-        # seen across many CI runs — it depends on which physical host the
+-        # runner happens to land on, not on any code change.
+-        make_vars.append("DYNAMIC_ARCH=1")
+-        make_vars.append("NO_AVX512=1")
+-        # Limit the set of compiled kernels to modern CPUs; pre-2010
+-        # architectures (BARCELONA, CORE2, …) are dropped.  CPUs not in the
+-        # list fall back to the generic kernel — correctness is unaffected.
+-        if dynamic_list:
+-            make_vars.append(f"DYNAMIC_LIST={dynamic_list}")
+-
+-    # Never build the CBLAS C interface — COIN-OR uses Fortran-style BLAS
+-    # (dgemm_, dtrsm_, …) so the cblas_* wrappers are dead weight.
+-    make_vars.append("NO_CBLAS=1")
+-
+-    if extra_cflags:
+-        make_vars.append(f"CFLAGS={extra_cflags}")
+-        make_vars.append(f"FFLAGS={extra_cflags}")
+-
+-    # Build static + shared libs (libs target skips test suite).
+-    # Building shared is required on all platforms so configure scripts
+-    # (CoinUtils LAPACK test) can link against the shared library — static
+-    # requires explicit Fortran runtime flags which is fragile.
+-    run("make", f"-j{NPROC}", "libs", "shared", *make_vars, cwd=src)
+-    run("make", *make_vars, f"PREFIX={dest_dir}", "install", cwd=src)
+-
+-
+-# ── Build SuiteSparse AMD (static only, direct compilation) ──────────────────
+-
+-def build_amd(extra_cflags=""):
+-    src = clone_if_missing(
+-        "SuiteSparse",
+-        "https://github.com/DrTimothyAldenDavis/SuiteSparse.git",
+-        SUITESPARSE_TAG,
+-    )
+-    ss_dir  = os.path.join(src, "SuiteSparse_config")
+-    amd_src = os.path.join(src, "AMD", "Source")
+-    amd_inc = os.path.join(src, "AMD", "Include")
+-
+-    os.makedirs(LIB_DIR, exist_ok=True)
+-    inc_out = os.path.join(DIST_DIR, "include", "suitesparse")
+-    os.makedirs(inc_out, exist_ok=True)
+-
+-    # AMD is a pure combinatorial/integer library — it doesn't use BLAS or
+-    # LAPACK at all.  Compiling directly from C source avoids the SuiteSparse
+-    # cmake build system which unconditionally runs FindBLAS (and fails when
+-    # only a static OpenBLAS is present because the link test needs the
+-    # Fortran runtime libraries).
+-    cc = os.environ.get("CC", "gcc")
+-    cflags = ["-O2", "-fPIC", f"-I{ss_dir}", f"-I{amd_inc}"]
+-    if extra_cflags:
+-        cflags.extend(extra_cflags.split())
+-
+-    # SuiteSparse_config.c → libsuitesparseconfig.a
+-    ss_obj = os.path.join(THIS_DIR, "_ss_config.o")
+-    run(cc, *cflags, "-c",
+-        os.path.join(ss_dir, "SuiteSparse_config.c"), "-o", ss_obj)
+-    run("ar", "rcs", os.path.join(LIB_DIR, "libsuitesparseconfig.a"), ss_obj)
+-
+-    # AMD/Source/*.c → libamd.a
+-    amd_objs = []
+-    for c_file in sorted(_glob.glob(os.path.join(amd_src, "*.c"))):
+-        obj = c_file[:-2] + ".o"
+-        run(cc, *cflags, "-c", c_file, "-o", obj)
+-        amd_objs.append(obj)
+-    run("ar", "rcs", os.path.join(LIB_DIR, "libamd.a"), *amd_objs)
+-
+-    # Install headers
+-    for h in _glob.glob(os.path.join(amd_inc, "*.h")):
+-        shutil.copy2(h, inc_out)
+-    shutil.copy2(os.path.join(ss_dir, "SuiteSparse_config.h"), inc_out)
+-
+-
+-# ── Build COIN-OR projects ────────────────────────────────────────────────────
+-
+-def build_coin_or(dest_dir=None, extra_cxxflags="", extra_ldflags="", is_debug=False):
+-    """Build the full COIN-OR stack and install into *dest_dir*.
+-
+-    *extra_cxxflags* is appended to CXXFLAGS and can be used to enable
+-    architecture-specific optimisations (e.g. "-O3 -march=haswell -DCOIN_AVX2=4"
+-    for the Haswell-optimised build) or debug flags.
+-
+-    *extra_ldflags* is appended to LDFLAGS for all configure calls.  On macOS,
+-    the Clp project already gets "-L{lib_dir} -lopenblas"; extra_ldflags is
+-    merged into that rather than passed separately.
+-
+-    *is_debug* controls whether C assert()s are compiled in.  COIN-OR's own
+-    AC_COIN_PROG_CXX/AC_COIN_PROG_CC autoconf macros normally default
+-    CXXFLAGS/CFLAGS to "-O2 -DNDEBUG" (release) or "-g" (--enable-debug), but
+-    only via ": ${CXXFLAGS:=...}" -- a shell default that never fires because
+-    we always pass CXXFLAGS/CFLAGS explicitly on the configure command line
+-    (to control -march, -ffp-contract, etc.). That silently opted every
+-    release build (generic and AVX2, on every platform) out of -DNDEBUG,
+-    leaving internal consistency assert()s compiled into the SHIPPED wheels:
+-    an assert failing in the field aborts (SIGABRT/access violation) the
+-    caller's process instead of leaving debugging to an explicit debug build.
+-    So: pass is_debug=True for the debug/debug_avx2 variants (which
+-    deliberately want assertions active, see scripts/build_mip_debug_cuts.sh)
+-    and leave it False (the default) for the generic/avx2 release variants,
+-    which now get -DNDEBUG explicitly.
+-    """
+-    if dest_dir is None:
+-        dest_dir = DIST_DIR
+-    lib_dir = os.path.join(dest_dir, "lib")
+-
+-    # AMD is a pure combinatorial/integer library that does not benefit from
+-    # AVX2 and is only built once (into the base cbc_dist/). Both COIN-OR
+-    # variants can safely link against the same static archive.
+-    amd_inc   = os.path.join(DIST_DIR, "include", "suitesparse")
+-
+-    env = os.environ.copy()
+-    pkg_config_dir = os.path.join(lib_dir, "pkgconfig")
+-    # MSYS2 bash uses ':' as separator and MSYS2-format paths.
+-    if platform.system() == "Windows":
+-        env["PKG_CONFIG_PATH"] = (
+-            _win_to_msys2(pkg_config_dir) + ":" + env.get("PKG_CONFIG_PATH", "")
+-        )
+-    else:
+-        env["PKG_CONFIG_PATH"] = (
+-            pkg_config_dir + os.pathsep + env.get("PKG_CONFIG_PATH", "")
+-        )
+-
+-    # Flags common to every project.
+-    # zlib is intentionally kept enabled (it is manylinux2014-allowed and
+-    # lets CBC read compressed MPS/LP files).
+-    common = [
+-        f"--prefix={dest_dir}",
+-        f"--libdir={lib_dir}",
+-        "--enable-static" if platform.system() != "Windows" else "--disable-static",
+-        "--enable-shared",      # produce .so/.dylib/.dll for cffi use
+-        "--disable-readline",   # libreadline not manylinux-allowed
+-        "--disable-bzlib",      # libbz2 not manylinux-allowed
+-        "--without-cholmod",    # use AMD instead
+-        "--without-glpk",       # not needed
+-        "--without-asl",        # AMPL solver library not needed
+-    ]
+-    if platform.system() == "Windows":
+-        # Declare both build and host as MinGW64 so that autoconf sets
+-        # cross_compiling=no (build==host) and uses the plain gcc/g++ from
+-        # /mingw64/bin rather than looking for x86_64-w64-mingw32-prefixed
+-        # cross-compiler tools.  With host_os=mingw32, libtool names DLLs as
+-        # lib*.dll (MinGW convention) rather than cyg*.dll (Cygwin convention).
+-        common += ["--build=x86_64-w64-mingw32", "--host=x86_64-w64-mingw32"]
+-
+-    # Use a distinct build sub-directory per variant so that generic,
+-    # AVX2, and debug builds can coexist in the same cloned source tree.
+-    if dest_dir == DIST_DIR:
+-        bld_suffix = "_build"
+-    elif dest_dir == DIST_DIR_AVX2:
+-        bld_suffix = "_build_avx2"
+-    elif dest_dir == DIST_DIR_DEBUG_AVX2:
+-        bld_suffix = "_build_debug_avx2"
+-    else:
+-        bld_suffix = "_build_debug"
+-
+-    for name, url in COIN_REPOS:
+-        src = clone_if_missing(name, url, COIN_OR_BRANCH)
+-        bld = os.path.join(src, bld_suffix)
+-        os.makedirs(bld, exist_ok=True)
+-
+-        extra = []
+-        ldflags_in_extra = False
+-        if name == "CoinUtils":
+-            # OpenBLAS provides both BLAS and LAPACK in one archive.
+-            # AMD provides fill-reducing ordering for sparse systems.
+-            #
+-            # On macOS, COINUTILS_HAS_LAPACK causes CoinDenseFactorization to
+-            # call OpenBLAS's dgetrf_single, which uses aligned AVX2 loads
+-            # (vmovdqa).  CoinDenseFactorization's elements_ buffer is allocated
+-            # with plain new[] (8/16-byte aligned), causing SIGSEGV on the
+-            # unaligned 32-byte AVX2 access.  Disabling LAPACK for CoinUtils
+-            # makes it fall back to the built-in pure-C pivot factorization,
+-            # which is correct and fast enough for the small dense bases
+-            # encountered in practice (e.g. 36-row LP).  Clp still gets LAPACK
+-            # via its own --with-lapack-lflags.
+-            if platform.system() == "Darwin":
+-                extra += ["--without-lapack"]
+-            else:
+-                extra += [f"--with-lapack-lflags=-L{lib_dir} -lopenblas"]
+-            extra += [
+-                f"--with-amd-cflags=-I{amd_inc}",
+-                f"--with-amd-lflags=-L{LIB_DIR} -lamd -lsuitesparseconfig",
+-            ]
+-        elif name == "Clp":
+-            # Do NOT pass --with-amd-cflags here: Clp wraps #include <amd.h>
+-            # inside extern "C" {} in ClpCholeskyUfl.cpp, and SuiteSparse v7's
+-            # amd.h transitively includes C++ headers (<complex> etc.) which
+-            # clang rejects inside extern "C".  AMD ordering is still available
+-            # to CBC through CoinUtils which doesn't have this wrapping issue.
+-            # --without-amd is required (not just omitting the flag): Clp's
+-            # configure auto-probes default system paths (e.g.
+-            # /usr/include/suitesparse) for AMD and, if found, compiles
+-            # ClpCholeskyUfl.cpp against it — but without --with-amd-lflags
+-            # the resulting libClp fails to link with undefined references to
+-            # SuiteSparse_malloc/SuiteSparse_free on any host that happens to
+-            # have a system SuiteSparse package installed.
+-            extra += [
+-                "--without-amd",
+-                f"--with-lapack-lflags=-L{lib_dir} -lopenblas",
+-            ]
+-            if platform.system() == "Darwin":
+-                # ClpMain.cpp calls openblas_set_num_threads() when CLP_USE_OPENBLAS=1.
+-                # On macOS two-level namespace, the clp executable must link -lopenblas
+-                # explicitly — transitive propagation via libClp.dylib is not enough.
+-                # --with-lapack-lflags covers shared library dependencies but the
+-                # executable link step needs LDFLAGS for direct symbol resolution.
+-                darwin_ldflags = f"-L{lib_dir} -lopenblas"
+-                if extra_ldflags:
+-                    darwin_ldflags += f" {extra_ldflags}"
+-                extra += [f"LDFLAGS={darwin_ldflags}"]
+-                ldflags_in_extra = True
+-            elif platform.system() == "Linux":
+-                # ClpRacingSolver.cpp resolves openblas_set_num_threads() via
+-                # dlsym(RTLD_DEFAULT, ...) when CLP_USE_OPENBLAS is defined
+-                # (which it always is here). glibc < 2.34 (e.g. manylinux2014,
+-                # manylinux_2_28) keeps dlopen/dlsym in libdl rather than libc,
+-                # and it is not linked automatically, causing "undefined
+-                # reference to `dlsym'" when linking libClp.so. Newer glibc
+-                # (>= 2.34) folds libdl into libc, so -ldl is a harmless no-op
+-                # there.
+-                linux_ldflags = "-ldl"
+-                if extra_ldflags:
+-                    linux_ldflags += f" {extra_ldflags}"
+-                extra += [f"LDFLAGS={linux_ldflags}"]
+-                ldflags_in_extra = True
+-        elif name == "Cbc":
+-            extra += [
+-                "--without-nauty",     # symmetry detection via nauty disabled
+-                "--without-lapack",
+-                # Enable multi-threaded MIP search (parallel branch-and-bound).
+-                # Requires pthreads — available on all supported platforms.
+-                "--enable-cbc-parallel",
+-            ]
+-            if platform.system() == "Linux":
+-                # Same dlsym/libdl requirement as Clp above: CbcModel.cpp and
+-                # Cbc_C_Interface.cpp also resolve openblas_set_num_threads()
+-                # and omp_set_num_threads() via dlsym(RTLD_DEFAULT, ...).
+-                linux_ldflags = "-ldl"
+-                if extra_ldflags:
+-                    linux_ldflags += f" {extra_ldflags}"
+-                extra += [f"LDFLAGS={linux_ldflags}"]
+-                ldflags_in_extra = True
+-        else:  # Osi, Cgl — do not use LAPACK directly
+-            extra += ["--without-lapack"]
+-
+-        configure = os.path.join(src, "configure")
+-        # clang (macOS) requires C++17 mode to accept aggregate assignment from
+-        # braced initializer lists (e.g. CoinDynamicConflictGraph.cpp).
+-        # -std=c++17 is harmless on GCC as well.
+-        # Note: -no-undefined is NOT passed here via LDFLAGS because it is a
+-        # libtool-specific flag, not a raw linker flag.  Passing it via LDFLAGS
+-        # causes configure's own link tests ("C compiler cannot create
+-        # executables") to fail with exit code 77 on MinGW.  COIN-OR's
+-        # AC_COIN_PROG_LIBTOOL macro already appends -no-undefined to
+-        # LT_LDFLAGS internally (aclocal.m4), which is the correct path —
+-        # it reaches libtool only when building shared libraries.
+-        # Clp and Cbc both check CLP_USE_OPENBLAS to conditionally compile
+-        # the OpenBLAS thread-count management (openblas_set_num_threads).
+-        # This enables CbcModel to cap BLAS threads to 1 during parallel B&B,
+-        # preventing stack overflow crashes on macOS whose secondary threads
+-        # have a 512 KB default stack (vs 8 MB on Linux).
+-        openblas_flag = "-DCLP_USE_OPENBLAS=1" if name in ("Clp", "Cbc") else ""
+-        # -DNDEBUG strips assert()s for release builds (never added by
+-        # autoconf's own defaults here -- see the is_debug docstring above);
+-        # debug builds must NOT get it so assertions stay active for gdb/ASan.
+-        ndebug_flag = "" if is_debug else "-DNDEBUG"
+-        cxxflags_parts = ["-std=c++17", FP_CONTRACT_OFF]
+-        if ndebug_flag:
+-            cxxflags_parts.append(ndebug_flag)
+-        if extra_cxxflags:
+-            cxxflags_parts.append(extra_cxxflags)
+-        if openblas_flag:
+-            cxxflags_parts.append(openblas_flag)
+-        cxxflags = " ".join(cxxflags_parts)
+-        # Also set CFLAGS: the COIN-OR stack is pure C++ (no .c sources as of
+-        # this writing), so this is mostly a defensive no-op, but configure's
+-        # own link/feature-detection tests invoke $CC directly and future .c
+-        # files would silently pick up FMA contraction otherwise.
+-        cflags_parts = [FP_CONTRACT_OFF]
+-        if ndebug_flag:
+-            cflags_parts.append(ndebug_flag)
+-        configure_args = [
+-            configure, *common, *extra,
+-            f"CXXFLAGS={cxxflags}", f"CFLAGS={' '.join(cflags_parts)}",
+-        ]
+-        if extra_ldflags and not ldflags_in_extra:
+-            configure_args.append(f"LDFLAGS={extra_ldflags}")
+-        run(*configure_args, cwd=bld, env=env)
+-        run("make", "-j", NPROC, cwd=bld)
+-        run("make", "install", cwd=bld)
+-
+-
+-# ── Bundle dynamic dependencies ───────────────────────────────────────────────
+-
+-def _is_system_lib(path: str) -> bool:
+-    """Return True for libs that should NOT be bundled into the wheel."""
+-    name = os.path.basename(path)
+-    if platform.system() == "Linux":
+-        return bool(_MANYLINUX_ALLOWED.match(name))
+-    # macOS: only the standard system library trees are truly "system".
+-    # A loader-relative (@rpath/@loader_path/@executable_path) install name
+-    # does NOT necessarily mean the lib has already been bundled: modern
+-    # Homebrew GCC reports its own runtime libs (libgcc_s, libstdc++, ...)
+-    # with an @rpath install name from the start, before cbcbox's own
+-    # bundling pass ever touches them. Those still need to be resolved to
+-    # a real file on disk and copied in; see _resolve_macos_dep().
+-    return path.startswith("/usr/lib/") or path.startswith("/System/")
+-
+-
+-def _resolve_macos_dep(binary: str, dep: str) -> str:
+-    """Resolve a loader-relative (@rpath/@loader_path/@executable_path)
+-    dependency reference *dep* found in *binary* to an absolute file path.
+-
+-    Returns "" if it cannot be resolved.
+-    """
+-    if not dep.startswith("@"):
+-        return dep
+-    name = os.path.basename(dep)
+-    base_dir = os.path.dirname(os.path.realpath(binary))
+-
+-    # 0) @loader_path/@executable_path are directly relative to the
+-    #    binary's own directory -- no need to consult LC_RPATH.
+-    if dep.startswith("@loader_path/") or dep.startswith("@executable_path/"):
+-        candidate = os.path.join(base_dir, name)
+-        if os.path.exists(candidate):
+-            return candidate
+-
+-    # 1) Look at the binary's own LC_RPATH entries (this is how the
+-    #    dynamic linker would actually resolve an @rpath/ reference).
+-    if dep.startswith("@rpath/"):
+-        out = subprocess.run(
+-            ["otool", "-l", binary], capture_output=True, text=True
+-        ).stdout
+-        lines = out.splitlines()
+-        rpaths = []
+-        for i, line in enumerate(lines):
+-            if line.strip() == "cmd LC_RPATH":
+-                for j in range(i, min(i + 4, len(lines))):
+-                    m = re.search(r"path (.+) \(offset", lines[j])
+-                    if m:
+-                        rpaths.append(m.group(1).strip())
+-                        break
+-        for rp in rpaths:
+-            rp = rp.replace("@loader_path", base_dir).replace(
+-                "@executable_path", base_dir
+-            )
+-            candidate = os.path.join(rp, name)
+-            if os.path.exists(candidate):
+-                return candidate
+-
+-    # 2) Fall back to the compiler toolchain -- this covers GCC runtime
+-    #    libs (libgcc_s, libstdc++, libquadmath, libgfortran) that Homebrew
+-    #    GCC reports with an @rpath install name but which live in the
+-    #    toolchain's own lib directory, not next to *binary*.
+-    for cc in ("gfortran", "gcc", "g++"):
+-        try:
+-            r = subprocess.run(
+-                [cc, "-print-file-name=" + name],
+-                capture_output=True, text=True,
+-            )
+-        except FileNotFoundError:
+-            continue
+-        candidate = r.stdout.strip()
+-        if candidate and candidate != name and os.path.exists(candidate):
+-            return candidate
+-
+-    return ""
+-
+-
+-def _soname_linux(lib_path: str) -> str:
+-    """Return the ELF SONAME of *lib_path*, falling back to its basename."""
+-    try:
+-        r = subprocess.run(
+-            ["patchelf", "--print-soname", lib_path],
+-            capture_output=True, text=True,
+-        )
+-        soname = r.stdout.strip()
+-        if soname:
+-            return soname
+-    except Exception:
+-        pass
+-    return os.path.basename(lib_path)
+-
+-
+-def _dynamic_deps_linux(path: str) -> dict:
+-    """Return {soname: resolved_path} for non-system deps on Linux."""
+-    out = subprocess.run(["ldd", path], capture_output=True, text=True).stdout
+-    deps = {}
+-    for line in out.splitlines():
+-        m = re.search(r"\s=>\s(/\S+)", line)
+-        if m and not _is_system_lib(m.group(1)):
+-            resolved = m.group(1)
+-            # Use the ELF soname as the destination filename so the dynamic
+-            # linker finds it even when ldd reports the versioned real file.
+-            deps[_soname_linux(resolved)] = resolved
+-    return deps
+-
+-
+-def _dynamic_deps_macos(path: str) -> list:
+-    """Return [install_name, ...] for non-system deps on macOS."""
+-    out = subprocess.run(
+-        ["otool", "-L", path], capture_output=True, text=True
+-    ).stdout
+-    deps = []
+-    for line in out.splitlines()[1:]:
+-        parts = line.strip().split()
+-        if parts and not _is_system_lib(parts[0]):
+-            deps.append(parts[0])
+-    return deps
+-
+-
+-def _dynamic_deps_windows(path: str) -> dict:
+-    """Return {dll_name: source_path} for non-system MinGW DLLs needed by *path*.
+-
+-    Uses objdump (from MinGW64) to list DLL imports, then resolves each name
+-    against C:\\msys64\\mingw64\\bin\\ and DIST_DIR\\bin\\ (for DLLs installed
+-    by our own build, such as libopenblas.dll).
+-    """
+-    search_dirs = [r"C:\msys64\mingw64\bin", os.path.join(DIST_DIR, "bin")]
+-    r = subprocess.run(
+-        [_MSYS2_BASH, "-lc",
+-         "export PATH=/mingw64/bin:/usr/bin:$PATH && "
+-         f"objdump -p {shlex.quote(_win_to_msys2(path))} | grep 'DLL Name:'"],
+-        capture_output=True, text=True,
+-    )
+-    deps = {}
+-    for line in r.stdout.splitlines():
+-        m = re.search(r"DLL Name:\s+(\S+\.dll)", line, re.IGNORECASE)
+-        if m:
+-            name = m.group(1)
+-            if not _WIN_SYS_DLL.match(name):
+-                for search_dir in search_dirs:
+-                    candidate = os.path.join(search_dir, name)
+-                    if os.path.exists(candidate):
+-                        deps[name] = candidate
+-                        break
+-    return deps
+-
+-
+-def bundle_dynamic_deps(binary: str, lib_dir: str, _visited: set = None):
+-    """
+-    Inspect *binary* for non-system dynamic dependencies and handle them so
+-    the wheel is self-contained:
+-
+-    Linux  — copies each .so to *lib_dir* and uses patchelf to set an
+-             $ORIGIN-relative RPATH on both the binary and every copied lib.
+-    macOS  — copies each .dylib to *lib_dir*, rewrites the install-name
+-             reference inside *binary* to @rpath/name, sets the copied
+-             lib's own id to @rpath/name, and adds an @loader_path rpath
+-             to the binary.
+-    Windows — copies each non-system MinGW DLL next to the binary (in its
+-              own directory); no rpath patching needed since Windows searches
+-              the executable's directory first.
+-
+-    Recurses into copied libraries so transitive deps are also covered.
+-    If everything was statically linked this function is a no-op.
+-    """
+-    if _visited is None:
+-        _visited = set()
+-    os.makedirs(lib_dir, exist_ok=True)
+-
+-    in_lib_dir = (
+-        os.path.dirname(os.path.realpath(binary)) == os.path.realpath(lib_dir)
+-    )
+-
+-    if platform.system() == "Linux":
+-        rpath = "$ORIGIN" if in_lib_dir else "$ORIGIN/../lib"
+-        subprocess.run(["patchelf", "--set-rpath", rpath, binary], check=True)
+-
+-        for name, src_path in _dynamic_deps_linux(binary).items():
+-            if name in _visited:
+-                continue
+-            _visited.add(name)
+-            dst = os.path.join(lib_dir, name)
+-            if not os.path.exists(dst):
+-                shutil.copy2(src_path, dst)
+-                os.chmod(dst, 0o755)
+-            bundle_dynamic_deps(dst, lib_dir, _visited)
+-
+-    elif platform.system() == "Darwin":
+-        rpath = "@loader_path" if in_lib_dir else "@loader_path/../lib"
+-        # Silently ignore "already exists" errors from install_name_tool.
+-        subprocess.run(
+-            ["install_name_tool", "-add_rpath", rpath, binary],
+-            capture_output=True,
+-        )
+-
+-        for install_name in _dynamic_deps_macos(binary):
+-            name = os.path.basename(install_name)
+-
+-            # Always resolve a real on-disk source for this dependency (needed
+-            # to copy it into lib_dir even when `binary`'s reference is
+-            # already @rpath/name and needs no rewrite -- e.g. Homebrew GCC's
+-            # own libgcc_s reported natively via @rpath).
+-            src_path = install_name
+-            if install_name.startswith("@"):
+-                resolved = _resolve_macos_dep(binary, install_name)
+-                if not resolved:
+-                    print(
+-                        f"warning: could not resolve {install_name} "
+-                        f"referenced by {binary}; not bundled, may "
+-                        f"fail to load at runtime",
+-                        file=sys.stderr,
+-                    )
+-                src_path = resolved or None
+-
+-            # Always fix up *this* binary's own reference, regardless of
+-            # whether the target dependency file has already been bundled
+-            # ("visited") via some other referencing binary. The previous
+-            # code skipped this whenever `name in _visited`, which meant
+-            # only the *first* binary reaching a given dependency (in DFS
+-            # traversal order) got its reference rewritten to @rpath --
+-            # every other binary kept the absolute build-machine path.
+-            if install_name != f"@rpath/{name}":
+-                subprocess.run(
+-                    ["install_name_tool", "-change", install_name, f"@rpath/{name}", binary],
+-                    check=True,
+-                )
+-
+-            if name in _visited:
+-                continue
+-            _visited.add(name)
+-
+-            dst = os.path.join(lib_dir, name)
+-            if not os.path.exists(dst) and src_path:
+-                shutil.copy2(src_path, dst)
+-                os.chmod(dst, 0o755)
+-            if os.path.exists(dst):
+-                # Normalize the lib's own id to @rpath/name. This also
+-                # covers libraries that were already sitting in lib_dir
+-                # from the start (e.g. sibling COIN-OR libs built straight
+-                # there) and never went through the "freshly copied" path
+-                # above, which previously left their LC_ID_DYLIB as an
+-                # absolute build-machine path.
+-                subprocess.run(
+-                    ["install_name_tool", "-id", f"@rpath/{name}", dst],
+-                    capture_output=True,
+-                )
+-                bundle_dynamic_deps(dst, lib_dir, _visited)
+-
+-    elif platform.system() == "Windows":
+-        # On Windows the loader finds DLLs in the same directory as the
+-        # executable. Copy all non-system MinGW DLLs there and recurse for
+-        # transitive dependencies (libgfortran → libquadmath, etc.).
+-        bin_dir = os.path.dirname(os.path.realpath(binary))
+-        for name, src_path in _dynamic_deps_windows(binary).items():
+-            if name in _visited:
+-                continue
+-            _visited.add(name)
+-            dst = os.path.join(bin_dir, name)
+-            if not os.path.exists(dst):
+-                shutil.copy2(src_path, dst)
+-                os.chmod(dst, 0o755)
+-            bundle_dynamic_deps(dst, lib_dir, _visited)
+-
+-
+-# ── Windows: mirror DLLs into lib/ ───────────────────────────────────────────
+-
+-def copy_win_dlls_to_lib(dist_dir=None):
+-    """Copy every DLL from bin/ into lib/ as well.
+-
+-    On Windows, libtool installs DLLs to bindir (bin/) and import libs
+-    (.dll.a) to libdir (lib/).  python-mip and other ctypes/cffi consumers
+-    locate libraries via cbcbox.cbc_lib_dir() which points to lib/, so all
+-    DLLs must also be present there — both the COIN-OR ones (libCbc.dll, …)
+-    and the bundled MinGW runtime DLLs they depend on.
+-    """
+-    if dist_dir is None:
+-        dist_dir = DIST_DIR
+-    bin_dir = os.path.join(dist_dir, "bin")
+-    lib_dir = os.path.join(dist_dir, "lib")
+-    os.makedirs(lib_dir, exist_ok=True)
+-    for dll in _glob.glob(os.path.join(bin_dir, "*.dll")):
+-        dst = os.path.join(lib_dir, os.path.basename(dll))
+-        if not os.path.exists(dst):
+-            shutil.copy2(dll, dst)
+-
+-
+-
+-_cbc_exe = "cbc.exe" if platform.system() == "Windows" else "cbc"
+-
+-# CBCBOX_BUILD_VARIANT controls which variants are compiled (used by CI to run
+-# builds in parallel jobs):
+-#   unset / "all"  — build generic, AVX2 (x86_64), and debug:
+-#                      x86_64:     generic + avx2 + debug_avx2
+-#                      other arch: generic + debug
+-#   "generic"      — build only the generic variant (no debug)
+-#   "avx2"         — build only the AVX2 variant (x86_64 only, no debug)
+-#   "debug"        — build only the non-AVX2 debug variant (all platforms)
+-#                    COIN-OR flags: -O1 -g -fno-omit-frame-pointer
+-#                    AddressSanitizer automatically enabled on Linux and macOS.
+-#   "debug_avx2"   — build only the debug+AVX2 variant (x86_64 only)
+-#                    COIN-OR flags: -O1 -g -march=haswell -fno-omit-frame-pointer
+-#                    AddressSanitizer automatically enabled on Linux and macOS.
+-#                    Use this to debug AVX2-specific issues or to run a debuggable
+-#                    binary that exercises the same AVX2 code paths as the release.
+-#   "release_symbols" — build only the generic *release* variant (same CXXFLAGS,
+-#                    same optimisation level, same -DNDEBUG) with -g added on
+-#                    top, so the resulting binary is bit-for-bit behaviourally
+-#                    identical to what actually ships, just with debug symbols.
+-#                    Use this (under gdb) to get a real backtrace for bugs that
+-#                    only reproduce with release codegen/optimisation and do
+-#                    NOT reproduce in the "debug" (-O1) variant.
+-# In "avx2" mode AMD is still compiled (as a link-time static dep for the
+-# COIN-OR AVX2 build) but with Haswell-optimised flags.
+-# OpenBLAS and AMD are always built without debug flags; only the COIN-OR stack
+-# (CoinUtils, Osi, Clp, Cgl, Cbc) carries debug symbols in debug builds.
+-#
+-# CBCBOX_BUILD_ONLY=1 — skip the wheel-packaging stage (used by CI compile
+-# jobs that only need the binaries, not the final .whl).
+-_build_variant    = os.environ.get("CBCBOX_BUILD_VARIANT", "")
+-_build_release_symbols = _build_variant == "release_symbols"
+-_build_generic    = _build_variant not in ("avx2", "debug", "debug_avx2", "release_symbols")
+-_build_avx2       = _is_x86_64() and _build_variant not in ("generic", "debug", "debug_avx2", "release_symbols")
+-# Debug (non-AVX2): built by default on non-x86_64; on x86_64 only when
+-# explicitly requested so we avoid a redundant generic-debug wheel alongside
+-# the haswell-debug one.
+-_build_debug      = _build_variant == "debug" or (_build_variant == "" and not _is_x86_64())
+-# Debug+AVX2: built by default on x86_64 (the only debug variant for that arch).
+-_build_debug_avx2 = _is_x86_64() and (_build_variant == "debug_avx2" or _build_variant == "")
+-
+-if _build_variant == "debug_avx2" and not _is_x86_64():
+-    print(
+-        f"[cbcbox] WARNING: CBCBOX_BUILD_VARIANT=debug_avx2 is only supported on x86_64 "
+-        f"(current arch: {platform.machine()}). No build will be performed.",
+-        flush=True,
+-    )
+-
+-# Flags applied to all C/C++ code in the AVX2 variant, including the static
+-# AMD library that is ultimately linked into COIN-OR .so/.dylib.
+-_AVX2_CFLAGS = "-O3 -march=haswell"
+-
+-# OpenBLAS DYNAMIC_ARCH kernel lists for x86_64 (reduces library size by
+-# dropping pre-2010 architectures that are unlikely to be encountered).
+-# CPUs not covered by the list fall back to the generic kernel automatically.
+-#   Generic: SSE4.2 baseline (Nehalem 2008+) through current Zen.
+-#   AVX2:    only AVX2-capable targets (Haswell 2013+).
+-# ZEN2, ZEN3, SKYLAKE are excluded: OpenBLAS 0.3.31 compiles their generic C
+-# dot/nrm2 kernels with AVX2+FMA intrinsics but omits -mfma from the compiler
+-# invocation, causing an "always_inline target mismatch" build error.
+-# ZEN2/ZEN3 users fall back to the ZEN kernel (still AVX2); SKYLAKE falls back
+-# to HASWELL — both negligible in practice.
+-_OPENBLAS_DYNLIST_X86_GENERIC = "NEHALEM SANDYBRIDGE HASWELL SKYLAKEX ZEN"
+-_OPENBLAS_DYNLIST_X86_AVX2    = "HASWELL SKYLAKEX"
+-
+-# AddressSanitizer is automatically enabled for debug builds on Linux and macOS.
+-# Windows/MinGW does not support ASan, so it is skipped there.
+-# OpenBLAS is always built without ASan to avoid false positives from its
+-# hand-optimised BLAS kernels; only the COIN-OR stack is instrumented.
+-# Debug build flags: -O1 -g (no ASan — ASan proved too fragile across
+-# the different CI container toolchains; debug info alone is sufficient
+-# for stack traces and debugger use).
+-_DEBUG_CFLAGS      = "-O1 -g -fno-omit-frame-pointer"
+-_DEBUG_LDFLAGS     = ""
+-_DEBUG_AVX2_CFLAGS  = "-O1 -g -march=haswell -fno-omit-frame-pointer"
+-_DEBUG_AVX2_LDFLAGS = ""
+-
+-if _build_generic and not os.path.exists(os.path.join(DIST_DIR, "bin", _cbc_exe)):
+-    build_openblas(DIST_DIR, dynamic_arch=True,
+-                   dynamic_list=_OPENBLAS_DYNLIST_X86_GENERIC if _is_x86_64() else None)
+-    build_amd()
+-    build_coin_or(DIST_DIR)
+-
*** 421 LINES SKIPPED ***