5

I'm trying to import a C++ class in Python. I know I could use BoostPython, SWIG or Cython, but just for didatical purposes I'm trying to manually export C++ methods and functions with extern "C". In a nutshell, I'm trying to replicate this.

My enviroment is Windows 10, with Anaconda 3 and Python 3.6. I've installed mingw64 4.8.3 as C/C++ compiler.

This is my foo.cpp:

#include <iostream>
// A simple class with a constuctor and some methods...
class Foo
{
    public:
        Foo(int);
        void bar();
        int foobar(int);
    private:
        int val;
};
Foo::Foo(int n)
{
    val = n;
}
void Foo::bar()
{
    std::cout << "Value is " << val << std::endl;
}
int Foo::foobar(int n)
{
    return val + n;
}
// Define C functions for the C++ class - as ctypes can only talk to C...
extern "C"
{
    Foo* Foo_new(int n) {return new Foo(n);}
    void Foo_bar(Foo* foo) {foo->bar();}
    int Foo_foobar(Foo* foo, int n) {return foo->foobar(n);}
}

I've compiled in this way: g++ -c -fPIC foo.cpp -o foo.o. The output is:

foo.cpp:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
#include <iostream>
^

Then, I've compiled in this way: g++ -shared -Wl,-soname,libfoo.dll -o libfoo.dll foo.o getting no errors/warnings. The file libfoo.dll has appared in the folder.

When I try in Python:

import ctypes
lib = ctypes.windll.LoadLibrary('libfoo.dll')

I get the error OSError: [WinError 126] the specified module could not be found. My Python working directory is the libfoo.dll folder.

I tried to create a simple C-HelloWorld library: I compiled in the same way (a part gcc instead of g++) and I succeded in loading it into Python.

Where is the problem? Is it in the compilation instructions? Or in the code?

Marco
  • 367
  • 1
  • 10
  • Have you tried to give it an absolute path to the `.dll`? When you do, remember to escape the slashes: `C:\\...\\...\\libfoo.dll` – Błażej Michalik Sep 29 '18 at 12:53
  • Yes, I tried. Also, I tried to move it to a different Disk (from `E:\\...\\libfoo.dll` to `C:\\...\\libfoo.dll`) – Marco Sep 29 '18 at 13:21
  • I'm not sure about mingw g++. In VS, making functions `extern` isn't enough for DLLs. If I want to use them from other EXE/DLL, I have to export them. Out of curiosity I googled and found this: [HOWTO Create and Deploy a Sample DLL using MinGW](http://www.mingw.org/wiki/sampledll) and this [Exporting a class from a DLL for multiple instantiations](http://www.mingw.org/wiki/exporting_a_class_from_a_dll_for_multiple_instantiations). It seems that is the same for mingw. – Scheff's Cat Sep 29 '18 at 14:56

1 Answers1

3

I've found a solution starting from @Scheff comment.

On Linux (I've tried on Ubuntu 16, GCC 4.4.0 and Python 3.6), my question code works well without modifications (both on the code and on the compilation instructions).

On Windows, I modified the extern "C" block in this way:

extern "C"
{
     __declspec(dllexport) Foo* Foo_new(int n) {return new Foo(n);}
     __declspec(dllexport) void Foo_bar(Foo* foo) {foo->bar();}
     __declspec(dllexport) int Foo_foobar(Foo* foo, int n) {return foo->foobar(n);}
}

and I recompiled as before.

Thereafter I was able to import the module and the C++ class as described in the question link.

For implementing the C++ print function please see this question.

Marco
  • 367
  • 1
  • 10