Python/C++ Extension, Undefined symbol error when linking a library - python

I made a project that has glfw as a library, my directory looks like this:
main_dir
|--include
|--|--glfw_binder.h
|--src
|--|--glfw_binder.cpp
|--lib
|--|--glfw
|--|--|--src
|--|--|--|--libglfw.so
|--|--|--|--libglfw.so.3
|--|--|--|--libglfw.so.3.3
|--|--|--|--...
|--|--|--include
|--|--|-- ...
|--main.cpp
|--setup.py
|--test.py
I've installed glfw from its website and simply extracted it to lib/ directory. Then I ran cmake -G "Unix Makefiles" followed by make to build it.
When I try to run it as pure C++ with this cmake file it runs just fine, it displays the glfw window:
cmake_minimum_required(VERSION 3.0)
project(Test)
add_subdirectory(lib/glfw)
find_package(PythonLibs REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_executable(Test main.cpp src/glfw_binder.cpp)
target_link_libraries(Test PRIVATE
${PYTHON_LIBRARIES}
glfw
)
And here is what my setup.py looks like:
from setuptools import setup, Extension, find_packages
module1 = Extension('test',
sources = ['main.cpp', 'src/glfw_binder.cpp'],
include_dirs=["include", "lib/glfw/include"],
library_dirs=["lib/glfw"],
libraries=["lib/glfw"],
extra_link_args=["lib/glfw"]
)
setup (name = 'python_test',
version = '1.0',
description = 'This is a demo package',
packages=find_packages("glfw"),
ext_modules = [module1]
)
Then I run python3 setup.py build followed by sudo python3 setup.py install. It creates the so files just fine. Then I run this test code:
import test
test.create_glfw_window()
When I run this script via python3 test.py I got this error:
Traceback (most recent call last):
File "/home/turgut/Desktop/TestDir/Python-Binder-Test/test.py", line 3, in <module>
import test
ImportError: /usr/local/lib/python3.10/dist-packages/python_test-1.0-py3.10-linux-x86_64.egg/test.cpython-310-x86_64-linux-gnu.so: undefined symbol: glfwDestroyWindow
It's not specific to glfwDestroyWindow it says this for all glfw functions. How am I supposed to link this?
Update: I've added these lines:
packages=['glfw'],
package_dir={'glfw': 'lib/glfw'},
#package_data={'glfw': ['lib/glfw/src/*.so']},
package_data={'glfw': ['lib/glfw/src/libglfw.so', "lib/glfw/src/libglfw.so.3", "lib/glfw/src/libglfw.so.3.3"]},
Now it gives me the following error:
ImportError: libglfw.so.3: cannot open shared object file: No such file or directory
Even though I've specified all the .so files together. I don't think this is the way to go but I thought it's worth mentioning.
Better update:
I've removed the above update and added these two lines to my extension:
include_dirs=["include", "lib/glfw/include"],
#extra_link_args=[ "-lm", "-lGL", "-lGLU", "-lglfw"],
library_dirs=["lib/glfw"],
libraries=['glfw']
and now I'm getting this error which I think is closer to what I'm looking for:
/usr/bin/ld: cannot find -lglfw: No such file or directory
collect2: error: ld returned 1 exit status
error: command '/usr/bin/x86_64-linux-gnu-g++' failed with exit code 1

For anyone facing a similar issue, you need to specify runtime_library_dirs so the setup.py file looks like this:
from setuptools import setup, Extension, find_packages
module1 = Extension('nerveblox',
sources = ['main.cpp', 'src/nerveblox_VM.cpp'],
include_dirs=["include", "lib/glfw/include"],
#extra_link_args=[ "-lm", "-lGL", "-lGLU", "-lglfw"],
library_dirs=["lib/glfw/src"],
libraries=['glfw', 'GL'],
runtime_library_dirs=['lib/glfw/src']
)
setup (
name = 'Nerveblox_python_test',
version = '1.0',
description = 'This is a demo package',
ext_modules = [module1],
install_requires=[
'importlib-metadata; python_version == "3.8"',
],
)

Related

ImportError When Using cx_Freeze On a Script The Includes ffpyplayer

I successfully froze a Python 3.6 script with cx_Freeze v5.1.1. Then I added a new capability to the script by adding MediaPlayer from the ffpyplayer package and the script works perfectly. But when I freeze the new script, I receive an error "from ffpyplayer.player import MediaPlayer ImportError: DLL load failed: The specified module could not be found."
The import statement in my application script is
from ffpyplayer.player import MediaPlayer
From other posts, I have tried adding both ffpyplayer and ffpyplayer.player to the packages statement in the cx_Freeze setup.py script (in separate attempts) to fix the problem. I also tried adding player.cp36-win_amd64.pyd to the include statement in setup.py, but I still got the same error message.
cx_Freeze copied all ffpyplayer files from site-packages into the exe.win-amd64-3.6\lib\ffpyplayer except the __pycache__ folder containing __init__.cpython-36.pyc. However, manually adding this folder to exe.win-amd64-3.6\lib\ffpyplayer\ and to exe.win-amd64-3.6\lib\ffpyplayer\player\did not fix the issue (same error message).
Here is a minimal version of the setup.py file that cx_Freeze uses:
from cx_Freeze import setup, Executable
d = "C:\\Users\\Slalo_000\\Dropbox\\Python36Scripts\\AddtoBuild\\"
exe=Executable(script="VSWv300.py", base = "Win32GUI", icon = d + "VSWiconLarge.ico")
includes=[]
excludes=[]
packages=["numpy", "cv2", "ffpyplayer"]
setup(
version = "2.0.0.0",
description = "appName",
author = "me",
author_email = "",
name = "appName",
options ={'build_exe'{'excludes':excludes,'packages':packages,'include_files':includes}},
executables = [exe]
)
EDIT: The full error message traceback is:
File “C:\Users\slalo_000\AppData\Local\Programs\Python\Python36\lib\site-packages\cx_Freeze\initscripts\__startup__.py”, line 14, in run module.run()
File “C:\Users\slalo_000\AppData\Local\Programs\Python\Python36\lib\site-packages\cx_Freeze\initscripts\Console.py”, line 26, in run exec(code, m.__dict__
File “VSWv300.py”, line 20, in <module>
File “C:\Users\slalo_000\AppData\Local\Programs\Python\Python36\lib\site-packages\ffpyplayer\player\__init__.py”, line 10, in <module> from ffpyplayer.player.player import MediaPlayer
ImportError:DLL load failed: The specified module could not be found.
Any suggestions?

sphinx python with boost-python library not found

I'm trying to use sphinx to generate documentation for a package that I wrote. Everything was working great until I added some code that used another package I wrote that wraps some boost-python modules.
Now when I run make html I get this (edited for clarity):
$ make html
sphinx-build -b html -d build/doctrees source build/html
Running Sphinx v1.3.1
loading pickled environment... done
building [mo]: targets for 0 po files that are out of date
building [html]: targets for 0 source files that are out of date
updating environment: 0 added, 1 changed, 0 removed
reading sources... [100%] my_project
/path/to/my_project/my_project/docs/source/my_project.rst:19: WARNING: autodoc: failed to import module u'my_project.my_module'; the following exception was raised:
Traceback (most recent call last):
File "/Users/harding/anaconda/lib/python2.7/site-packages/Sphinx-1.3.1-py2.7.egg/sphinx/ext/autodoc.py", line 385, in import_object
__import__(self.modname)
File "/path/to/my_project/__init__.py", line 12, in <module>
from . import module_that_uses_boost_python_classes
File "/path/to/module_that_uses_boost_python_classes.py", line 10, in <module>
import package_that_wraps_boost_python_classes
File "/path/to/package_that_wraps_boost_python_classes/__init__.py", line 21, in <module>
from native_boost_python_module import *
ImportError: dlopen(/path/to/native_boost_python_module.so, 2): Library not loaded: cpp_library.dylib
Referenced from: /path/to/native_boost_python_module.so
Reason: image not found
The problem is that when sphinx trys to import my module, it fails to load the linked c++ library from my boost-python related package. That package is installed via pip and it loads fine in all other situations.
I manually specified the full path to all the c++ libraries with install_name_tool -change and then sphinx works fine.
My question is this: how can I get sphinx to import my boost-python package without manually editing the c++ libraries manually with install_name_tool?
I have DYLD_LIBRARY_PATH set to include the directory that contains all the c++ libraries.
I'm on MacOS Sierra

Cython Compilation Error: dynamic module does not define module export function

I am building a package in Cython. I am using the following as the structure for setup.py:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
import numpy
import scipy
extensions = [
Extension("xxxxx",["xxxx/xxxxx.pyx"],
include_dirs=[numpy.get_include(),"."]),
Extension("nnls",["xxxxx/xxxxx.pyx"],
include_dirs=[numpy.get_include(),"."]),
]
setup(
name='xxxxxx',
version='0.0.0',
description='''********''',
url='xxxxxxx',
author='xxxxx',
author_email='xxxxx',
packages=[
'xxxxx',
],
install_requires=[
'cython',
'numpy',
'scipy',
],
ext_modules=cythonize(extensions),
)
However, I am getting an error upon installation in Python 3. It is working in Python 2 however, it is not compiling in Python 3 having the following error:
dynamic module does not define module export function
How can I solve this problem? Is the structure of the setup.py the reason why this is not compiling?
You need to call setup.py with Python 3 (python3 setup.py build_ext, maybe --inplace). It's because Python 3 defines a different name for the init function called when the module starts, and so you need to build it using Python 3 to ensure the correct name is generated.
See dynamic module does not define init function (PyInit_fuzzy) and How to specify Python 3 source in Cython's setup.py? for slightly more detail (it's bordering on a duplicate of these questions, but isn't quite in my view)
I experienced this and found that I had to use the same name of .pyx as the module name, e.g.
makefile:
# (default)
# INSTALL_DIR:=/usr/lib/python3.6/site-packages
# (my venv)
INSTALL_DIR:=/home/<username>/python3_venv/lib/python3.6/site-packages
all:
sudo python3 setup_myproj.py install --install-lib ${INSTALL_DIR}
setup_myproj.py
from distutils.core import setup, Extension
from Cython.Build import cythonize
ext = Extension("myproj",
sources=["myproj.pyx", "myCppProjFacade.cpp"],
<etc>
language="c++"
)
setup(name="myproj",
version="0.0.1",
ext_modules=cythonize(ext))
client module, run after installing to venv
import myproj as myCppProjWrapper
...
I also found that if the "myproj" names are different, under <python-lib-dir>/<python-vers>/site-packages the .so and .egg-info names are different and the client fails to load it.
In addition I found that the client's environment does not need to have the cython package installed.
I had the same error for torchvision. FIxed it by downgrading the installation versions:
pip install torch==1.2.0+cu92 torchvision==0.4.0+cu92 -f https://download.pytorch.org/whl/torch_stable.html

Cython ImportError

Following file as helloworld.pyx:
print("Hello World")
Following file as setup.py:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [Extension("helloworld",["helloworld.pyx"]
setup(
name = 'HW',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)
After i use python setup.py build_ext --inplace i got my *.so file
So, i rename the *.so to hw.so, for getting a shorter import name.
But if i sart python and type in: import hw i got this error:
ImportError: dynamic module does not define init function (PyInit_hw)
I was doing the exact thing bout 3 hours ago and all was ok. But i tryed something out from this side: http://sourceforge.net/p/ubertooth/mailman/message/31699880/
I tryed the following:
cmake -DPYTHON_EXECUTABLE=$(which python2) \
-DPYTHON_INCLUDE_DIR=$(echo /usr/include/python2*) \
-DPYTHON_LIBRARY=$(echo /usr/lib/libpython2.*.so) \
because i wanted to fix something. I replaced all "2" with "3" cause i am working with python3.4
After i made this i always got the error above. Did i destroy any path? How can i undo it? Thank u for your help
When looking at the Python 3 documentation on "Extending Python with C or C++" we see that
The initialization function must be named PyInit_name(), where name is the name of the module, and should be the only non-static item defined in the module file.
(https://docs.python.org/3/extending/extending.html#the-module-s-method-table-and-initialization-function)
This means that we cannot just change the file name of the module without changing the init function. We have to compile the module with the final name in the first place. Renaming the .so file after compiling it will not work.

Python setuptools develop command: "No module named..."

I'm trying to install a python package I've developed using the develop command of setuptools.
[sidenote: There is a bewilderingly vast quantity of information about this on the web (distutils, distutils2, setuptools, distribute). setuptools and develop are, as far as I can tell, the most modern/best practice way to use a piece of code that's in development. Perhaps I am wrong.]
Here's what I did:
(1) I placed an empty __init__.py in the directory with my Python code.
(2) I made a setup.py:
from setuptools import setup, find_packages
setup(name = "STEM_pytools",
version = "0.1",
packages = find_packages(),
author = "Timothy W. Hilton",
author_email = "my#email.address",
description = "visualization and data pre-/post-processing tools for STEM",
license = "",
keywords = "STEM",
url = "")
(3) I ran
python setup.py develop
That seemed to proceed without problems.
However, when I try to use the package, I get:
>>> import STEM_pytools
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named STEM_pytools
The same thing happens with the install command: it's output looks ok, then "No module named STEM_pytools". I'm tearing my hair out. Any suggestions appreciated!
I solved the problem, although I still don't entirely understand why it works now and did not work before. It seems my setup.py and the directory structure of my project were not interacting successfully.
This is the directory structure that worked with my setup.py:
STEMpytools/
setup.py
stem_pytools/
__init__.py
source1.py
source2.py
...
sourceN.py
This directory structure did not work, at least when paired with my setup.py:
STEMpytools/
setup.py
__init__.py
source1.py
source2.py
...
sourceN.py
This explanation helped me a lot: http://bashelton.com/2009/04/setuptools-tutorial/
Now, from the python interpreter, these both work:
import stem_pytools
import stem_pytools.source1
Experimenting on my system suggests it is necessary to place __init__.py and the package source code in a subdirectory one level below the root directory that contains setup.py. I'm not sure from the setuptools and distutils documentation why this is the case.

Categories

Resources