嵌入在 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", &initCppMod );
initCppMod
是一个创建的函数通过BOOST_PYTHON_MODULE
宏,用于初始化Python模块CppMod
。此时,您的嵌入式python脚本可能会调用import CppMod
,然后作为模块成员访问CppClass。以上是关于嵌入在 C++ 中的 Python的主要内容,如果未能解决你的问题,请参考以下文章