无法使用boost.python导入模块

时间:2013-07-16 08:45:08

标签: c++ boost boost-python

我正在尝试使用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只运行一些警告(在某些boost文件中重新定义)。

当我尝试在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)

3 个答案:

答案 0 :(得分:2)

当您使用gcc链接二进制文件时,请注意order is important。将二进制文件传递给链接器的顺序应该是第一个单元(例如您的目标文件)应使用以下单元(其他目标文件或库)解析。在您的示例中,您错误地链接了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

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

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

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

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

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

将报告所有未解析的符号,但仍会链接二进制文件。您还有其他选项on this SO thread警告:这不是您通常想要的。例如libpythonX.Y之类的内容从未明确链接,但它们仍然可以在运行时使用。在实践中,你仍然会得到一堆不值得继续的假未定义引用。最好的方法是修复你的Makefile并确保你的目标代码库之前。

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

gcc $^ ${CLinkFlags} -o $@

在您编译并运行ldd后,您应该会看到现在libboost_python(和python,因为您明确链接它)将与greet.so和装载应该按预期工作。我在当地自己测试过。

根据经验,如果您使用gcc进行了未定义的引用,并且您确信它们应该存在于任何链接代码中,请仔细检查订单。

这是Makefile的完全工作/最小版本,它将根据您的具体情况执行工作(请注意,我们还设置了私有boost库的运行时路径,因此您无需设置{{1} }如其他答案所示 - 见下面的详细信息):

LD_LIBRARY_PATH

通过库本身的setting the runtime 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,如其他答案所示。

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

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

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