1

我正在尝试使用 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} $^ 

runningmake 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)
4

3 回答 3

3

请注意,当您使用 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

注意 unit 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

将报告所有未解析的符号,但仍将链接二进制文件。您在此 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按照其他答案的指示设置环境变量。

于 2013-07-17T10:28:15.527 回答
1

Boost python 需要 boost pythonso文件。当你以多种方式运行 python 时,你可以将它添加到你的路径中。我在用

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH:../ThirdParty/boost_1_52_0/lib/linux64/
于 2013-07-16T08:48:45.047 回答
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
于 2013-07-17T11:29:03.820 回答