I am currently trying to embed Python in my C++ application to give the user advanced scripting possibilities.
My program is working great on Windows so far (it is fully working), and now I'm trying to do the same on GNU/Linux (Debian 7 for now) but this is giving me much more trouble than I expected.
First, I download the python.tar.gz and compile it from source with enable-shared option to get the fPIC option:
./configure --enable-shared --prefix=/opt/python
make && make altinstall
Then, I install numpy thanks to pip : python3.4 -m pip install numpy. Easy.
Last, I copy the installation to another location (yes, it should be deployed anywhere), in my home directory to be precise, and name it python_install. This copy seems to give me much pain.
On the code side, I call Py_Initialize which is working good. Here is what I have done so far :
#include "Python.h"
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include "numpy/arrayobject.h"
#include <iostream>
int InitNumpy()
{
import_array();
}
int main()
{
std::string python_home = "/home/xxxx/dev/test-python/python_install";
setenv("PYTHONHOME", python_home.c_str(),1 );
Py_Initialize();
std::cout << "Importing Numpy... ";
int cr = InitNumpy();
std::cout << cr << std::endl;
return 0;
}
ImportError: numpy.core.multiarray failed to import
I think the error is pretty clear, Python can't find any libraries including numpy. But I have tried everything from setting PYTHONPATH to playing with -Wl,-rpath to set additional directories.... even PySys_SetPath... What is working on Windows is failing here on Linux.
Any ideas would be welcome ! Thanks.
EDIT : Here is the makefile I used (corrected):
CC=g++
CFLAGS= -Ipython_install/include/python3.4m -Ipython_install/lib/python3.4/site-packages/numpy/core/include -Wno-unused-result -DNDEBUG -g -fwrapv -O3 -Wall
#Wrong
#LDFLAGS= -Lpython_install/lib/python3.4/config-3.4m -lpython3.4m -lpthread -ldl -lutil -lm -Xlinker -export-dynamic -Wl,-rpath,\$${ORIGIN}/python_install/lib
#Right
LDFLAGS= -Lpython_install/lib/ -lpython3.4m -lpthread -ldl -lutil -lm -Xlinker -export-dynamic -Wl,-rpath,\$${ORIGIN}/python_install/lib
EXEC=test-python
all: $(EXEC)
test-python: test-python.o
$(CC) -o $@ $^ $(LDFLAGS)
%.o: %.cpp
$(CC) -o $@ -c $< $(CFLAGS)
.PHONY: clean mrproper
clean:
rm -rf *.o
mrproper: clean
rm -rf $(EXEC)
Options are coming directly from the python3.4m-config executable...
2 Answers 2
The short answer is : don't link statically on Python. All Python modules link dynamically on libpython3.4.so, so the C++ program has to do the same. To sum up Python embedding :
- Link dynamically on Python (cf corrected Makefile). Use rpath to locate the python .so.
- In the C++ code, set
PYTHONHOMEenvironment variable to the Python installation or usePy_SetPythonHome()function. - Call
Py_Initialize(); If you want to import custom module, add the module path to Python path.
PyObject *sys = PyImport_ImportModule("sys"); PyObject *path = PyObject_GetAttrString(sys, "path"); PyList_Append(path, PyUnicode_FromString(sys_path.toUtf8().data()));
2 Comments
PYTHONHOME in the C++ code?Py_SetPythonHome do the same and should be used. cf docs.python.org/3.6/c-api/init.html You say "python can't find any libraries", have you tried starting python and importing them? If it's an issue with importing directly in python you are going to have to recheck PYTHOPATH is correct, or perhaps your installed files weren't installed with permission settings to execute. (I've had that happen twice).
Also, have you checked out the tips for compiling on unix like systems from the manual?.
It is not necessarily trivial to find the right flags to pass to your compiler (and linker) in order to embed the Python interpreter into your application, particularly because Python needs to load library modules implemented as C dynamic extensions (.so files) linked against it.
To find out the required compiler and linker flags, you can execute the pythonX.Y-config script which is generated as part of the installation process (a python3-config script may also be available)
How do you compile your code?
EDIT
I've tried my best to reproduce your error but can't do it on my machine. The farthest I got is that I think that your analysis of the error is wrong.
I think the error is pretty clear, Python can't find any libraries including numpy.
The reason behind having an import_array() is to check if there's a numpy and if the numpy version you have matches the installed version of python. In the source it's defined as a macro (i.e. for np for py2):
#if PY_VERSION_HEX >= 0x03000000
#define NUMPY_IMPORT_ARRAY_RETVAL NULL
#else
#define NUMPY_IMPORT_ARRAY_RETVAL
#endif
#define import_array() {if (_import_array() < 0) {PyErr_Print();
PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to
import"); return NUMPY_IMPORT_ARRAY_RETVAL; } }
Since that's the error you see, I've reason to suspect that your pip installed the "wrong" numpy for your python version. But then again based on your makefile there is a numpy inside your python3.4 folders, if it hadn't it would throw an error No such file or directory. Additionally you say you even had to use the LD_LIBRARY_PATH (not recommended btw) to start python with numpy, that just means that numpy really is not properly pointed to by any path that is currently defined for your python, including the site-packages folder you have in your compiled python (which is searched through by default).
I suspect that you have a preexisting python installed by default, and your system wide environment paths are set to it. But that's a really weird statement considering you explicitly link the numpy in python3 folder AND you setenv PYTHONHOME.
I'm sorry I couldn't be of more help, but I can't reproduce the issue without actually doing the python build from scratch (also not currently on debian). Good luck, keep me posted?
6 Comments
Explore related questions
See similar questions with these tags.
PYTHONPATHis not set)?/usr/bin/ld: cannot find -lpython3.4m. Real problem is : I am supposed to deploy my application and my python wrappers in .deb archive via apt-get... So I might force the python installation somewhere. I have to think about it.