"Cython" tutorial to make Python explosive: When C ++ code depends on the library. Write setup.py.

Overview

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!

Situation explanation

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)

Cython for the time being

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

How are the dependent libraries written in 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. ..

Summary

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

"Cython" tutorial to make Python explosive: When C ++ code depends on the library. Write setup.py.
"Cython" tutorial to make Python explosive: When C ++ code depends on the library. First of all, CMake.
"Cython" tutorial to make Python explosive: When a function on the C ++ side has an overload.
"Cython" tutorial to make Python explosive: Pass the C ++ class object to the class object on the Python side. Part 2
"Cython" tutorial to make Python explosive: Handling when a function on the C ++ side is passed by reference.
"Cython" tutorial to make Python explosive: Pass a C ++ class object to a class object on the Python side. Part ①
"Cython" Tutorial to Make Python Explosive: Basic Configuration
"Cython" tutorial to make Python explosive: How to parse an Enum class defined in C ++ code into a Python Enum.
How to use the C library in Python
I want to make C ++ code from Python code!
I stumbled on the character code when converting CSV to JSON in Python
Make a breakpoint on the c layer with python
I felt that I ported the Python code to C ++ 98.
Pass OpenCV data from the original C ++ library to Python
How to write code to access python dashDB on Bluemix or local
I wrote the code to write the code of Brainf * ck in python
[Python] How to import the library
Try to write python code to generate go code --Try porting JSON-to-Go and so on
Execute Python code on C ++ (using Boost.Python)
How to deal with "^ [[A ^ [[B ^ [[C ^ [[D"] when you press the arrow keys when executing python on mac
python setup.py test the code using multiprocess
Make the library created by Eigen in C ++ available from Python with Boost.Numpy.
When you can't uninstall the python library. Can't uninstall'hogehoge'. No files were found to uninstall.
Note on encoding when LANG = C in Python
The trick to write flatten concisely in python
Introduction to Python with Atom (on the way)
To write to Error Repoting in Python on GAE
A story that got stuck when trying to upgrade the Python version on GCE
Make it easy to install the ROS2 development environment with pip install on Python venv
[Note] How to write QR code and description in the same image with python
How to pass arguments when invoking python script from blender on the command line