Compile numpy without openblas to reduce pack size
Summary
Compiling numpy on Windows by self can save 36 MiB of openblas dependency. Building numpy from source on Windows is not as difficult as imagined.
Preface
I recently needed to package a tool that uses some numpy computations. At first glance with pyinstaller
, there is a huge openblas dependency:
1 |
|
I admire those powerful tools that could do a lot with just a few megabytes in the past. Besides, the performance requirements for numpy in this program are not high. So I tried to remove this dependency. There are many discussions online about packaging and reducing package size, but they only replace mkl with openblas. However, openblas is still quite large.
After searching, this site provides builds without openblas and mkl, but the last update was in 2022, and the version is still 1.22.4, which is a bit old. Since third-party builds already exist, I guessed this might not be too difficult.
Preparation
Compiler
On Windows, just download Microsoft C++ Build Tools
, start it and select Desktop development with C++
. Wait for it to finish and you are good to go. No need to set environment variables as numpy will handle it later.
Source Code
1 | git clone --recurse-submodules https://github.com/numpy/numpy.git |
Disable openblas
In numpy/distutils/
, add a file site.cfg
with the following content:
1 | [openblas] |
Refer to site.cfg.example
in root for complete description.
According to official docs, you can also disable openblas by setting environment variables.
Virtual environment and dependencies
1 | python -m venv .#env |
Later we will run commands in the .#env
virtual environment by default.
Build
For <=1.24.x, you can build with bare msvc like this:
1 | python setup.py build -j 16 |
However, for 1.25+, this will silently fail on Windows by generating compilation commands longer than 32768 lines.
A viable solution is to switch to using cibuildwheel.
Modify pyproject.toml
, find [tool.cibuildwheel]
, and comment out before-build
, before-test
, test-command
by adding #
in front or just delete them. It should look like:
1 | [tool.cibuildwheel] |
The before-build
script is for downloading openblas. The two test steps don’t work for me.
Then build in PowerShell:
1 | $env:CIBW_BUILD="cp311-win_amd64" # cp311 means CPython3.11, change to other versions if needed |
If everything goes well, you should see a whl file generated under wheelhouse:
1 | -rwxrwxrwx 1 root root 6.1M Aug 7 23:37 wheelhouse/numpy-1.25.2-cp310-cp310-win_amd64.whl |
Test
After installing the whl, check debug info:
1 | > python -c "import numpy as np; np.show_config(); print(np.__version__)" |
Very good, no openblas at all. Run tests:
1 | > python runtests.py -v --no-build |
For normal binary installs, the result is:
1 | > python -c "import numpy as np; np.show_config(); print(np.__version__)" |
Packaging
1 | # test.py |
Without openblas install, pyinstaller test.py
gives:
1 | 6.9 MiB [##########] /numpy |
With default install, the result is:
1 | 36.4 MiB [##########] libopenblas64__v0.3.23-246-g3d31191b-gcc_10_3_0.dll |
The difference is about 35 MiB, quite significant. Removing openblas, my tool can fit in a single 15 MiB file. Although it’s still some way from my goal of a few megabytes, this is Python after all, so I’m quite satisfied.
Misc
- The commit I built 1.25.x on is ea677928332c37e8052b4d599bf6ee52cf363cf9. Reset to it if yours is different.
- My Windows version is 22H2 19045.3271
- The pure build takes around 2 minutes on my trashy E5-2678.
- Sizes above are from ncdu output.
Compile numpy without openblas to reduce pack size
https://myuan.fun/Compile-numpy-without-openblas-to-reduce-pack-size/