Reputation: 61
I'm trying to include a python file in a C++ project compiled using CMake.
First I did this standalone using these two files:
#include <Python.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
setenv("PYTHONPATH", ".", 0);
char hostname[] = "localhost";
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pValue;
Py_Initialize();
pName = PyString_FromString("GetHostname");
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if(pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, "GetHostname");
if (pFunc && PyCallable_Check(pFunc)) {
pArgs = PyTuple_New(1);
pValue = PyString_FromString(hostname);
PyTuple_SetItem(pArgs, 0, pValue);
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pValue != NULL) {
printf("The IP address is %s\n", PyString_AsString(pValue));
Py_DECREF(pValue);
}
else {
Py_DECREF(pFunc);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr, "Call Failed\n");
return 1;
}
}
else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function\n");
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load file\n");
return 1;
}
Py_Finalize();
return 0;
}
And
import socket
def GetHostname(hostname):
addr = socket.gethostbyname(hostname)
return addr
When I compile using
g++ $(python-config --cflags) -o test $(python-config --ldflags) ./test.cpp
from how to link python static library with my c++ program everything works fine.
But this is included in a project compiled using CMake and I must be doing something wrong because after compiling it I get
Traceback (most recent call last):
File "/src/GetHostname.py", line 1, in <module>
import socket
File "/usr/lib64/python2.6/socket.py", line 46, in <module>
import _socket
ImportError: /usr/lib64/python2.6/lib-dynload/_socketmodule.so: undefined symbol: PyExc_ValueError
In CMakeLists.txt I added the lines
find_package( PythonInterp REQUIRED )
find_package( PythonLibs REQUIRED )
include_directories ( ${PYTHON_INCLUDE_DIRS} )
add_library (GetHostname MODULE GetHostname.cc)
target_link_libraries(GetHostname ${PYTHON_LIBRARIES})
CONFIGURE_FILE(${PATH_TO_SOURCE}GetHostname.py ${PATH_TO_BUILD}GetHostname.py COPYONLY)
Based on this thread Python.h: No such file or directory
Everything compiles but the python module fails to load due to the error. Am I not linking the python libraries correctly in CMake?
Any thoughts that can explain why it fails are welcome.
Using Python 2.6
I'm aware of that this can be done in C++ however this is not the only python module that I need to include so rewriting it in C++ is not the answer I'm looking for. Also I know for now the IP address for localhost is known, this is just for testing purposes.
Upvotes: 4
Views: 3138
Reputation: 61
So I finally found the answer myself.
The problem was that when linking in CMake the linkage with python libraries are only loaded locally (RTLD_LOCAL), which means the actual python script isn't linked with the python libraries, only C++.
To fix this just load the python libraries with global symbol resolution the first thing in your C++ code.
dlopen("libpython2.6.so.1.0", RTLD_NOW | RTLD_NOLOAD | RTLD_GLOBAL);
This is a quick and dirty fix in that it is specific to python2.6, you should make this portable by defining the variable in CMake based on the version installed on the machine.
You will have to import dlfcn to use dlopen:
#include <dlfcn.h>
Upvotes: 2