I want to make the code written in ** c ++ ** into a ** library ** that can be called by ** python **. However, there was a big wall called ** cython **.
Dependencies of deep dark libraries, building an environment that makes you want to go crazy. Type conversion that I don't know what to do. That feeling of despair that makes me wonder if I'm writing python, c ++, or what I'm doing.
I have a little more time to touch cython, so I would like to summarize it little by little. I'm a beginner level in python, c ++, and cython, so if you have any mistakes, please let me know.
This time, I will aim to ** cythonize a very simple c ++ code and call it from python as a library **.
The minimum ** folder structure ** is as follows.
hoge@~/Documents/cython_test> tree .
.
├── cython
│ ├── library_cython.pyx
│ ├── test_library.pxd
│ └── test_library.pyx
├── my_library
│ ├── test.cpp
│ └── test.h
└── setup.py
2 directories, 6 files
setup.py The first is setup.py, which is needed to build the library.
`` `test_library``` is the name of the library to be read by python.
In other words, after building, call import test_library
.
setup.py
from setuptools import setup, Extension, find_packages
from Cython.Build import cythonize
from Cython.Distutils import build_ext
from distutils import sysconfig
ext_modules = [
Extension(
"test_library", sources=[
"./cython/test_library.pyx",
"./my_library/test.cpp"
],
language="c++"
)
]
setup(
name = "test_library",
cmdclass = {"build_ext": build_ext},
ext_modules= cythonize(ext_modules)
)
At this time,
Extension(
"test_library", sources=[
"./cython/test_library.pyx",
setup(
name = "test_library",
Let's keep the names of the three test_library
s that appear in. I was addicted to it here.
Create a class called TestClass
on the c ++ side. Call this from python via cython.
For simplicity, TestClass only has a constructor and a method called `test_function1 ()`
.
At this time, let's attach the namespace properly. I'm not sure why, but this is more convenient when converting to cython. Here, the namespace is my_library
.
test.h
namespace my_library
{
class TestClass{
public:
TestClass();
void test_function1();
};
} // namespace my_library
Write the contents of the function defined in the header. `test_function1 ()`
is just a function to print.
test.cpp
#include <iostream>
#include "test.h"
using namespace std;
namespace my_library{
TestClass::TestClass(){};
void TestClass::test_function1(){
cout << "printed from cpp function" << endl;
}
}
As you can see in setup.py, `` `test_library.pyxis the main cython file. Includes
library_cython.pyx``` below.
test_library.pyx
import cython
cimport cython
include "library_cython.pyx"
def test():
return TestClassCython()
The `` `pxd``` file is like a definition file for passing the necessary information to test_library.pyx from c ++. Now we really need to write again in the form of cython what was defined in the c ++ header.
test_library.pxd
cdef extern from "../my_library/test.h" namespace "my_library":
cdef cppclass TestClass:
TestClass()
void test_function1()
In this `` `library_cython.pyx```, we will define the python (cython?) Class that is actually called on the python side. The first confusing thing is to keep a pointer to a class defined in c ++ as a member variable of the class. In the constructor, construct the class on the c ++ side and pass its address to the ptr of this member variable. The destructor is erasing this ptr with del.
Also, the `test_function1_cython ()`
method internally calls the method defined on the c ++ side by setting it to
ptr.test_function1 ()` ``.
library_cython.pyx
import cython
cimport cython
cdef class TestClassCython:
cdef TestClass* ptr
def __cinit__(self):
self.ptr = new TestClass()
def __deadaloc(self):
del self.ptr
def test_function1_cython(self):
self.ptr.test_function1()
When the above is ready,
python setup.py install
will do. If you build successfully, enter the python interpreter and
Python 3.6.7 (default, Nov 16 2019, 21:57:19)
[GCC 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.11.45.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import test_library
>>> a = test_library.test()
>>> a.test_function1_cython()
printed from cpp function
>>>
I would be happy if I could do that.
So, using cython, I tried to call a class written in c ++ from python via a library. This is just the beginning, and the dependencies can get confusing, for example when using a library that needs to be compiled in c ++, but I'd like to write again for a slightly darker case.
If you find it helpful, we welcome your likes and comments! !!
end.
Recommended Posts