[Перевод] Встраивание PyPy кода в приложения на C

b1c71cb6299741fc9b60f3500f199c27.jpg
На конференции 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 
#include "api.h"

int main(void) {
    float result = compute(12.34f, 10.0f);
    printf("The result: %f\n", 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.

© Habrahabr.ru