简体   繁体   中英

Calling c++ function, from Python script, on a Mac OSX

I've a c++ code on my mac that uses non-standard lybraries (in my case, OpenCV libs) and need to compile this so it can be called from other computers (at least from other mac computers). Runned from python. So I've 3 fundamental questions:

  1. How to compile my project so it can be used from python? I've read that I should create a *.so file but how to do so?
  2. Should it work like a lib, so python calls some specific functions, chosen in python level?
  3. Or should it contain a main function that is executed from command line?

Any ideas on how to do so? PS: I'm using the eclipse IDE to compile my c++ project.

Cheers,

If you use linux, the answers of atmaere and nouney may work for you.

In my case, as I use MacOSX, I figured my way through using the cython library. A straight forward tutorial to make things work is described bellow:

How to call C++ from Python script:

  1. INSTALL CYTHON: To install Cython, tool that integrates python scripts with c/c++, visit: https://pypi.python.org/pypi/Cython/

  2. DOWNLOAD A EXAMPLE: Download a C++ implementation example from here: http://wiki.cython.org/WrappingCPlusPlus?action=AttachFile&do=get&target=cythoncpp.tgz

  3. PREPARE C++ SOURCE FILES: be sure that your *.cpp and *.h files are correct. In the downloaded example, the filenames are cpp_rect.h and cpp_rect.cpp

  4. CREATE PYTHON WRAPER CPLASS: according to the rectangle.pyx file in the downloaded example or to the model described in http://docs.cython.org/src/userguide/wrapping_CPlusPlus.html?highlight=cpp#create-cython-wrapper-class

  5. PREPARE THE SETUP.PY FILE: the downloaded example already counts with this file but more information can be found in this tutorial: http://docs.cython.org/src/userguide/wrapping_CPlusPlus.html?highlight=cpp#specify-c-language-in-setup-py . [PS: 1 The easiest way to compile is with the disutilis package, using a setup.py file. For mor info about compilation options, visit http://docs.cython.org/src/reference/compilation.html# .

  6. TRY TO COMPILE: Go to the terminal, from the same folder where your source files are. At this point you already ghave 4 files: cpp_rect.h, cpp_rect.cpp, rectangle.pyx and setup.py. From there, execute the command $ python setup.py build_ext --inplace

  7. If you receive a g++ error, such as it happened to me: "unable to execute gcc-4.2: No such file or directory" u can hack the flag system doing sudo ln -s /usr/bin/gcc /usr/bin/gcc-4.2 . Than repeat the previous step.

  8. TEST YOUR CODE: At this momment, you have everything you need: the setup.py was used along with the rectangle.pyx to generate the rectangle.so file, which is WHAT we need! Just build a pythons script to test your integration. Luckly, the example already counts with a test script, named use_rect.py.

Now just run it from the terminal using " $ python userect.py "

How to compile my project so it can be used from python? I've read that I should create a *.so file but how to do so?

That depends on your compiler. By example with g++: g++ -shared -o myLib.so myObject.o

Should it work like a lib, so python calls some specific functions, chosen in python level?

Yes it is, in my opinion. It seems do be the "obvious" way, since it's great for the modularity and the evolution of the C++ code.

Here is an example using SWIG:

The Python code which calls C++ function "inflow":

 import inflow    # importing C++ inflow library
 nframes = 25
 print 'calling inflow function in loop ...'
 for i in xrange(0,1001):
      z = inflow.inflow(""" arguments""")
     """ code does something with z """

The C++ function will be as usual:

 #include <iostream>
 #include <vector>
  inflow(/* arguments from Python*/)
  {
   /* code does something */

  }

Now to interface with Python, here are the steps:

1) IMPORTANT - Make sure the C++ code you are trying to bind in this step has a different name than the one given in the command. Else it will overwrite with swig code.

Lets say example_wrap.cpp is the file you want to interface with Python and "example.i" is the SWIG interface file. SWIG will generate a new file with the name example.cpp.

2) swig -c++ -python -o example_wrap.cpp example.i

3) g++ -I /usr/include/python2.7 -fPIC -c example_wrap.cpp -o example_wrap.o

4) g++ -shared -o _example.so example_wrap.o

Idea is that the compiled module name should start with an underscore, followed by the name.

5) Open Python in term, and say

from example import *

and then start calling the functions.

6) Source : http://www.iram.fr/~roche/code/python/SWIG.html#purpose

The interface file for the example would look something like this:

 %module example
 %{
   #include "example.h"
 %}

 %include "std_vector.i"
 // Instantiate templates used by example
 namespace std {
  %template(IntVector) vector<int>;
  %template(DoubleVector) vector<double>;
  }

  // Include the header file with above prototypes
  %include "example.h"
  1. I think you should take a look in boost python , it's an amazing library and also works in linux, windows and mac. Using boost python, you can export your classes and functions in order to access them directly from python. There are many many examples and the documentation is very good!!!

  2. Using boost python, you should define which functions/classes you want to expose, and them compile your source code into a library file that's going to be imported inside python.

The Simple, Effective, and Quick Approach:

Void Methods

test.cpp

#include <iostream>
extern "C" void Print()
{
    std::cout << "This is data from inside a c++ file." << std::endl;
}

Compile time commands

g++ -c -fPIC test.cpp -o test.o // DO NOT FORGET '-fPIC'
g++ -shared -o test.so test.o // FOR UNIX ONLY

Main.py

from ctypes import cdll

test = cdll.LoadLibrary('./test.so')
test.Print()

Passing and returning values

In test.cpp

extern "C" int Multiply(int a, int b)
{
    return a*b;
}

In Main.py from ctypes import cdll

test = cdll.LoadLibrary('./test.so')
value = test.Multiply(5,5)
print(value)


Summary
No additional libraries are needed.
No constructors are needed.
No c++ classes are needed.
No public declarations are needed.

Simply create a method and mark it as extern "C"
Then call it in python.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM