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