Unable to import a custom DLL in python

2019-04-02 06:13发布

问题:

I am trying to expose a C++ class to python with boost::python, so I am going through this tutorial. I created a visual studio .dll project, with this source code:

#include <boost/python.hpp>
using namespace boost::python;

struct World
{
    void set(std::string msg) { this->msg = msg; }
    std::string greet() { return msg; }
    std::string msg;
};

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

And I built it as a 64-bit dll. The next step in the tutorial says:

Here, we wrote a C++ class wrapper that exposes the member functions greet and set. Now, after building our module as a shared library, we may use our class World in Python. Here's a sample Python session:

>>> import hello
>>> planet = hello.World()
>>> planet.set('howdy')
>>> planet.greet()
'howdy'

However, after launching python in the same directory and typing import hello I get

>>> import hello
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named 'hello'
>>>

I have tried renaming the 'dll' files to hello.dll, and also copying every output file (dll, exp, ilk, lib, and pdb) to %PYTHONPATH%\DLLs, yet I am still unable to import the module into python.

Much googling brought me to this article recommending I use ctypes to import the dll. This lets me load the dll, but I am still unable to call the "World" class. For example:

>>> import ctypes
>>> mydll = ctypes.cdll.LoadLibrary("hello")
>>> mydll
<CDLL 'hello', handle 7fef40a0000 at 0x775ba8>
>>> hello = mydll.World()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Program Files\Python35\lib\ctypes\__init__.py", line 360, in __getatt
r__
    func = self.__getitem__(name)
  File "C:\Program Files\Python35\lib\ctypes\__init__.py", line 365, in __getite
m__
    func = self._FuncPtr((name_or_ordinal, self))
AttributeError: function 'World' not found
>>>

So a couple questions:

  1. Is it possible to import a dll in python without using ctypes? The tutorial seems to indicate that it is, but doesn't provide very much detail about the right way to get the dll into python.

  2. Which files do I need and where? It seems like I should only need the dll file from visual studio in the working directory of my python shell, but this is clearly not working for me.

  3. Why can't I call World through ctypes?

Some more important details: I am using windows 7 64-bit, python 3.5.2 64-bit, and Visual Studio 2015 with Boost 1.61.

回答1:

I actually just figured out the answer shortly after posting the question. Thanks to this blog post I found out that simply renaming the hello.dll to hello.pyd was enough. From some more googling, I think that ctypes is only for C DLLs, not C++, and not with boost!. The point of boost::python, is to remove the need for ctypes and make the DLL compatible with python. So to answer all of my own questions:

  1. Yes, but it must have a .pyd extension.

  2. You only need the compiled dll file and the boost_python_vc140...dll (may vary). However, like I said, the dll file must be renamed.

  3. Because ctypes is not the right tool for loading a boost::python dll!