我正在尝试使用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)
答案 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.so
和libpython2.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