Как можно использовать CFFI для вызова существующей функции C с учетом исходного кода?
У меня есть исходный / заголовочный файл C, который является частью большого проекта. Я хотел бы проверить это как единое целое, независимое от реального проекта. Хотя было бы возможно сделать это в C, создав новый проект с другим main()
Я хотел бы посмотреть, смогу ли я использовать Python (3) и его фреймворки (например, перенос) для ускорения построения тестов, использования существующих фреймворков отчетности и т. Д.
У меня сложилось впечатление, что я могу сделать это с CFFI. Вот пример файла C:
// magic.c
// Implementation of magic.
int add(int a, int b)
{
return a;
}
Заголовок:
// magic.h
// Add two numbers (where a + b is not greater than INT_MAX).
int add(int a, int b);
Вот скрипт, который просто пытается скомпилировать его, чтобы я мог вызвать некоторые функции:
# cffi_test.py
import cffi
INCLUDE_DIRS = ('.',)
SOURCES = ('magic.c',)
ffi = cffi.FFI()
ffi.set_source(
'_magic_tests',
'#include "magic.h"',
include_dirs = INCLUDE_DIRS,
sources = SOURCES,
libraries = [],
)
ffi.compile()
В конечном итоге я планирую сделать это частью установки перед набором модульных тестов, например. чисто функция Python test_add()
вызовет и проверит результат функции C add()
через ffi
объект, который построен в тестовой настройке.
Вышеупомянутый скрипт, кажется, работает; работает без ошибок, создает _magic_tests.c
файл, _magic_tests.cp35-win32.pyd
файл и Release
каталог. я тоже могу import _magic_tests
без ошибок.
Но я не могу понять, как на самом деле вызвать функцию C через CFFI. Я не могу найти документацию для set_source()
функция, и это кажется довольно неотъемлемой частью всего процесса. Обзор упоминает это много, но ссылка содержит ноль случаев этого. В документах есть раздел о вызове функций, но он относится к некоторым lib
объект, не показывая, как он создан. Если я посмотрю на предыдущий пример, есть lib
объект, созданный из ffi.dlopen()
, но я не вижу, как применить это к тому, что производит сам CFFI.
Мой большой вопрос (т.е. моя проблема с Х):
- Является ли CFFI разумным инструментом для вызова и тестирования функций C в кросс-платформенном режиме (Windows 7-10, Linux, OS X), и если да, то как?
Вопросы, возникающие в связи с моим текущим подходом (т.е. мои проблемы Y):
- Где находится документация для
set_source()
? Как я могу узнать, какие аргументы он принимает? - Как мне произвести
lib
объекты, которые содержат функции, которые я хочу вызвать? - Это самый простой способ использовать CFFI для вызова функции C? Я не особенно нуждаюсь или не хочу, чтобы создавалась общая библиотека или распространяемый пакет; если это должно произойти, это нормально, но это не обязательно. Какие еще подходы я могу попробовать?
Моя текущая настройка:
- ОС: Windows 10
- Python: CPython 3.5.1 32 бит
- Пип: 8.1.2
- CFFI: 1.6.0
- Компилятор C: все, что поставляется с Visual C++ Build Tools 2015, по ссылке из этого поста MSDN
Я использую CFFI и pycparser из хранилища Кристофа Гольке.
1 ответ
Для моего проекта я использую cffi
проверить мой C-код. по моему мнению cffi
является отличным инструментом для генерации привязок Python для кода на C и поэтому считает, что это разумный инструмент для вызова и тестирования функций C из Python. Тем не менее, ваш код будет таким же кроссплатформенным, как и код C, так как вы должны скомпилировать привязку для каждой платформы.
Ниже вы можете найти несколько ссылок на документацию, которая должна ответить на ваши вопросы. Кроме того, я написал пример кода, чтобы проиллюстрировать, как вы будете использовать cffi
, Более подробный пример вы можете найти в моем проекте по адресу https://github.com/ntruessel/qcgc/tree/master/test.
Документация для
set_source()
можно найти здесь https://cffi.readthedocs.io/en/latest/cdef.htmlhttps://cffi.readthedocs.io/en/latest/overview.html объясняет, как вы можете использовать CFFI, я рекомендую API, в автономном режиме.
Четыре твоих примера, build_magic_tests.py
будет выглядеть примерно так:
from cffi import FFI
ffibuilder = FFI()
# For every function that you want to have a python binding,
# specify its declaration here
ffibuilder.cdef("""
int add(int a, int b);
""")
# Here go the sources, most likely only includes and additional functions if necessary
ffibuilder.set_source("magic_tests",
"""
#include "magic.h"
""", sources=["magic.c"])
if __name__ == "__main__":
ffibuilder.compile()
Чтобы создать модуль magic_tests, вы должны запустить python build_magic_tests.py
, Сгенерированный модуль может быть импортирован и использован следующим образом:
from magic_tests import ffi, lib
def run_add():
assert 4 == lib.add(4, 5)