I want to make the code written in C ++ a library that can be called in Python. However, there was a big wall called Cython.
This is the "Cython" tutorial that makes Python explosive: when C ++ code depends on the library. First of all, CMake. It will be a continuation of.
So far, we've seen how to comfortably compile a C ++ program that depends on the gmp library using cmake. From here, the main subject is finally to write the code to cythonize this C ++ program and compile it with setup.py.
The code used here can be found on github here, so if you are interested, please have a look!
In the previous article, I had to understand the dependencies of my C ++ program in order to write setup.py in the first place.
--About dependencies that are easy to trip when writing C ++ programs --About compiling C ++ with CMake
I explained. This time, I will write the code that actually converts the C ++ function to Cython, write setup.py referring to the previous CMakeLists.txt, and compile it so that it can be called from Python.
The code on the C ++ side is also included as a review.
cpp_library/TestClass1.h
#include <gmp.h>
namespace my_library
{
class TestClass1{
public:
TestClass1();
void test_function1();
static void gmp_print_test();
};
} // namespace my_library
cpp_library/TestClass1.cpp
#include <iostream>
#include "TestClass1.h"
using namespace std;
namespace my_library{
TestClass1::TestClass1(){};
void TestClass1::test_function1(){
cout << "printed from cpp function" << endl;
}
void TestClass1::gmp_print_test(){
mpz_t test;
mpz_init(test);
mpz_set_ui(test, 1);
gmp_printf("print : %Zd \n", test);
}
}
If you have such a test.cpp, make sure you can compile it with the following CMakeLists.txt```.
cpp_library/test.cpp
#include "TestClass1.h"
using namespace my_library;
int main(){
TestClass1::gmp_print_test();
}
cpp_library/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(TEST VERSION 1.1.0 LANGUAGES CXX)
# Executable will be in ../bin
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR})
set(CMAKE_CXX_FLAGS "-g -O0 -lgmp")
add_executable(test1
test.cpp
TestClass1.cpp
)
target_sources(test1
PRIVATE
)
target_include_directories(test1 PRIVATE /usr/local/gmp/6_1_2/include/)
target_link_libraries(test1 gmp /usr/local/gmp/6_1_2/lib)
First, write the cython code as follows to wrap the C ++ function. As I did before, the pxd file was a cython header file and the pyx file was a cython program body file. Write to wrap C ++ as follows.
cython/test_class1.pxd
cdef extern from "../cpp_library/TestClass1.h" namespace "my_library":
cdef cppclass TestClass1:
TestClass1()
void test_function1()
void gmp_print_test()
cython/test_class1.pxd
import cython
cimport cython
cdef class TestClass1Cython:
cdef TestClass1* ptr
def __cinit__(self):
self.ptr = new TestClass1()
def __deadaloc(self):
del self.ptr
def test_function1_cython(self):
self.ptr.test_function1()
@staticmethod
def gmp_print_test():
cdef TestClass1 testclass1
testclass1.gmp_print_test()
cython/my_library.pxd
cdef extern from "../cpp_library/TestClass1.h" namespace "my_library":
cdef cppclass TestClass1:
TestClass1()
void test_function1()
void gmp_print_test()
cython/my_library.pyx
import cython
cimport cython
include "test_class1.pyx"
def test():
return TestClass1Cython()
setup.py
From here, write setup.py clearly that it depends on the gmp library.
In fact, if you already know how to write CMakeLists.txt, it's an easy task.
As you can see,
libraries=["gmp"],
library_dirs=["/usr/local/lib", "/usr/local/gmp/6_1_2/lib"],
include_dirs=["/usr/local/gmp/6_1_2/include"],
like,
--Dependent libraries --Location of object files in the library --Header file location
Just like when you wrote CMakeLists.txt.
As a result, I created the following setup.py.
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(
"my_library", sources=["./cython/my_library.pyx",
"./cpp_library/TestClass1.cpp"
],
libraries=["gmp"],
library_dirs=["/usr/local/lib", "/usr/local/gmp/6_1_2/lib"],
include_dirs=["/usr/local/gmp/6_1_2/include"],
language="c++",
extra_compile_args=['-std=c++1z',"-lgmp"]
),
]
setup(
name = 'my_library',
cmdclass = {'build_ext': build_ext},
ext_modules = cythonize(ext_modules)
)
After completing the above, you have successfully converted the C ++ program that depends on the gmp library into cython.
python setup.I tried it with py install and it compiles. I will try to call it properly from the python side.
```bash
(myenv) root@e96f489c2395:/from_local/cython_practice# python
Python 3.6.3 (default, Jan 30 2020, 06:37:54)
[GCC 7.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import my_library
>>> my_library.TestClass1Cython.gmp_print_test()
print : 1
great. ..
This time, I explained how to use Cythonize when the code on the C ++ side depends on some library (gmp library in the example), and I was able to actually compile it.
Next, I will explain how to pass a class object on the C ++ side to a Python class object. Personally, I think that most things can be done if you know how to hand it over, so please take a look! !!
If you find it helpful, I'd love to hear from LGTM, comments, and more.
This time around here.
end.
Recommended Posts