嵌入在 C++ 中的 Python

Posted

技术标签:

【中文标题】嵌入在 C++ 中的 Python【英文标题】:Python Embedded in C++ 【发布时间】:2012-12-13 04:18:47 【问题描述】:

所以我有一个 GUI 程序,其中包含大量“东西”。我正在添加一个 python 脚本接口,以便有人可以与这个环境进行有问题的交互。我正在使用boost python。所以我首先要创建一个新模块。为简单起见,现在我的模块只是 hello world...

#include <boost/python.hpp>                                                     

char const* greet()                                                            
   return "hello, world" ;                                                      
                                                                               

BOOST_PYTHON_MODULE(cerrnimapi)                                                
  boost::python::def( "greet", greet ) ;                                        
  

在我的系统中,我有一个看起来像这样的类...

Controller::Controller( )          
  Py_Initialize( ) ;                                                            

  main_module = boost::python::import( "__main__" ) ;                           
  main_namespace = main_module.attr( "__dict__" ) ;                             
                                                                                                                                                     

void Controller::execute_script( std::string filename )                        
  try                                                                          
    boost::python::api::object ignored =                                        
      boost::python::exec_file( filename.c_str(), main_namespace ) ;            
   catch( boost::python::error_already_set const & )                          
    if (PyErr_ExceptionMatches(PyExc_ZeroDivisionError))                       
     else                                                                     
        PyErr_Print();                                                          
                                                                               
                                                                               

现在,当我在 GUI 中执行脚本时,出现错误...

Traceback (most recent call last):
  File "/home/mokon/repository/trunk/python.py", line 1, in <module>
    import cerrnimapi
ImportError: No module named cerrnimapi

所以我当然是在构建错误的东西。我的构建系统使用自动工具,所以这里有一些与此相关的构建系统......

在configure.ac中:

AM_PATH_PYTHON                                                                  
AC_ARG_VAR([PYTHON_INCLUDE], [Include flags for python, bypassing python-config])
AC_ARG_VAR([PYTHON_CONFIG], [Path to python-config])                            
AS_IF([test -z "$PYTHON_INCLUDE"], [                                            
  AS_IF([test -z "$PYTHON_CONFIG"], [                                           
    AC_PATH_PROGS([PYTHON_CONFIG],                                              
                  [python$PYTHON_VERSION-config python-config],                 
                  [no],                                                         
                  [`dirname $PYTHON`])                                          
    AS_IF([test "$PYTHON_CONFIG" = no], [AC_MSG_ERROR([cannot find python-config for $PYTHON.])])
  ])                                                                            
  AC_MSG_CHECKING([python include flags])                                       
  PYTHON_INCLUDE=`$PYTHON_CONFIG --includes`                                    
  AC_MSG_RESULT([$PYTHON_INCLUDE])                                              
])                                                                              

AC_ARG_VAR([PYTHON_LD], [Linker flags for python, bypassing python-config])     
AS_IF([test -z "$PYTHON_LD"], [                                                 
  AS_IF([test -z "$PYTHON_CONFIG"], [                                           
    AC_PATH_PROGS([PYTHON_CONFIG],                                              
                  [python$PYTHON_VERSION-config python-config],                 
                  [no],                                                         
                  [`dirname $PYTHON`])                                          
    AS_IF([test "$PYTHON_CONFIG" = no], [AC_MSG_ERROR([cannot find python-config for $PYTHON.])])
  ])                                                                            
  AC_MSG_CHECKING([python linker flags])                                        
  PYTHON_LD=`$PYTHON_CONFIG --ldflags`                                          
  AC_MSG_RESULT([$PYTHON_LD])                                                   
]) 

在我的 obj/ 目录 Makefile.am...

pyexec_LTLIBRARIES = cerrnimapi.la                                              
cerrnimapi_la_SOURCES = $SRC_DIR/lib/PythonAPI.cpp                            
cerrnimapi_la_LDFLAGS = -avoid-version -module $(PYTHON_LD)                     
cerrnimapi_la_CXXFLAGS = $(PYTHON_INCLUDE)  

我的 makefile 与我的主程序一起在 obj 文件夹中构建共享库及其。这没有帮助。我还做了一个 make install 来在 python 文件夹中安装 cerrnimapi lib。这没有帮助。

我也尝试将 PythonAPI.cpp 添加到我的主程序 SOURCES 但无济于事。

有什么想法吗?让我知道哪些附加信息会有所帮助。

【问题讨论】:

我越想越觉得我做错了。难道我不应该能够将我的 lib 编译到我的 c++ 程序中,而嵌入式 python interp 将能够看到这些符号吗? 您的构建过程是否生成了一个名为“cerrnimapi.so”的共享库?这就是导入所要寻找的。至于库中的静态链接,这不是直接鼓励的,但如果你想破解它,这里有信息:mdqinc.com/blog/2011/08/…。 【参考方案1】:

需要检查的一些事项:

在您的 .so 文件(可能位于 .libs)上运行 nm 以确保您的模块初始化函数已导出。 让您的程序打印出sys.path 的值(使用PyRun_SimpleString),看看它期望您的模块出现在哪里。如果您只为解释器定义模块,您可能不想将它们安装在 $pyexecdir 中。 阅读Extending Embedded Python 文章。您根本不需要构建动态库,除非您正在尝试插件架构。

关于风格的一点:您应该尝试在$PYTHON_INCLUDE$PYTHON_LD 的测试之外找到$PYTHON_CONFIG,这样您就不会两次执行AC_PATH_PROGS

AM_PATH_PYTHON                                                                  
AC_ARG_VAR([PYTHON_CONFIG], [Path to python-config])                            
AS_IF([test -z "$PYTHON_CONFIG"], [                                           
  AC_PATH_PROGS([PYTHON_CONFIG],                                              
                [python$PYTHON_VERSION-config python-config],                 
                [no],                                                         
                [`dirname $PYTHON`])                                          
])                                                                            

AC_ARG_VAR([PYTHON_INCLUDE], [Include flags for python, bypassing python-config])
AS_IF([test -z "$PYTHON_INCLUDE"], [                                            
  AC_MSG_CHECKING([python include flags])                                       
  AS_IF([test "$PYTHON_CONFIG" = no], [AC_MSG_ERROR([cannot find python-config for $PYTHON.])])
  PYTHON_INCLUDE=`$PYTHON_CONFIG --includes`                                    
  AC_MSG_RESULT([$PYTHON_INCLUDE])                                              
])                                                                              

AC_ARG_VAR([PYTHON_LD], [Linker flags for python, bypassing python-config])     
AS_IF([test -z "$PYTHON_LD"], [                                                 
  AC_MSG_CHECKING([python linker flags])                                        
  AS_IF([test "$PYTHON_CONFIG" = no], [AC_MSG_ERROR([cannot find python-config for $PYTHON.])])
  PYTHON_LD=`$PYTHON_CONFIG --ldflags`                                          
  AC_MSG_RESULT([$PYTHON_LD])                                                   
])

【讨论】:

所以我正在创建的 python api 需要在我的主应用程序中访问模型,因为它需要与之交互。例如,我有一个简单的命令可以关闭该系统。为此,它获取一个全局对象并实质上调用其关闭方法。问题当然是从 .so 动态链接文件中调用它,因此全局为空。我需要它从主程序访问。我也没看到你指的那篇文章的哪个地方 任何帮助将不胜感激。我觉得这是非常基本的事情......我已经有一段时间没有担心这个了...... 我链接到您的手册部分显示了如何在主程序中定义模块。您根本不需要 .so。要回调你的主程序,看起来你必须传递函数指针:***.com/questions/3454909/…。不要那样做,会弄乱的。 好的,是的,似乎 boost 并没有在那个例子中做所有事情。如果我像在那个例子中那样做,该程序可以正常工作,但我正在使用 boost.. 例如"import emb print "Number of arguments", emb.numargs()" 这会导致一些错误 我想我在这里找到了答案:wiki.python.org/moin/boost.python/EmbeddingPython -> "现在,在main() 内部和调用Py_Initialize() 之前,我们要调用PyImport_AppendInittab( "CppMod", &amp;initCppMod ); initCppMod 是一个创建的函数通过BOOST_PYTHON_MODULE宏,用于初始化Python模块CppMod。此时,您的嵌入式python脚本可能会调用import CppMod,然后作为模块成员访问CppClass。

以上是关于嵌入在 C++ 中的 Python的主要内容,如果未能解决你的问题,请参考以下文章

嵌入在 C++ 中的 Python

嵌入式开发:C++在深度嵌入式系统中的应用

嵌入式 Linux 中的 C 与 C++

如何中断嵌入在 C++ 应用程序中的 python 解释器

c++ 中的嵌入式 python 代码 - 导入 python 库时出错

在 C++ 中嵌入 Python:解释器在执行过程中的持久性