简体   繁体   English

使用CMake Import错误编译嵌入式Python的C ++

[英]Compile C++ with embedded Python using CMake Import error

I'm trying to include a python file in a C++ project compiled using CMake. 我正在尝试在使用CMake编译的C ++项目中包含python文件。

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. 如何链接python静态库与我的c ++程序一切正常。

But this is included in a project compiled using CMake and I must be doing something wrong because after compiling it I get 但这包含在使用CMake编译的项目中,我必须做错了,因为在编译后我得到了

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 在CMakeLists.txt中,我添加了这些行

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 基于这个线程Python.h:没有这样的文件或目录

Everything compiles but the python module fails to load due to the error. 一切都编译但由于错误导致python模块无法加载。 Am I not linking the python libraries correctly in CMake? 我没有在CMake中正确链接python库吗?

Any thoughts that can explain why it fails are welcome. 任何可以解释为什么失败的想法都是受欢迎的。

Using Python 2.6 使用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. 我知道这可以在C ++中完成,但是这不是我需要包含的唯一python模块,所以用C ++重写它不是我正在寻找的答案。 Also I know for now the IP address for localhost is known, this is just for testing purposes. 我现在也知道localhost的IP地址是已知的,这仅用于测试目的。

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++. 问题是当在CMake中链接时,与python库的链接只在本地加载(RTLD_LOCAL),这意味着实际的python脚本不与python库链接,只与C ++链接。

To fix this just load the python libraries with global symbol resolution the first thing in your C++ code. 要解决这个问题,只需在C ++代码中加载具有全局符号解析功能的python库。

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. 这是一个快速而又脏的修复,因为它特定于python2.6,你应该通过在CMake中根据机器上安装的版本定义变量来使其可移植。

You will have to import dlfcn to use dlopen: 您必须导入dlfcn才能使用dlopen:

#include <dlfcn.h>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM