使用 Boost::Python 从嵌入式 python 中提取数据
Posted
技术标签:
【中文标题】使用 Boost::Python 从嵌入式 python 中提取数据【英文标题】:Extracting data from embedded python using Boost::Python 【发布时间】:2014-08-27 17:20:16 【问题描述】:我正在尝试学习一点 boost::python 知识,但我一直坚持从 python 字符串中提取数据。
目前,我能够干净地编译,但是在执行代码时,我收到了分段错误。我已将 seg-fault 缩小到实际使用 boost::python::extract 的行。
希望得到指导。提前致谢!
为方便起见,我提供了一个github repo:https://github.com/brianbruggeman/boost_python_hello_world/tree/feature/stack_overflow
Cpp 代码(say_hello.cpp):
#include <boost/python.hpp>
#include <iostream>
namespace bp = boost::python;
// Embedding python
int main(int argc, char** argv)
int data = 0;
Py_Initialize();
PyRun_SimpleString("data = 1");
bp::object module(bp::handle<>(bp::borrowed(PyImport_AddModule("__main__"))));
bp::object dictionary = module.attr("__dict__");
bp::object data_obj = dictionary["data"];
// Error: The following line has the segmentation fault...
data = bp::extract<int>(data_obj);
std::cout << "data = " << data << std::endl;
Py_Finalize();
return 0;
我做错了什么?为了完整起见,我使用的是 Mac OS X Mavericks,并且在下面包含了 CMakeLists.txt 文件:
project(hello)
cmake_minimum_required(VERSION 2.8)
FIND_PACKAGE(PythonInterp)
FIND_PACKAGE(PythonLibs)
FIND_PACKAGE(Boost COMPONENTS python)
include_directories($PYTHON_INCLUDE_DIRS $Boost_INCLUD_DIRS)
link_directories($PYTHON_LIBRARY_DIRS $Boost_LIBRARY_DIRS)
add_executable(hello say_hello.cpp)
target_link_libraries(hello
$Boost_LIBRARIES
$PYTHON_LIBRARIES)
Python 是使用 Homebrew 编译和安装的:
brew install python
Boost 是使用 Homebrew 编译和安装的:
brew install boost --with-python
编辑(boost-python 的新安装):
brew install --build-from-source boost-python
【问题讨论】:
【参考方案1】:代码很好。构建过程是问题所在。
Brew 正在针对从 Brew 的 python 包安装的 python 库构建 libboost_python
库:
$ otool -L $(brew list boost | grep "libboost_python.dylib")
/usr/local/Cellar/boost/1.55.0_2/lib/libboost_python.dylib:
/usr/local/lib/libboost_python.dylib (...)
/usr/local/Frameworks/Python.framework/Versions/2.7/Python (...) <-- brew
...
但是,CMake 正在链接 OSX 系统提供的 Python 库:
$ (mkdir build && cd build && cmake ../)
...
-- Found PythonLibs: /usr/lib/libpython2.7.dylib (found version "2.7.5")
...
因此,程序和 Boost.Python 链接到不同的 Python 库,导致未定义的行为。要解决此问题,请修复 FindPythonLibs.cmake
文件或更新 CMakeLists.txt
以明确链接到 brew 提供的 Python 库。
这是一个完整的 CMakeLists.txt
示例,它将 PYTHON_LIBRARIES
变量显式设置为 brew 在我的系统上安装的 Python 库:
project(hello)
cmake_minimum_required(VERSION 2.8)
find_package(PythonLibs)
set(PYTHON_LIBRARIES /usr/local/Frameworks/Python.framework/Versions/2.7/Python)
find_package(Boost COMPONENTS python)
include_directories($PYTHON_INCLUDE_DIRS $Boost_INCLUDE_DIRS)
link_directories($Boost_LIBRARY_DIRS)
add_executable(hello say_hello.cpp)
target_link_libraries(hello
$Boost_LIBRARIES
$PYTHON_LIBRARIES)
及其用法:
$ (mkdir build && cd build && cmake ../ && make)
...
-- Found PythonLibs: /usr/lib/libpython2.7.dylib (found version "2.7.5")
...
Scanning dependencies of target hello
[100%] Building CXX object CMakeFiles/hello.dir/say_hello.cpp.o
Linking CXX executable hello
[100%] Built target hello
$ ./build/hello
data = 1
请注意,PythonLibs 仍会打印它找到的库,但 PYTHON_LIBRARIES
变量已明确设置为适当的库。
还有几点需要注意:
Boost.Python 不支持安全调用Py_Finalize()
。根据Embedding - Getting started 部分:
注意此时千万不能调用
Py_Finalize()
来停止解释器。这可能会在 boost.python 的未来版本中得到修复。
在嵌入时,我经常发现使用 try/catch
块、捕获 boost::python::error_already_set
异常和打印错误很有帮助:
Py_Initialize();
try
// ...
catch (boost::python::error_already_set&)
PyErr_Print();
【讨论】:
感谢您的洞察! (y) 今天,boost-python 应该安装:brew install --build-from-source boost-python以上是关于使用 Boost::Python 从嵌入式 python 中提取数据的主要内容,如果未能解决你的问题,请参考以下文章
如何在 boost::python 嵌入式 python 代码中导入模块?
Boost python,嵌入时从python调用c++函数