【问题标题】:cannot import module using boost.python无法使用 boost.python 导入模块
【发布时间】:2013-07-14 08:39:19
【问题描述】:

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

running 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)

【问题讨论】:

  • 如果你在Linux上,你能不能也粘贴ldd greet.so的输出?这是否显示您的 boost_python 库已链接?
  • libboost_python 在哪里?它没有被链接,因此,您缺少符号。确保您的编译按预期工作。
  • @AndréAnjos 正如我所写,我没有收到任何编译/链接错误。如果链接过程有问题,我想指出,因为我无法发现它。
  • 我刚刚在下面添加了对您问题的完整解释,如果您认为它解决了您的问题,请点赞。

标签: c++ boost boost-python


【解决方案1】:

请注意order is important 当您使用 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

注意单元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 库,因此您无需将 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} $^

通过库本身的setting the runtime path,运行时链接器会在尝试LD_LIBRARY_PATH 之前自动先查找那里。如果您决定不这样做,则必须按照其他答案的指示设置环境变量 LD_LIBRARY_PATH

【讨论】:

  • 谢谢。我不知道这个命令有什么意义。
  • 你的回答很好,但还没有结束。将您的答案与 Doctorloves 答案合并,摆脱所有错误。
  • 好的,我刚刚添加了一条注释,说明如何使用链接器本身来做到这一点。
【解决方案2】:

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

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

【讨论】:

  • 它似乎不起作用。我运行export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH:~/boost_1_54_0/stage/lib 并得到了同样的错误。我使用了错误的目录?
  • 我认为 /boost_1_54_0/stage/lib 有 boost python 所以?
  • 这是否意味着我不能在没有 boost 库的机器上使用扩展?如果没有 - 我该怎么做?
【解决方案3】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-04
    • 1970-01-01
    • 2012-11-06
    相关资源
    最近更新 更多