Boost.Python __init__() should return None, not 'NoneType'

4.5k views Asked by At

I have a whole bunch of working C++ code that I want to write Python bindings for. I'm trying to use Boost.Python since it seems to be the easiest way to get this working, but it isn't cooperating. Here's part of the code for the extension module I'm trying to build:

BOOST_PYTHON_MODULE(libpcap_ext) {
    using namespace boost::python;
    class_<PacketEngine>("PacketEngine")
        .def("getAvailableDevices", &PacketEngine_getAvailableDevices);
}

Bjam seems to be a pain and refuses to recognize my Pythonpath or allow me to link with libpcap, so I'm using CMake. Here's my CMakeLists file, which can import and build everything just fine (outputs libpcap.so as expected):

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
IF(NOT CMAKE_BUILD_TYPE)
  SET(CMAKE_BUILD_TYPE "DEBUG")
  #SET(CMAKE_BUILD_TYPE "RELEASE")
  #SET(CMAKE_BUILD_TYPE "RELWITHDEBINFO")
  #SET(CMAKE_BUILD_TYPE "MINSIZEREL")
ENDIF()

FIND_PACKAGE(Boost 1.55.0)
find_package(PythonLibs REQUIRED)
IF(Boost_FOUND)
  INCLUDE_DIRECTORIES("${Boost_INCLUDE_DIRS}" "${PYTHON_INCLUDE_DIRS}")
  SET(Boost_USE_STATIC_LIBS OFF)
  SET(Boost_USE_MULTITHREADED ON)
  SET(Boost_USE_STATIC_RUNTIME OFF)
  FIND_PACKAGE(Boost 1.55.0 COMPONENTS python)

  ADD_LIBRARY(pcap_ext MODULE PacketWarrior/pcap_ext.cc PacketWarrior/PacketEngine.h PacketWarrior/PacketEngine.cc PacketWarrior/Packet.h PacketWarrior/Packet.cc)
  TARGET_LINK_LIBRARIES(pcap_ext pcap)
  TARGET_LINK_LIBRARIES(pcap_ext ${Boost_LIBRARIES} ${PYTHON_LIBRARIES})
ELSEIF(NOT Boost_FOUND)
  MESSAGE(FATAL_ERROR "Unable to find correct Boost version. Did you set BOOST_ROOT?")
ENDIF()

ADD_DEFINITIONS("-Wall")

And my pcap.py file that attempts to utilize the module:

import libpcap_ext
engine = libpcap_ext.PacketEngine()
print engine.getAvailableDevices()

But whenever I try to run the module, I get the following error:

Traceback (most recent call last):
  File "../pcap.py", line 2, in <module>
    engine = libpcap_ext.PacketEngine()
TypeError: __init__() should return None, not 'NoneType

I'm assuming it's because Boost.Python is trying to use Python 3 and my system default is Python 2.7.3. I've tried changing my user-config.jam file (in my boost_1_55_0 directory) to point to Python 2.7 and tried building:

# Configure specific Python version.
# using python : 2.7 : /usr/bin/python2.7 : /usr/include/python2.7 : /usr/lib ;

Boost.Python's installation instructions [0] seem to fail for me when I try to build quickstart with bjam (lots of warnings), so I tried following the Boost Getting Started instructions [1] to build a Python header binary, which is I think what is causing this problem. Any recommendations as to how to fix this would be amazing, I've spent hours on this.

1

There are 1 answers

2
Burkhard On BEST ANSWER

This error is probably due to linking against the wrong Python library. Make sure your extension as well as the Boost Python library are linked against the Python installation you are using to import the module.

On Linux you can check against which libraries you've linked with ldd. On OS X otool -L does the same thing. So, for example

otool -L libpcap_ext.so
otool -L /path/to/libboost_python-mt.dylib

should list the Python library they are linked against.

With CMake you can use the variable PYTHON_LIBRARY to change which Python library is used. As an example, on the command line you can set it with

cmake -DPYTHON_LIBRARY="/path/to/libpython2.7.dylib" source_dir

Lastly, on OS X a quick and dirty way (i.e. without recompiling) to change the dynamically linked libraries is install_name_tool -change.