多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

SciPy 构建实战:BLAS/LAPACK 库选择、g77 ABI 与 ILP64 配置完全指南

SciPy 构建实战:BLAS/LAPACK 库选择、g77 ABI 与 ILP64 配置完全指南 科学计算数据科学高性能计算【免费下载链接】scipySciPy library main repository项目地址https://gitcode.com/gh_mirrors/sc/scipy点击查看免费下载本指南以 SciPy 官方构建文档 doc/source/building/blas_lapack.rst 为骨架系统讲解从源码构建 SciPy 时如何选择 BLAS/LAPACK 后端OpenBLAS、MKL、Accelerate、BLIS、ATLAS、Netlib 等、如何在非标准路径下借助 pkg-config 发现独立库文件、如何解决 g77/gfortran 两种 Fortran ABI 不兼容问题以及 ILP6464 位整数构建与 Cython 层整数 ABI 的取舍。读完本文你将掌握 SciPy 各类 BLAS/LAPACK 构建选项的准确写法、底层检测原理以及下游 Cython 包如何适配blas_int/blas_bint类型以同时兼容 LP64 与 ILP64 构建。构建选项总览一切从 Meson 选项开始SciPy 目前采用 Meson 构建系统BLAS/LAPACK 的库选择除默认的 OpenBLAS 外全部通过 Mesonbuild options机制实现。所有相关选项集中定义在仓库根目录的 meson.options 文件中其默认值如下选项类型默认值说明blasstringopenblas要链接的 BLAS 库lapackstringopenblas要链接的 LAPACK 库use-ilp64booleanfalse是否使用 ILP6464 位整数BLAS/LAPACK 接口cython-blas-abicomboautocython_blas/cython_lapackCython API 的整数 ABI取值auto/lp64/ilp64blas-symbol-suffixstringauto使用的 BLAS/LAPACK 符号后缀mkl-threadingstringautoMKL 线程方式可选seq/iomp/gomp/tbbuse-g77-abibooleanfalse是否强制使用 g77 兼容包装器调用 LAPACK其中use-ilp64、cython-blas-abi、use-g77-abi三个选项正是本指南后续三个核心章节的构建开关blas与lapack选项名直接对应构建命令行中的-Dblas与-Dlapack参数。选择 BLAS 与 LAPACK 实现开发构建与打包构建的两种写法文档给出了开发构建配合 SciPy 自带的spin工具与打包发布python -m build两种场景下切换到纯libblas/liblapack的命令。这里说的纯libblas在 Linux 发行版上通常指 Netlib BLAS/LAPACK而在 conda-forge 上可以通过链接器机制在同一套库名上动态切换不同实现# 开发构建spin $ spin build -S-Dblasblas -S-Dlapacklapack # 构建并安装 wheel $ python -m build -Csetup-args-Dblasblas -Csetup-args-Dlapacklapack $ pip install dist/scipy*.whl # 或者pip23.1 起也可这样直接使用 $ python -m pip -Csetup-args-Dblasblas -Csetup-args-Dlapacklapack注意两种命令行前缀的区别spin使用-S-Dblas...-S表示把选项透传给 Meson setup而python -m build使用-Csetup-args-Dblas...-C把参数传给 build 后端。文档最后还给出了省略setup-args前缀直接写-C-Duse-g77-abitrue的用法说明-Csetup-args与-C均可接受。各主流实现的选择参数只要对应库以pkg-config或 CMake 方式安装到位以下选项均可正常工作AcceleratemacOS 系统框架-DblasaccelerateMKL使用其对应 pkg-config 文件名例如-Dblasmkl-dynamic-lp64-gompBLIS-Dblasblis——注意 BLIS 只提供 BLAS因此还需要同时给出-Dlapack指向一个 LAPACK 实现ATLAS-Dblasblas-atlas具体 pkg-config 文件名可能随发行版而异由于 Accelerate、MKL 与 SciPy 官方配套的scipy-openblas都同时包含 BLAS 与 LAPACK 两套接口且二者版本必然一致因此这三种情况下无需再指定-Dlapack。例如仅用一条参数即可构建出基于 Accelerate 的 wheel$ python -m build -Csetup-args-Dblasacceleratespin 的便捷别名对于日常开发最常用的两个后端spin提供了更易记忆的专属开关$ spin build --with-accelerate $ spin build --with-scipy-openblas32其中--with-scipy-openblas32后面的数字对应scipy-openblas打包时的符号宽度LP64这是开发环境中最常见的选择之一。使用 pkg-config 检测非标准位置的库底层检测机制文档明确指出Meson 在后台对指定库的发现顺序是先用pkg-config探测再用 CMake 探测。因此当你手里只有一套散落的共享库文件时例如armpl_lp64.so位于/a/random/path/lib/对应头文件位于/a/random/path/include/正确的做法不是去改 Meson 配置而是手工编写一个 pkg-config 的.pc文件。编写自己的 .pc 文件.pc文件的名称必须与-Dblas/-Dlapack中使用的名字一致本例为armpl_lp64.pc位置则可以放在任意目录通过环境变量PKG_CONFIG_PATH指向它。文件内容模板如下libdir/path/to/library-dir # e.g., /a/random/path/lib includedir/path/to/include-dir # e.g., /a/random/path/include version1.2.3 # set to actual version extralib-lm -lpthread -lgfortran # if needed, the flags to link in dependencies Name: armpl_lp64 Description: ArmPL - Arm Performance Libraries Version: ${version} Libs: -L${libdir} -larmpl_lp64 # linker flags Libs.private: ${extralib} Cflags: -I${includedir}验证 .pc 文件是否生效编写完成后用pkg-config的两个查询命令即可验证解析是否正确$ pkg-config --libs armpl_lp64 -L/path/to/library-dir -larmpl_lp64 $ pkg-config --cflags armpl_lp64 -I/path/to/include-dir若输出与预期一致说明 SciPy 构建时也能通过这条PKG_CONFIG_PATH找到该库。指定 Fortran ABIg77 与 gfortran 的兼容问题问题根源部分线性代数库使用g77ABI又称 f2c calling convention编译另一些则使用 GFortran ABI这两种 ABI 彼此不兼容。SciPy 默认按 GFortran ABI 构建如果链接到用 g77 ABI 构建的库MKL 是典型代表运行时会抛出异常甚至直接段错误segfault。SciPy 的解决方式文档说明 SciPy 通过ABI 包装器ABI wrappers来解决包装器依赖 CBLAS API或针对 BLAS API 中少数受影响函数使用自定义包装。这一点可以从源码得到印证——仓库中的 scipy/_build_utils/_generate_blas_wrapper.py 注释说明这些包装器被硬编码在wrap_g77_abi.c与wrap_dummy_g77_abi.c中用于处理 ABI 差异及缺失符号对应实现位于 scipy/_build_utils/src/wrap_dummy_g77_abi.c其注释同样说明wrap_g77_abi.c中的包装器通过调用对应接口来保证兼容性。自动检测与手动覆盖关键点在于SciPy 必须在构建时就知道该走哪条路径。构建系统会自动检测目标库是否为 MKL 或 Accelerate——这两者恒为 g77 ABI——若命中则改用 CBLAS API 而非 BLAS API。当自动检测失效或用户希望针对纯libblas/liblapack强制使用该机制时conda-forge 就是这么做的使用-Duse-g77-abitrue选项覆盖$ python -m build -C-Duse-g77-abitrue -Csetup-args-Dblasblas -Csetup-args-Dlapacklapack构建 ILP6464 位整数BLAS/LAPACK构建开关与典型命令以-Duse-ilp64true开启 ILP64 支持。官方文档给出两个典型示例macOS 上使用 Accelerate$ python -m build --wheel -Csetup-args-Dblasaccelerate -C-Duse-ilp64true -Dcython-blas-abilp64x86-64 上使用 MKL# 注意 -Dblas 参数中的 lp64 并非笔误只要 cython_blas ABI 设置为 lp64见下节就必须如此 $ python -m build --wheel -Csetup-args-Dblasmkl-dynamic-lp64-seq -C-Duse-ilp64true -Dcython-blas-abilp64-Dblasmkl-dynamic-lp64-seq中的lp64表示链接 MKL 的 LP64 符号集即符号本身是 32 位整数接口而-Duse-ilp64true会通过符号后缀或 CBLAS 层让 SciPy 内部拿到 ILP64 能力——这正是blas-symbol-suffix选项存在的意义。对 Python 层 API 的影响构建时开启-Duse-ilp64true会默认同时把scipy.linalg中的底层 Python 与 Cython API 翻转为 ILP64这可能导致下游用法需要相应适配。在 Python 层底层 BLAS/LAPACK 函数可从scipy.linalg.blas与scipy.linalg.lapack两个命名空间获得两者均已在 scipy/linalg/init.py 中导入并公开 from scipy.linalg.blas import dgemm # 可能是 LP64 或 ILP64 版本要显式选择某个底层例程的具体变体使用get_blas_funcs与get_lapack_funcs两个选择函数。其实现位于 scipy/linalg/blas.py 与 scipy/linalg/lapack.py均带_memoize_get_funcs记忆化装饰器以缓存查找结果ilp64参数接受True/False/preferred三种取值其中preferred表示优先返回 ILP64 例程若不可用则回退到 32 位 LP64 例程默认即为preferred。返回函数的int_dtype属性记录了整型参数的实际位宽 from scipy.linalg.blas import get_blas_funcs daxpy get_blas_funcs(axpy, (np.ones(3),), ilp64preferred) daxpy.int_dtype dtype(int64) # depends on the build option高层线性代数函数norm、solve等在内部正是通过这套机制选择例程因此对 LP64/ILP64 是透明兼容的用户无需关心具体位宽。运行时确认构建配置构建完成后可以通过scipy.show_config()在运行时核对当前构建的配置细节重点关注其中的blas cython ilp64条目它直接反映 Cython 层的整数 ABI 设置。Cython BLAS/LAPACK 整数 ABIblas_int 与 blas_bint 类型Cython 层的 BLAS/LAPACK APIscipy.linalg.cython_blas与scipy.linalg.cython_lapack对所有整型参数统一使用blas_int类型。默认情况下blas_int跟随use-ilp64设置LP64 构建解析为 C 的int32 位ILP64 构建解析为int64_t64 位。这一映射关系可在 scipy/_build_utils/_wrappers_common.py 中看到blas_int: CBLAS_INT的定义。部分 LAPACK 函数使用布尔变量Fortran 的logical对应地cython_lapack使用blas_bint类型当blas_int解析为 Cint时blas_bint解析为 Cython 的bint当blas_int解析为int64_t时blas_bint同样解析为int64_t。-Dcython-blas-abi 的三个取值blas_int的行为可通过-Dcython-blas-abi构建选项覆盖它接受三个值auto默认跟随use-ilp64设置lp64即使use-ilp64true也始终使用 32 位整数ilp64始终使用 64 位整数。例如想要构建 ILP64 的 BLAS/LAPACK、但把 Cython API 保持在 LP64为了下游兼容时$ spin build -S-Dblasaccelerate -S-Duse-ilp64true -S-Dcython-blas-abilp64这对Accelerate最为实用因为它对同时使用 LP64 与 ILP64支持良好。MKL也支持这种混用——其mkl-dynamic-lp64-*共享库中提供了带_64符号后缀的 ILP64 符号但文档特别提醒切勿混链不同的共享库即避免同时链接mkl_rt.so、mkl-dynamic-lp64-*.so与mkl-dynamic-ilp64-*.so。在引入 ILP64 的过渡期这个SciPy 内部用 ILP64、Cython API 保持 LP64的配置很有价值因为下游包可能尚未在其 Cython BLAS/LAPACK 调用中支持 64 位整数。下游 Cython 包如何消费 blas_int文档强调消费cython_blas或cython_lapack接口的下游包理想情况下应在所有调用点直接使用blas_int类型。然而有些包更愿意继续使用int并手动在int与blas_int之间做映射——把这种映射收敛到一个内部包装函数中调用 LAPACK 前把int输入转成blas_int返回后再把blas_int输出转回int比较方便。但文档明确指出代价这样做会把数组尺寸限制在 INT_MAX即使底层 LAPACK 本身启用了 ILP64 也无济于事。官方为此提供了一个可运行的完整示例即仓库中的ilp64_test_package测试包位于 scipy/linalg/tests/_cython_examples/ilp64_test_package。该包的 README 清晰演示了两种适配路径包装器方案通过 Cython 包装层把int强制转换为blas_int其他模块只依赖这个包装层无需改动。其.pxd声明src/ilp64_test_package/_blas_lapack_wrappers.pxd注释指出这模拟了 scikit-learn 与 statsmodels 的既有模式——内部 API 使用int需要适配到 ILP64 构建下 BLAS/LAPACK 期望的 64 位整数。效果是无论 SciPy 内部是 LP64 还是 ILP64对外暴露的线性代数始终是 LP64测试见 tests/test_wrappers.py。直接使用方案不经过中间包装层直接使用 SciPy 的blas_int类型这样下游功能不受INT_MAX对数组尺寸的限制测试见 tests/test_direct.py。test_direct.py 中的test_dnrm2_large_vector是检验 ILP64 是否真正生效的典型用例它构造了一个长度为2**31的向量超过 32 位int上限——当blas_int为 64 位时dnrm2计算结果正确为 1.0而仍为 32 位时结果退化为 0.0直观展示了 ILP64 在大规模计算中的价值。工作中的计划多选项自动择优文档最后列出一项尚未开箱即用的计划能力自动从多个可用的 BLAS 与 LAPACK 候选中按用户给定的优先级顺序进行选择。目前这一功能仍在规划中当前版本仍需用户在-Dblas/-Dlapack中显式指定单一实现对应 meson.options 中blas/lapack均为 string 类型选项这一事实。对于需要同时测试多套后端的用户现阶段建议通过切换PKG_CONFIG_PATH或直接修改构建参数来实现。小结一条命令对应一类场景场景推荐命令开发构建使用纯 Netlib 库spin build -S-Dblasblas -S-Dlapacklapack打包 wheel使用 Acceleratepython -m build -Csetup-args-Dblasaccelerate打包 wheel使用 MKLpython -m build -Csetup-args-Dblasmkl-dynamic-lp64-gomp仅用 BLIS需另配 LAPACK-Dblasblis -Dlapacklapack 实现链接非标准路径独立库手工编写.pc文件 设置PKG_CONFIG_PATH针对 g77 ABI 库强制包装-C-Duse-g77-abitrue启用 ILP64Cython 层保持 LP64-Duse-ilp64true -Dcython-blas-abilp64运行时核对 ABI 配置scipy.show_config()查看blas cython ilp64本文全部命令行与参数均以当前仓库 meson.options 中的实际默认值和构建文档 doc/source/building/blas_lapack.rst 为准。配置环境前请先确认目标 BLAS/LAPACK 已通过pkg-config或 CMake 正确安装并以pkg-config --libs与--cflags验证.pc文件解析无误。赞分享科学计算数据科学高性能计算【免费下载链接】scipySciPy library main repository项目地址https://gitcode.com/gh_mirrors/sc/scipy点击查看免费下载相关推荐NumPy 构建指南BLAS 与 LAPACK 库的自动检测、手动选择与配置调优NumPy 构建指南BLAS 与 LAPACK 库的自动检测、手动选择与配置调优 本文是 NumPy 从源码构建系列指南中的核心章节围绕 doc/sourc科学计算数据分析SciPy 1.18.0 版本全解析BLAS/LAPACK 多 ABI 构建、Whittaker-Henderson 平滑与大规模 Array API 支持SciPy 1.18.0 版本全解析BLAS/LAPACK 多 ABI 构建、Whittaker Henderson 平滑与大规模 Array API 支持科学计算数据科学高性能计算SciPy 低层 LAPACK 接口完全指南scipy.linalg.lapack 的函数查找、类型前缀与 ILP64 实践SciPy 低层 LAPACK 接口完全指南scipy.linalg.lapack 的函数查找、类型前缀与 ILP64 实践 导读 scipy.linalg.科学计算数据科学高性能计算创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表