无法使用boost.python导入模块

cannot import module using boost.python

本文关键字:python 导入 模块 boost      更新时间:2023-10-16

我正在尝试使用boost.python构建一个简单的程序。
我有以下代码:

//greet.cpp
#include <iostream>
#include <boost/python.hpp>
void greet()
{
    std::cout << "hello world!" << std::endl;
}
BOOST_PYTHON_MODULE(greet)
{
    using namespace boost::python;
    def("greet", greet);
}

以及以下makefile:

PYTHON_VERSION := 2.7
PYTHON_INC := /usr/include/python$(PYTHON_VERSION)
PYTHON_LIB_LOCATION := /usr/lib/python${PYTHON_VERSION}
PYTHON_LIB_FILE := python${PYTHON_VERSION}
BOOST_INC := ~/boost_1_54_0
BOOST_LIB_LOCATION := /home/elyashiv/boost_1_54_0/stage/lib
BOOST_LIB_FILE := boost_python
CC := gcc
CFLAGS := -c -fPIC
CInc := -I ${BOOST_INC} -I ${PYTHON_INC}
CLinkFlags = -shared -Wl,-soname,$@ -L${BOOST_LIB_LOCATION} -l${BOOST_LIB_FILE} -L${PYTHON_LIB_LOCATION} -l${PYTHON_LIB_FILE}
greet.o: greet.cpp
%.so: %.o
    gcc ${CLinkFlags} -o $@ $^
%.o: %.cpp
    ${CC} ${CFLAGS} ${CInc} $^ 

运行make greet.so时只有几个警告(在某些提升文件中进行了重新定义)。

当我尝试在python中导入模块时,我会得到以下信息:

Python 2.7.3 (default, Apr 10 2013, 05:46:21) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import greet
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: ./greet.so: undefined symbol: _ZNK5boost6python7objects21py_function_impl_base9max_arityEv

我做错了什么?如何解决?

编辑

ldd greet.so:的输出

linux-gate.so.1 =>  (0x001ee000)
libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0x0055d000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x0058e000)
/lib/ld-linux.so.2 (0x003a2000)

请注意,当您使用gcc链接二进制文件时,顺序很重要。将二进制文件传递到链接器的顺序应确保第一个单元(例如,对象文件)应使用以下单元(其他对象文件或库)进行解析。在您的示例中,您错误地链接了greet.so

%.so: %.o
    gcc ${CLinkFlags} -o $@ $^

这将生成这样的编译行:

gcc -shared -Wl,-soname,greet.so -L/usr/lib -lboost_python -L/usr/lib/python2.7 -lpython2.7 -o greet.so greet.o

请注意,依赖于libboost_python.solibpython2.7.so中定义的符号的单元greet.o排在最后,因此,当gcc的链接器到达它时,它无法再解析未定义的符号。不幸的是,这不是一个错误,因为链接器无法知道你是否想要这个(例如,在Python中,libpythonX.Y将在你导入代码之前加载,因此它可能会被跳过-你可以从命令行完全转储该库)。因此,默认情况是忽略所有未定义的符号。

您可以通过设置几个标志来强制检测未定义的符号来改变这种行为:

CLinkFlags += -Wl,--unresolved-symbols=report-all

将所有未解决的符号报告为错误,并:

CLinkFlags += -Wl,--unresolved-symbols=report-all -Wl,--warn-unresolved-symbols

将报告所有未解析的符号,但仍将链接二进制。您在这个SO线程中解释了其他选项请注意:这不是您通常想要的。例如,像libpythonX.Y这样的东西从未显式链接,但它们在运行时仍然可用。在实践中,你仍然会得到一堆不值得去追求的虚假的未定义引用。最好的方法是修复您的Makefile,并确保您的对象代码早于库。

要修复您的示例,只需将$^移动到链接的开始,如:

gcc $^ ${CLinkFlags} -o $@

在编译并运行ldd之后,您应该看到现在libboost_python(以及python,因为您显式地链接它)将与greet.so链接,并且加载应该如您所期望的那样工作。我自己在当地测试过。

根据经验,如果您对gcc有未定义的引用,并且您确信它们应该出现在任何链接的代码中,请仔细检查顺序。

以下是Makefile的一个完整工作/最小版本,它将为您的特定案例完成工作(请注意,我们还设置了您的私有boost库的运行时路径,因此您不需要像其他答案所示那样设置LD_LIBRARY_PATH-请参阅下面的详细信息):

PYTHON_VERSION := 2.7
PYTHON_INC := /usr/include/python$(PYTHON_VERSION)
BOOST_INC := /home/elyashiv/boost_1_54_0
BOOST_LIB_LOCATION := /home/elyashiv/boost_1_54_0/stage/lib
BOOST_LIB_FILE := boost_python
CC := gcc
CFLAGS := -c -fPIC
CInc := -I${BOOST_INC} -I${PYTHON_INC}
CLinkFlags = -shared -Wl,-soname,$@ -Wl,-rpath,${BOOST_LIB_LOCATION} -L${BOOST_LIB_LOCATION} -l${BOOST_LIB_FILE}
greet.so: greet.o
%.so: %.o
  gcc $^ ${CLinkFlags} -o $@
%.o: %.cpp
  ${CC} ${CFLAGS} ${CInc} $^

通过在库本身上设置运行时路径,运行时链接器会在尝试LD_LIBRARY_PATH之前先自动查找。如果您决定不这样做,则必须设置环境变量LD_LIBRARY_PATH,如其他答案所示。

Boost python需要Boost python so文件。当您以各种方式运行python时,您可以将其添加到您的路径中。我正在使用

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH:../ThirdParty/boost_1_52_0/lib/linux64/

试试这些命令。这些对我有用。

g++ -c -I/usr/include/python2.7 -fPIC hello.cpp -o hello.o 
g++ -shared -Wl,-soname,"hello.so" -L/usr/local/lib hello.o -lboost_python -fPIC -o hello.so