How to work out the missing dependencies for a Python package

Posted by Ben Nuttall

When you install a compiled Python wheel, whether it’s from PyPI or piwheels, it will likely depend on some shared libraries, specifically certain .so files (shared object files) in order to be used.

If you’ve ever been in the situation where you’ve installed a library but importing it fails, it’s a pretty unpleasant experience:

The next step for most people is to Google the error message. But that’s a long and slow process that often doesn’t lead to a successful import.

The best way to resolve this issue requires a couple of command line tools: ldd and apt-file.

First, navigate to the location of the package installation. This is usually /usr/local/lib/python3.5/dist-packages/<package>/. Note the package directory will be named after the import line, which may differ from the name of the package as you installed it. For example, you pip install numpy and import numpy but you pip install opencv-python and import cv2.

Run ls in that directory and look for an .so file:

pi@raspberrypi:/usr/local/lib/python3.5/dist-packages/cv2 $ ls
cv2.cpython-35m-arm-linux-gnueabihf.so data __init__.py __pycache__

Run ldd on that file:

ldd cv2.cpython-35m-arm-linux-gnueabihf.so

(tab completion is your friend)

You’ll see a lot of .so files. Those are shared objects the Python library source code refers to. Some of them will be available on your system, and will show the location they can be found:

libpthread.so.0 => /lib/arm-linux-gnueabihf/libpthread.so.0 (0x74fdb000)

Others will show “not found”. These are the ones you need to make available:

libhdf5_serial.so.100 => not found

You can use grep to filter out the found ones:

ldd cv2.cpython-35m-arm-linux-gnueabihf.so | grep "not found"

To find out which apt packages provide this .so, use apt-file. apt-file isn’t installed by default, so install it with apt:

sudo apt install apt-file

You’ll want to update apt-file‘s cache:

sudo apt-file update

Then use apt-file search on the missing .so file:

apt-file search libhdf5_serial.so.100

This will show a list of apt packages (including some duplicates):

libhdf5-100: /usr/lib/arm-linux-gnueabihf/libhdf5_serial.so.100
libhdf5-100: /usr/lib/arm-linux-gnueabihf/libhdf5_serial.so.100.0.1

This indicates that the package libhdf5 will provide the required .so file opencv refers to. So install it:

sudo apt install libhdf5-100

That’s it! Just rinse and repeat. Once you’ve made all the missing shared object files available, you’ll be able to import the module no problem:

Note that some shared objects can be provided by multiple packages. Sometimes it’s obvious which is the lighter option, i.e. libatlas3-base rather than libatlas-base-dev (avoid -dev packages if possible), or libpango-1.0-0 rather than the humongous wolfram-engine. You can see the file size with apt-cache show:

pi@raspberrypi:~ $ apt-file search libpango-1.0.so.0
libpango-1.0-0: /usr/lib/arm-linux-gnueabihf/libpango-1.0.so.0
libpango-1.0-0: /usr/lib/arm-linux-gnueabihf/libpango-1.0.so.0.4000.5
wolfram-engine: /opt/Wolfram/WolframEngine/11.3/SystemFiles/Libraries/Linux-ARM/libpango-1.0.so.0
pi@raspberrypi:~ $ apt show libpango-1.0 | grep Size

Installed-Size: 515 kB
Download-Size: 305 kB
pi@raspberrypi:~ $ apt show wolfram-engine | grep Size

Installed-Size: 829 MB
Download-Size: 306 MB

As you can see, the choice here is an easy one: 300 kB vs 300MB!

We’re planning to add project pages to piwheels.org, which will feature library dependencies so you don’t have to look them up manually. If you were looking for opencv requirements, see our blog post New opencv builds which includes the lists of dependencies for the opencv packages.

Tags: opencv