【问题标题】:Is this Boost::Python (Python 3.7) error "__init__() should return None, not 'NoneType'" a linking problem?这是 Boost::Python (Python 3.7) 错误“__init__() 应该返回 None,而不是 'NoneType'”是链接问题吗?
【发布时间】:2019-07-09 13:17:38
【问题描述】:

更新

我不打算添加这个作为答案,因为我还没有从技术上解决这个问题。但是由于我现在花了 2.5 天的时间来尝试让 boost-python3 工作,我已经失去了使用它的意愿。

我刚刚遇到pybind11(我之前对 python 绑定工具的冗长搜索没有发现它,我不知道)并且正在使用它。 2.5 天的痛苦与 cmake example... 相比,所有特定的 python-version-dependency-hell 都消失了。

它在语法上与 boost-python 相似,但更容易管理、更快、只有标题并且功能更丰富。

耶!

原始问题

我正在使用 boost::python 在 python 3.7.2 中绑定一个类。

类导入成功但实例化它会出现以下错误:

<my-terminal>$ python
Python 3.7.2 (default, Feb 14 2019, 17:36:47) 
[Clang 10.0.0 (clang-1000.11.45.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import classes
>>> t = classes.World()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() should return None, not 'NoneType'
>>> 

这里是classes.cpp

#include <boost/python.hpp>
#include <boost/python/list.hpp>
#include <boost/python/extract.hpp>
#include <string>
#include <sstream>
#include <vector>

struct World
{
    void set(std::string msg) { mMsg = msg; }
    void many(boost::python::list msgs) {
        long l = len(msgs);
        std::stringstream ss;
        for (long i = 0; i<l; ++i) {
            if (i>0) ss << ", ";
            std::string s = boost::python::extract<std::string>(msgs[i]);
            ss << s;
        }
        mMsg = ss.str();
    }
    std::string greet() { return mMsg; }
    std::string mMsg;
};

using namespace boost::python;

BOOST_PYTHON_MODULE(classes)
{
    class_<World>("World")
        .def("greet", &World::greet)
        .def("set", &World::set)
        .def("many", &World::many)
    ;
};

假设

This question, almost identical 已解决,因为 python 2/3 问题(链接到 python 3 而不是 python 2 库)。所以我怀疑是图书馆链接问题。

检验假设

我无法让 bjam 工作,也无法为一个模块切换我们所有的构建系统......所以我正在使用 cmake 构建,它成功编译为 classes.so,输出如下,建议我找到所有正确的包含、库和可执行文件:

-- Found PythonInterp: /Users/me/.pyenv/versions/boost37/bin/python3 (found suitable version "3.7.2", minimum required is "3") 
PYTHON_VERSION_SUFFIX
-- Boost version: 1.68.0
-- Found the following Boost libraries:
--   python37
-- Found PythonLibs: /usr/local/Frameworks/Python.framework/Versions/3.7/lib/libpython3.7m.dylib (found suitable version "3.7.2", minimum required is "3") 
-- PYTHON_LIBRARIES = /usr/local/Frameworks/Python.framework/Versions/3.7/lib/libpython3.7m.dylib
-- PYTHON_EXECUTABLE = /Users/thc29/.pyenv/versions/boost37/bin/python3
-- PYTHON_INCLUDE_DIRS = /usr/local/Frameworks/Python.framework/Versions/3.7/include/python3.7m
-- Boost_LIBRARIES = /usr/local/lib/libboost_python37-mt.dylib

Boost-python3库目录内容:

ls /usr/local/Cellar/boost-python3/1.68.0/lib
libboost_numpy37-mt.a       libboost_numpy37.dylib      libboost_python37.a
libboost_numpy37-mt.dylib   libboost_python37-mt.a      libboost_python37.dylib
libboost_numpy37.a      libboost_python37-mt.dylib

我使用brew install boostbrew install boost-python3 --build-from-source 激活了我的python 3.7 virtualenv,以确保boost-python3 链接到正确版本的python。

检查库...

otool -L classes.so 给出:

classes.so:
    /usr/l/opt/boost-python3/lib/libboost_python37-mt.dylib (compatibility version 0.0.0, current version 0.0.0)
    /usr/local/opt/python/Frameworks/Python.framework/Versions/3.7/Python (compatibility version 3.7.0, current version 3.7.0)
    /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.200.5)

otool -L /usr/local/opt/boost-python3/lib/libboost_python37-mt.dylib 给出:

/usr/local/opt/boost-python3/lib/libboost_python37-mt.dylib:
        /usr/local/opt/boost-python3/lib/libboost_python37-mt.dylib (compatibility version 0.0.0, current version 0.0.0)
        /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.200.5)

在相关问题中,这表明了他们的问题。但是这里看起来不错!

还没有进展...

在正确编译并检查链接的痛苦过程之后,我无法发现任何缺陷。这是一个不同的问题吗?还是有我没有发现的链接问题?

感谢您的帮助!

【问题讨论】:

    标签: python c++ python-3.x boost boost-python


    【解决方案1】:

    在此处为使用 Anaconda 或 Conda-Forge 发行版的用户添加答案:

    python 解释器在libpythonXY 库中静态链接。这就是为什么它使 python 二进制文件与其他发行版相比有所不同。

    OP 报告的问题的解决方法是使用:

    -undefined dynamic_lookup
    

    代替:

    -lpythonXY
    

    您正在创建 Python C/C++ 扩展,而不是嵌入 Python 解释器。所以你不应该链接到 python 库。 Pybind11 可以正确处理这个问题。

    有关详细信息,请参阅以下内容:

    附带说明一下,python 3.8 添加了一个附加标志:--embed,然后才在输出中添加-lpythonXY

    $ python3.8-config --libs
    -ldl -framework CoreFoundation
    
    $ python3.8-config --libs --embed
    -lpython3.8 -ldl -framework CoreFoundation
    

    【讨论】:

    • 非常感谢 - 这已经解决了我的相关问题。
    【解决方案2】:

    我关注similar example,并采用here 的Makefile。我已经通过brewmacOS 上安装了python 3.7.4boost-python。要修复 NoneType 问题,我按照以下步骤操作:

    1.检查Python路径
    要检查python 路径,请使用

    which python
    

    如果输出不像下面这样(brewpython安装路径)

    /usr/local/opt/python/libexec/bin/python
    

    PATH 变量设置为

    export PATH="/usr/local/opt/python/libexec/bin:$PATH"
    

    检查Python 路径是否再次与上面的路径相似。

    2。检查编译标志
    以下是采用的Makefile。注意LIB 变量。如果boost-python 标志为-lboost_python,则将其更改为-lboost_python37

    CPP = clang++
    PYLIBPATH = $(shell python-config --exec-prefix)/lib
    # LIB = -L$(PYLIBPATH) $(shell python-config --libs) -lboost_python
    LIB = -L$(PYLIBPATH) $(shell python-config --libs) -lboost_python37
    OPTS = $(shell python-config --include) -O2
    
    default: hello.so
    
    
    hello.so: hello.o
        $(CPP) $(LIB) -Wl,-rpath,$(PYLIBPATH) -shared $< -o $@
    
    hello.o: hello.cpp Makefile
        $(CPP) $(OPTS) -c $< -o $@
    
    clean:
        rm -rf *.so *.o
    
    .PHONY: default clean
    
    

    重新编译C++ 代码并运行python 脚本。 NoneType 问题应该会消失。

    希望这会有所帮助。

    注意
    如果你使用的是anaconda,并且想在上述修改后恢复PATH变量,试试

    export PATH="~/anaconda3/bin:$PATH"
    

    您的anaconda 的路径可能不同。

    信用
    1. GeorgeHow do I use brew installed Python as the default Python?的评论
    2. leiycld: library not found for -lboost_python on MacOS 的评论

    【讨论】:

    • 谢谢尼克,这看起来就像它会解决问题,所以我会接受信任,即使我无法测试(很久以来搬到 pybind,根据问题中的更新)。也感谢您提供非常好的解释答案。
    【解决方案3】:

    跟进 Nehal's 对基于 Anaconda 的构建的回答。重读 cmake 的 FindPython 文档显示在 cmake 3.15 中添加了 Python::Module 目标用于创建模块。这意味着 CMakeLists.txt 应该是:

    set(Python3_FIND_VIRTUALENV FIRST)
    find_package(Python3 REQUIRED Development)
    find_package(Boost REQUIRED python3)
    add_library(classes MODULE classes.cpp)
    target_link_libraries(classes PRIVATE Python3::Module Boost::python3)
    

    显然,Python3::Python 用于将 Python 嵌入到另一个应用程序中。

    【讨论】:

      猜你喜欢
      • 2019-08-09
      • 2013-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-10
      • 2015-07-03
      • 2018-06-25
      相关资源
      最近更新 更多