Related post: Compile numpy WITHOUT Intel MKL/BLAS/ATLAS/LAPACK
Recent versions of numpy use meson for build configuration, I can build numpy from source but failed to exclude BLAS/LAPACK/... deps.
Here is what I tried in github workflow:
- name: Build Numpy no BLAS
run: |
curl -L -o numpy.tar.gz https://github.com/numpy/numpy/releases/download/v2.3.4/numpy-2.3.4.tar.gz
tar -xzf numpy.tar.gz
# patch meson.build to explicit skip blas detection
patch numpy-2.3.4/numpy/meson.build build_tools/numpy_disable_blas.diff
uv pip install meson-python cython build
uv run python -m build --wheel --outdir ~/numpycache --config-setting=setup-args=-Dblas=none --config-setting=setup-args=-Dlapack=none ./numpy-2.3.4
I patched meson.build because there is no argument that will disable BLAS/LAPACK detection, it looks like the following after patch:
...
# numpy-2.3.4/numpy/meson.build
# start from line 108
# First try scipy-openblas, and if found don't look for cblas or lapack, we
# know what's inside the scipy-openblas wheels already.
# if blas_name == 'openblas' or blas_name == 'auto'
# blas = dependency('scipy-openblas', method: 'pkg-config', required: false)
# if blas.found()
# blas_name = 'scipy-openblas'
# endif
# endif
# if blas_name == 'auto'
# foreach _name : blas_order
# if _name == 'mkl'
# blas = dependency('mkl',
# modules: ['cblas'] + blas_interface + mkl_opts,
# required: false, # may be required, but we need to emit a custom error message
# version: mkl_version_req,
# )
# # Insert a second try with MKL, because we may be rejecting older versions
# # or missing it because no pkg-config installed. If so, we need to retry
# # with MKL SDL, and drop the version constraint (this always worked).
# if not blas.found() and mkl_may_use_sdl
# blas = dependency('mkl', modules: ['cblas', 'sdl: true'], required: false)
# endif
# else
# if _name == 'flexiblas' and use_ilp64
# _name = 'flexiblas64'
# endif
# blas = dependency(_name, modules: ['cblas'] + blas_interface, required: false)
# endif
# if blas.found()
# break
# endif
# endforeach
# else
# if blas_name == 'mkl'
# blas = dependency('mkl',
# modules: ['cblas'] + blas_interface + mkl_opts,
# required: false,
# version: mkl_version_req,
# )
# # Same deal as above - try again for MKL
# if not blas.found() and mkl_may_use_sdl
# blas = dependency('mkl', modules: ['cblas', 'sdl: true'], required: false)
# endif
# else
# blas = dependency(blas_name, modules: ['cblas'] + blas_interface, required: false)
# endif
# endif
blas = disabler()
have_blas = false # blas.found()
if have_blas
_args_blas = ['-DHAVE_CBLAS'] # note: used for C and C++ via `blas_dep` below
if use_ilp64
_args_blas += ['-DHAVE_BLAS_ILP64']
if 'openblas' in blas.name()
_args_blas += ['-DOPENBLAS_ILP64_NAMING_SCHEME']
endif
endif
if blas_symbol_suffix == 'auto'
if blas_name == 'scipy-openblas' and use_ilp64
blas_symbol_suffix = '64_'
else
blas_symbol_suffix = blas.get_variable('symbol_suffix', default_value: '')
endif
message(f'BLAS symbol suffix: @blas_symbol_suffix@')
endif
if blas_symbol_suffix != ''
_args_blas += ['-DBLAS_SYMBOL_SUFFIX=' + blas_symbol_suffix]
endif
blas_dep = declare_dependency(
dependencies: [blas],
compile_args: _args_blas,
)
else
if allow_noblas
blas_dep = []
else
error('No BLAS library detected! Install one, or use the ' + \
'`allow-noblas` build option (note, this may be up to 100x slower ' + \
'for some linear algebra operations).')
endif
endif
# if 'mkl' in blas.name() or blas.name() == 'accelerate' or blas_name == 'scipy-openblas'
# # For these libraries we know that they contain LAPACK, and it's desirable to
# # use that - no need to run the full detection twice.
# lapack = blas
# else
# if lapack_name == 'auto'
# foreach _name : lapack_order
# lapack = dependency(_name, modules: ['lapack'] + blas_interface, required: false)
# if lapack.found()
# break
# endif
# endforeach
# else
# lapack = dependency(lapack_name, modules: ['lapack'] + blas_interface, required: false)
# endif
# endif
lapack = disabler()
have_lapack = false # lapack.found()
if not have_lapack and not allow_noblas
error('No LAPACK library detected! Install one, or use the ' + \
'`allow-noblas` build option (note, this may be up to 100x slower ' + \
'for some linear algebra operations).')
else
lapack_dep = declare_dependency(dependencies: [lapack, blas_dep])
endif
...
The building log shows BLAS related variables are not set, which is exactly what I expected.
Configuring __config__.py using configuration
..\numpy\meson.build:445: WARNING: The variable(s) 'BLAS_INCLUDEDIR', 'BLAS_LIBDIR', 'BLAS_OPENBLAS_CONFIG', 'BLAS_PCFILEDIR', 'BLAS_TYPE_NAME', 'BLAS_VERSION', 'LAPACK_INCLUDEDIR', 'LAPACK_LIBDIR', 'LAPACK_OPENBLAS_CONFIG', 'LAPACK_PCFILEDIR', 'LAPACK_TYPE_NAME', 'LAPACK_VERSION' in the input file 'numpy\__config__.py.in' are not present in the given configuration data.
Checking for size of "short" : 2
...
Build targets in project: 104
WARNING: Deprecated features used:
* 1.3.0: {'Source file src/umath/svml/linux/avx512/svml_z0_acos_d_la.s in the 'objects' kwarg is not an object.'}
NumPy 2.3.4
User defined options
Native files: /home/runner/work/STDF-Viewer/STDF-Viewer/numpy-2.3.4/.mesonpy-l6ngii4n/meson-python-native-file.ini
b_ndebug : if-release
b_vscrt : md
blas : none
buildtype : release
lapack : none
Found ninja-1.13.1 at /usr/local/bin/ninja
+ /usr/local/bin/ninja
[1/512] Copying file numpy/__init__.pxd
...
However, numpy still manages to detect the BLAS, which might be preinstalled in Github runner:
# numpy.show_config()
"Build Dependencies": {
"blas": {
"name": "scipy-openblas",
"found": true,
"version": "0.3.30",
"detection method": "pkgconfig",
"include directory": "/opt/_internal/cpython-3.13.8/lib/python3.13/site-packages/scipy_openblas64/include",
warnings.warn("Install `pyyaml` for better output", stacklevel=1)
"lib directory": "/opt/_internal/cpython-3.13.8/lib/python3.13/site-packages/scipy_openblas64/lib",
"openblas configuration": "OpenBLAS 0.3.30 USE64BITINT DYNAMIC_ARCH NO_AFFINITY Haswell MAX_THREADS=64",
"pc file directory": "/project/.openblas"
},
"lapack": {
"name": "scipy-openblas",
"found": true,
"version": "0.3.30",
"detection method": "pkgconfig",
"include directory": "/opt/_internal/cpython-3.13.8/lib/python3.13/site-packages/scipy_openblas64/include",
"lib directory": "/opt/_internal/cpython-3.13.8/lib/python3.13/site-packages/scipy_openblas64/lib",
"openblas configuration": "OpenBLAS 0.3.30 USE64BITINT DYNAMIC_ARCH NO_AFFINITY Haswell MAX_THREADS=64",
"pc file directory": "/project/.openblas"
}
},
Is there anything I missed? What is the proper way to disable BLAS detection?
Turns out the uv is behind all this.
uv silently uninstalled the local numpy and installed the numpy from pypi before:
uv run python -c "import numpy as np; print('NumPy version:', np.__version__); np.__config__.show()"
If you are trying to build via uv and numpy is one of the deps in your project, you need to add --no-sync to uv run to prevent the local numpy being uninstalled automatically.
uv pip install meson-python cython build
uv run --no-sync python -m build --wheel --config-setting=setup-args=-Dblas=none --config-setting=setup-args=-Dlapack=none ./numpy-2.3.4
You should see the following config if the local numpy is installed:
# numpy.show_config()
"Build Dependencies": {
"blas": {
"name": "none"
},
"lapack": {
"name": "none"
}
},