Compile C++ with embedded Python using CMake Import error

让人想犯罪 __ 提交于 2020-02-03 10:00:12

问题


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.


回答1:


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>


来源:https://stackoverflow.com/questions/17842915/compile-c-with-embedded-python-using-cmake-import-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!