pimoroni / mlx90640-library

Python library for the MLX90640 thermal camera
https://shop.pimoroni.com/products/mlx90640-thermal-camera-breakout
Apache License 2.0
133 stars 84 forks source link

Error in python experimental library: undefined symbol: _Z9get_framev #27

Closed robmarkcole closed 1 year ago

robmarkcole commented 5 years ago

Attempting to use the experimental library, and having run make, I get:

pi@pi-breakout-garden:~/Desktop/Github/mlx90640-library/python/library $ python3 test.py

Traceback (most recent call last):
  File "/home/pi/Desktop/Github/mlx90640-library/python/library/MLX90640.py", line 18, in swig_import_helper
    return importlib.import_module(mname)
  File "/usr/lib/python3.7/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 670, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 583, in module_from_spec
  File "<frozen importlib._bootstrap_external>", line 1043, in create_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
ImportError: ./build/lib.linux-armv7l-2.7/_MLX90640.so: undefined symbol: _Z9get_framev

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test.py", line 6, in <module>
    import MLX90640 as x
  File "/home/pi/Desktop/Github/mlx90640-library/python/library/MLX90640.py", line 21, in <module>
    _MLX90640 = swig_import_helper()
  File "/home/pi/Desktop/Github/mlx90640-library/python/library/MLX90640.py", line 20, in swig_import_helper
    return importlib.import_module('_MLX90640')
  File "/usr/lib/python3.7/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
ImportError: ./build/lib.linux-armv7l-2.7/_MLX90640.so: undefined symbol: _Z9get_framev
Gadgetoid commented 5 years ago

I wonder if this is related to SWIG version. I haven't look at this code for a while, and it was always very experimental, but it definitely used to - sort of - work. I'll check it out.

Gadgetoid commented 5 years ago

Since lbcm2835 hasn't been ported to Pi 4, I must caveat this with- "These steps wont actually work on a Pi 4" - but

sudo apt install swig
swig -python MLX90640.i
python setup.py build
sudo python setup.py install

Should hopefully get you working.

I've pushed the changes this produces up to a branch. It looks like the changes to the SwigMethods definitions are the ones that fix this issue in particular: https://github.com/pimoroni/mlx90640-library/commit/4916859c293416d6af16d39c00dab5e17c1e6320

robmarkcole commented 5 years ago

OK checked out your fix branch and hit the following:

pi@pi-breakout-garden:~/Desktop/Github/mlx90640-library/python/library $ sudo python setup.py install
running install
running bdist_egg
running egg_info
writing MLX90640.egg-info/PKG-INFO
writing top-level names to MLX90640.egg-info/top_level.txt
writing dependency_links to MLX90640.egg-info/dependency_links.txt
reading manifest file 'MLX90640.egg-info/SOURCES.txt'
writing manifest file 'MLX90640.egg-info/SOURCES.txt'
installing library code to build/bdist.linux-armv7l/egg
running install_lib
running build_py
running build_ext
copying build/lib.linux-armv7l-2.7/MLX90640.py -> build/bdist.linux-armv7l/egg
byte-compiling build/bdist.linux-armv7l/egg/MLX90640.py to MLX90640.pyc
creating stub loader for _MLX90640.so
byte-compiling build/bdist.linux-armv7l/egg/_MLX90640.py to _MLX90640.pyc
copying MLX90640.egg-info/PKG-INFO -> build/bdist.linux-armv7l/egg/EGG-INFO
copying MLX90640.egg-info/SOURCES.txt -> build/bdist.linux-armv7l/egg/EGG-INFO
copying MLX90640.egg-info/dependency_links.txt -> build/bdist.linux-armv7l/egg/EGG-INFO
copying MLX90640.egg-info/top_level.txt -> build/bdist.linux-armv7l/egg/EGG-INFO
writing build/bdist.linux-armv7l/egg/EGG-INFO/native_libs.txt
zip_safe flag not set; analyzing archive contents...
MLX90640: module references __file__
Traceback (most recent call last):
  File "setup.py", line 69, in <module>
    cmdclass = {'build_py' : build_py_ext_first, 'sdist' : sdist_ext_first},
  File "/usr/lib/python2.7/dist-packages/setuptools/__init__.py", line 145, in setup
    return distutils.core.setup(**attrs)
  File "/usr/lib/python2.7/distutils/core.py", line 151, in setup
    dist.run_commands()
  File "/usr/lib/python2.7/distutils/dist.py", line 953, in run_commands
    self.run_command(cmd)
  File "/usr/lib/python2.7/distutils/dist.py", line 972, in run_command
    cmd_obj.run()
  File "/usr/lib/python2.7/dist-packages/setuptools/command/install.py", line 67, in run
    self.do_egg_install()
  File "/usr/lib/python2.7/dist-packages/setuptools/command/install.py", line 109, in do_egg_install
    self.run_command('bdist_egg')
  File "/usr/lib/python2.7/distutils/cmd.py", line 326, in run_command
    self.distribution.run_command(command)
  File "/usr/lib/python2.7/distutils/dist.py", line 972, in run_command
    cmd_obj.run()
  File "/usr/lib/python2.7/dist-packages/setuptools/command/bdist_egg.py", line 220, in run
    os.path.join(archive_root, 'EGG-INFO'), self.zip_safe()
  File "/usr/lib/python2.7/dist-packages/setuptools/command/bdist_egg.py", line 273, in zip_safe
    return analyze_egg(self.bdist_dir, self.stubs)
  File "/usr/lib/python2.7/dist-packages/setuptools/command/bdist_egg.py", line 383, in analyze_egg
    safe = scan_module(egg_dir, base, name, stubs) and safe
  File "/usr/lib/python2.7/dist-packages/setuptools/command/bdist_egg.py", line 422, in scan_module
    code = marshal.load(f)
ValueError: bad marshal data (unknown type code)

Btw should I not be using sudo python3 setup.py? Also I am on pi3

21347 commented 5 years ago

Well, I had the same problem. _Z9get_framev was reported missing, but nm told me it was definately there. I found some pointers to library versions and changes in the C-Bindings between Python 2.7 and Python 3.0, so I tried regenerating all necessary files.

Python 2.7 Here is what finally fixed it for me: Makefile and example are for Python2.7 apparently, so I forced make and setup.py to regenerate all wrapper files by removing all autogenerated files from the directory. The result is then something like this:

-rw-r--r-- 1 pi   60 Aug  6 09:51 Makefile
-rw-r--r-- 1 pi  349 Aug  6 09:51 MLX90640.i
-rw-r--r-- 1 pi 3.2K Aug  6 09:51 MLX90640.py
-rw-r--r-- 1 pi 4.3K Aug  6 09:51 mlx90640-python.cpp
-rw-r--r-- 1 pi 2.3K Aug  6 09:51 setup.py
-rw-r--r-- 1 pi  858 Aug  6 09:51 test.py

Additionally, the "normal" way, it would require update-alternatives to recognize python2.7 as default. You can check this with python --version, it should - at the moment - return version 2.7. Also, something like

sudo apt install swig python-dev python-setuptools

should install the prerequisites. Afterwards make will have to regenerate the C wrapper, and the build did succeed. If you run test.py without executing sudo python setup.py install first, you will have to change test.py to point to your Pi's CPU version subdirectory (armv7l for Pi > 0,1, armv6l for me on the Zero)

For Python 3 As far as I know, swig wants -py3 to be specified on the command line to build for Python 3. So, clean again and change the makefile to read

all:
    swig3.0 -py3 -c++ -python MLX90640.i
    python setup.py build

Of course, prerequisites:

sudo apt install python3-dev python3-setuptools

Then, for me, it worked and I could also generate a Python 3.7.3 version of the library...

21347 commented 5 years ago

I put the fixes I made in the previous post with some other improvements to the python bindings into a fork, see https://github.com/21347/mlx90640-library

21347 commented 5 years ago

Hi, well - I just fetched my code to a new machine, and - guess what: _Z9get_framev not found.

I re-checked the setup, and apparently, last time I missed something: swig is told to generate C++ bindings (see https://github.com/pimoroni/mlx90640-library/blob/f4549dc6cc416f8db05a8bfd1d4850aee5e7af75/python/library/Makefile#L2) In mlx90640-python.cpp, however, these functions are declared extern "C".

Last time I tried a lot of stuff, seems I did not clean good enough between tries...

extern "C", as far as I know, will change the symbol names to be "not changed" (as in "get_frame"), as standard C++ exports will look like "_Z9get_framev".

Currently, I simply removed the extern "C" declaration, and it worked.