На конференции PyGrunn 2016 я выступил с докладом о пакете Python cffi и его использовании для встраивания PyPy кода в приложения на C.
С выходом cffi 1.5.0 и его последующим включением в PyPy 5, становится возможным встраивать PyPy код. Это делается путем компиляции кода Python в динамическую библиотеку, которая затем может быть использована в любом другом языке. В этой статье я покажу вам, как это делать.
Встраиваемый API
Первый шаг заключается в определении интерфейса, который определяет, как приложению на С следует вызывать наш Python код. Мы должны указать это с помощью прототипов C-функций. Для нашего примера мы рассмотрим функцию, которая выполняет какие-то вычисления, но, конечно, это может быть все что угодно.
float compute(float first, float second);
Теперь мы должны реализовать эти вычисления на Python:
from my_library import ffi, lib
@ffi.def_extern()
def compute(first, second):
""" Вычисляет абсолютное расстояние между двумя числами. """
return abs(first - second)
Этот фрагмент содержит несколько особенных вещей для его правильного встраивания. Первая строка импортирует объекты ffi
и lib
из динамической библиотеки. Делая это реализация получает доступ к функциям, предоставляемым cffi и их можно использовать для более сложных задач, таких как выделение памяти. Имя my_library
определено ниже и соответствует имени нашей динамической библиотеки.
Второе, что мы замечаем в этом фрагменте — это декоратор @ffi.def_extern
. Он говорит cffi, что декорированные функции должны быть представлены в публичном API, создаваемой C-библиотеки. Декорированные функции будут сопоставлены с прототипами, указанными в объявлении API и их аргументами и возвращаемые значения будут преобразовываться автоматически.
Скрипт генерирующий библиотеку
Теперь, когда у нас есть API и его реализация, мы должны на самом деле куда-то его встроить. Для этого мы используем скрипт, который генерирует динамическую библиотеку. Он требует, чтобы два фрагмента кода, приведенные выше, находились в файлах api.h
и implementation.py
.
import cffi
ffi = cffi.FFI()
ffi.embedding_api(open("api.h").read())
ffi.embedding_init_code(open("implementation.py").read())
ffi.set_source("my_library", "")
ffi.compile(verbose=True)
Этот скрипт очень прост. Мы должны указать наш API и предоставить его реализацию. Они оба читаются с диска и соответствуют фрагментам кода, приведенным в предыдущем разделе.
После указания исходников, мы должны сказать cffi название нашей библиотеки. В этом примере это my_library
. Кроме того, здесь есть место для добавления дополнительного C-кода, предоставляющего типы для заголовочного файла нашего API, например, с помощью подключения соответствующих заголовочных файлов (что не допускается в embedding_api
). Остается только скомпилировать исходники, чтобы создать файл нашей библиотеки.
Запуск скрипта выводит некоторую информацию и создает нашу библиотеку:
$ pypy embed.py
generating ./my_library.c
running build_ext
building 'my_library' extension
...
$ ls my_library.dylib
-rwxr-xr-x 1 djinn staff 9856 May 15 14:46 my_library.dylib
Все что осталось — это где-нибудь ее использовать!
Использующее приложение
Использовать встраиваемый Python-код на самом деле очень просто. Это можно сделать с помощью следующего кода:
#include <stdio.h>
#include "api.h"
int main(void) {
float result = compute(12.34f, 10.0f);
printf("The result: %fn", result);
return 0;
}
Как вы видите, для вызова нашего Python-кода практически ничего не нужно. Используя API CPython, вы должны были бы запустить интерпретатор и выполнить множество преобразований параметров и возвращаемого значения. Но не с cffi! Созданная библиотека берет все на себя, так что вы можете сосредоточиться на действительно полезной работе. Последнее, что я должен показать вам, это как скомпилировать и запустить этот код.
$ clang -o test test.c my_library.dylib
$ ./test
The result: 2.340000
И вот оно! С помощью всего нескольких строк кода мы написали программу на C, которая запускает интерпретатор PyPy и выполняет наш Python-код, как если бы это был код на C. Конечно, я показал вам только основы, но это действительно мощная технология. Для получения дополнительной информации, можно посмотреть в документацию cffi.
Автор: DuDDiTs