Страницы

Поиск по вопросам

воскресенье, 8 декабря 2019 г.

Как с помощью Cython вызвать функцию c callback, написанную на C?

#python #c #cython


Есть функция на C: 

//my_f.h
typedef void (*callback_t)(int result);

void my_f(int a, int b, int c, callback_t cb);


//my_f.c
#include "my_f.h"

void my_f(int a, int b, int c, callback_t cb)
{
    cb(a * b + c);
}


собираем в библиотеку коммандой:

gcc -shared -fPIC -o libmy_f.so my_f.c


Теперь нужно из собранной библиотеки libmy_f.so правильно вызвать функцию my_f()
в Python.
Вопрос следущий -- как эту библиотеку правильно обернуть используя Cython?
    


Ответы

Ответ 1



Можно использовать boost, который позаботится о конвертировании типов и прочих жизненных радостях: Плюсовый код: std::string bar(const std::string& s) { return s + "!"; } BOOST_PYTHON_MODULE(foo) { using namespace boost::python; def("bar", bar); } Питоновый код: import foo print (foo.bar('what?'))

Ответ 2



Чтобы только одну функцию вызвать, удобно ctypes использовать: #file: run_my_f_ctypes.py import ctypes @ctypes.CFUNCTYPE(None, ctypes.c_int) def callback(result): print(result) lib = ctypes.cdll.LoadLibrary('./libmy_f.so') lib.my_f(1, 2, 3, callback) # -> 5 Если нужно именно Cython использовать, то чтобы можно было бы передать обычную Питон-функцию, обратный вызов должен принимать void* аргумент -- пример. Если вы не можете интерфейс my_f библиотеки изменить, чтобы callback_t принимал бы void* параметр (через который можно Питон-функцию передать как показано в примере), то в качестве обходного решения (hack), можно через глобальную переменную функцию передать: #file: cy_my_f.pyx cdef extern from "my_f.h": ctypedef void (*callback_t)(int result) void my_f(int a, int b, int c, callback_t cb) def call_with_callback(a, b, c, callback): global py_callback py_callback = callback my_f(a, b, c, c_callback) cdef void c_callback(int result): py_callback(result) В этом случае только один вызов может быть активен одновременно. #!/usr/bin/env python3 #file: run_my_f.py import pyximport # $ pip install cython pyximport.install() # compile on-the-fly import cy_my_f cy_my_f.call_with_callback(1, 2, 3, print) # -> 5 Обратите внимание Питон-функция print передана как есть. Чтобы собрать cy_my_f Питон-модуль из cy_my_f.pyx, необходимо указать путь к my_f библиотеке: #file: cy_my_f.pyxbld import os from distutils.extension import Extension dirname = os.path.dirname(__file__) def make_ext(modname, pyxfilename): return Extension(name=modname, sources=[pyxfilename], libraries=["my_f"], include_dirs=[dirname], # where my_f.h library_dirs=[dirname], # where -lmy_fy ) def make_setup_args(): return dict(script_args=["--verbose"]) Во время import cy_my_f, pyximport (часть cython) автоматически использует cy_my_f.pyxbld, чтобы собрать cy_my_f модуль расширения для CPython, определённый в cy_my_f.pyx файле.

Комментариев нет:

Отправить комментарий