I'm trying to distribute an opencv binary on different Linux operating systems, but I've failed because of dependency problems. What I'm aiming for is something similar to the opencv-python pip package that doesn't require additional software to be installed.
My questions are as follows:
OpenCV were built statically.
I first had a problem with glibc version incompatibility. An update on the different systems solved the problem.
Then I had a missing libtiff.so error. set(BUILD_TIFF ON) solved the problem.
Then I got an error that libQtWidgets.so was missing. I installed the qtbase5-dev package. However, I don't want users to have to install new software. I tried to build qtbase statically, but it complained that the opengl library was missing. This means that the static library will still require opengl to be installed on the destination machines. Which again is incompatible with my goal.
Even after installing qtbase5-dev, I had another version incompatibility with libavcodec.
Update 1
Looking at cv2.abi3.so
gave more information.
readelf -d cv2.abi3.so
shows
0x000000000000000f (RPATH) Library rpath: [$ORIGIN/../opencv_python.libs]
0x0000000000000001 (NEEDED) Shared library: [libpng16-7379b3c3.so.16.40.0]
0x0000000000000001 (NEEDED) Shared library: [libavcodec-512f0acb.so.59.37.100]
0x0000000000000001 (NEEDED) Shared library: [libavformat-3ff1be5b.so.59.27.100]
0x0000000000000001 (NEEDED) Shared library: [libavutil-a0a0531e.so.57.28.100]
0x0000000000000001 (NEEDED) Shared library: [libswscale-2c3c8be7.so.6.7.100]
0x0000000000000001 (NEEDED) Shared library: [libQt5Widgets-e69d94fb.so.5.15.0]
0x0000000000000001 (NEEDED) Shared library: [libQt5Gui-a7aedf18.so.5.15.0]
0x0000000000000001 (NEEDED) Shared library: [libQt5Test-c38a5234.so.5.15.0]
0x0000000000000001 (NEEDED) Shared library: [libQt5Core-39545cc7.so.5.15.0]
0x0000000000000001 (NEEDED) Shared library: [libz.so.1]
0x0000000000000001 (NEEDED) Shared library: [libopenblas-r0-f650aae0.3.3.so]
0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0]
0x0000000000000001 (NEEDED) Shared library: [librt.so.1]
0x0000000000000001 (NEEDED) Shared library: [libdl.so.2]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x0000000000000001 (NEEDED) Shared library: [ld-linux-x86-64.so.2]
Some of the dependencies names have been rewritten and shipped with the package in the opencv_python.libs
directory.
I intend to do the same.
The renaming process seems to be part of the packaging process. Numpy has similiar renamings, making me think that the renaming process is outside python-opencv
I am still looking for that renaming process
I found a solution.
opencv-python uses auditwheel to relabel cross-distribution Linux wheels.
There is a workaround to relabel any shared libraries.
If maximum portability is needed, use some of the manylinux images as a build hosts. I have used the image opencv-python-manylinux2014-x86-64.
python -m pip install build auditwheel
Execute the follwing pyton script
from os.path import join, dirname, abspath
import json
from auditwheel import policy
def patch_whitelisted_libs():
policies = None
with open(join(dirname(abspath(policy.__file__)), "manylinux-policy.json")) as f:
policies = json.load(f)
lib_whitelist = [
"libxcb.so.1",
]
lib_blacklist = []
changed = False
for p in policies:
for lib in lib_whitelist:
if not (lib in p["lib_whitelist"]):
p["lib_whitelist"].append(lib)
changed = True
for lib in lib_blacklist:
if lib in p["lib_whitelist"]:
p["lib_whitelist"].remove(lib)
changed = True
if changed:
with open(join(dirname(abspath(policy.__file__)), "manylinux-policy.json"), "w") as f:
f.write(json.dumps(policies))
if __name__ == '__main__':
patch_whitelisted_libs()
from setuptools import setup, Extension, find_packages
ext_module = Extension('package_name', sources = [], libraries = [])
setup(
name='package_name',
version = '0.0.0',
packages = ['package_name'],
package_dir = {'package_name': '/path/to/shared_objects/directory'},
package_data = {'package_name': ['opencv_custom.so', 'qt/plugins/platforms/libqxcb.so']},
ext_modules = [ext_module],
)
[build-system]
requires = [
"setuptools>=58"
]
build-backend = "setuptools.build_meta"
python -m build --wheel
python -m auditwheel repair dist/<generated built wheel>
unzip -o -d relabelled dist/<generated built wheel> 'package_name/*' 'package_name.libs/*'
auditwhell expects you to keep the tree layout extracted. If it is not the case, change the rpath of every shared object defined by package_data in the setup.py file with
patchelf --force-rpath --set-rpath '$ORIGIN/<you tree layout>' <your shared object>
QT may complain about not being able to load a plugin. I solved it by setting an environment variable
QT_QPA_PLATFORM_PLUGIN_PATH=/path/to/the/distributed/plugins
QT may complain about not founding fonts. I solved it by setting an environment variable
QT_QPA_FONTDIR=/path/to/the/distributed/fonts/dejavu