We continue the topic of how to call C / C ++ from Python3 . Now we use the cffi , pybind11 libraries . The method through ctypes was discussed in a previous article.
C
A test library to demonstrate working with global variables, structures, and functions with arguments of various types.
test.h
typedef struct test_st_s test_st_t; extern int a; extern double b; extern char c; int func_ret_int(int val); double func_ret_double(double val); char *func_ret_str(char *val); char func_many_args(int val1, double val2, char val3, short val4); test_st_t *func_ret_struct(test_st_t *test_st); struct test_st_s { int val1; double val2; char val3; };
test.c
#include <stdio.h> #include <stdlib.h> #include "test.h" int a = 5; double b = 5.12345; char c = 'X'; int func_ret_int(int val) { printf("C get func_ret_int: %d\n", val); return val; } double func_ret_double(double val) { printf("C get func_ret_double: %f\n", val); return val; } char * func_ret_str(char *val) { printf("C get func_ret_str: %s\n", val); return val; } char func_many_args(int val1, double val2, char val3, short val4) { printf("C get func_many_args: int - %d, double - %f, char - %c, short - %d\n", val1, val2, val3, val4); return val3; } test_st_t * func_ret_struct(test_st_t *test_st) { if (test_st) { printf("C get test_st: val1 - %d, val2 - %f, val3 - %c\n", test_st->val1, test_st->val2, test_st->val3); } return test_st; }
The library is exactly the same as in the ctypes article.
CFFI
This is a library for working exclusively with C. From the description of this library:
Interact with almost any C code from Python
Some of this was almost found.
For the experiment, version 1.12.3 was used , you can read about it here .
A little about this library in 2 words, CFFI generates its binding on top of our library and compiles it into a library with which we will work.
Installation
pip3 install cffi
Assembly
The build script that will collect the binding around our library.
build.py
import os import cffi if __name__ == "__main__": ffi = cffi.FFI()
Python
An example of working with C from Python through CFFI :
from cffi import FFI import sys import time
To work with C ++ code, you need to write a C binding for it. The article about the method through ctypes describes how to do this. Link below.
Pros and Cons of CFFI
Pros :
- simple syntax when used in Python
- no need to recompile the source library
Cons :
pybind11
pybind11, by contrast, is designed specifically for working with C ++ . Version 2.3.0 was used for the experiment, you can read about it here . She does not collect C sources, so I translated them into C ++ sources.
Installation
pip3 install pybind11
Assembly
We need to write a build script for our library.
build.py
import pybind11 from distutils.core import setup, Extension ext_modules = [ Extension( '_test',
We execute it:
python3 setup.py build --build-lib=./lib
C ++
In the library source you need to add:
namespace py = pybind11;
Python
An example of working with C from Python via pybind11 :
import sys import time
Pros and cons of pybind11
Pros :
- simple syntax when used in Python
Cons :
- you need to edit C ++ sources, or write a binding for them
- it is necessary to collect the necessary library from source
The average test execution time on each method with 1000 starts:
- ctypes: - 0.0004987692832946777 seconds ---
- CFFI: - 0.00038521790504455566 seconds ---
- pybind: - 0.0004547207355499268 seconds ---
+, - because the results were slightly different each time. Plus, time was spent printing, which I was too lazy to turn off (take this time as a constant, because it will be ~ the same in all tests). But still, there is a time difference in the function calls and obtaining the results from them.
References