0

I am trying to get up and running with using ctypes to call C++ libraries from Python 2.7 on a Linux machine. For the moment, I'm just trying toy examples. I read and was able to replicate the example given in this thread: Calling C/C++ from python?. Note that the C++ class functions take no inputs.

I'm trying to extend this example as follows.

foo.cpp

#include <iostream>
#include <string>
using namespace std;

class Foo {
public:
  Foo(string name);
  void bar(void);
private:
  string myName;
};
Foo::Foo(string name) {
  std::cout << "Entered constructor in C++" << std::endl;
  myName = name;
}
void Foo::bar(void) {
  std::cout << "Hello, this is " << myName << std::endl;
}

extern "C" {
  Foo* Foo_new(string name) {return new Foo(name);}
  void Foo_bar(Foo* foo) {foo->bar();}
}

The code compiles cleanly using g++ -c -fPIC foo.cpp -o foo.o and then g++ -shared -Wl,-soname,libfoo.so -o libfoo.so foo.o.

I then use the following wrapper,

fooWrapper.py

from ctypes import cdll, c_char_p
lib = cdll.LoadLibrary('./libfoo.so')

class Foo(object):
    def __init__(self,name):
        self.name = name
        self.obj = lib.Foo_new(c_char_p(name))
    def bar(self):
        lib.Foo_bar(self.obj)

Because I'm passing a string to the constructor, I'm under the impression that I need to cast it using c_char_p. Maybe this is wrong.

When I execute the code in Python 2.7, I get a segmentation fault,

Python 2.7.2 (default, Feb 27 2012, 18:28:19) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-48)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import fooWrapper as f
>>> foo = f.Foo('somename')
Segmentation fault

So I never get into the C++ constructor function. I have the same problem whether or not I include the self.name = name line in the constructor method in the Python code.

What am I doing wrong? Thanks.

Community
  • 1
  • 1
xbot
  • 327
  • 3
  • 13
  • std::string is not a typedef to a pointer, it's a class. I'm not 100% sure, but I'd try changing your Foo to take a character pointer and see if it doesn't segment fault that way. I'm not sure how you'd change it to maintain compatibility with std::string but I'm sure theres a way. – Wug Aug 27 '12 at 13:25
  • You are calling `Foo` constructor in `f.Foo('somename')` from python.shouldn't you do `f.bar` instead from your python code ? – Neel Basu Aug 27 '12 at 13:26

1 Answers1

0

In your extern "C" you declare Foo_new to take a std::string argument, however for the code to be callable from Python you have to make it a true C function, which include receiving strings a character pointers. Especially as you actually tells the interpreter to convert your string to a character pointer (that's what the c_char_p call does).

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Thanks, I appear to have fixed it. In my `extern "C"`, I now have `Foo* Foo_new(char* name) {return new Foo(name);}` with everything else the same. This works. – xbot Aug 27 '12 at 16:34