我有一个C源代码/头文件,它是一个较大项目的一部分。我想将此单元作为一个单元进行测试,而与实际项目无关。尽管可以通过用不同的main()
创建一个新项目来用C做到这一点,但我想看看是否可以使用Python(3)及其框架(例如 Nose )来加速测试的构建,并使用现有的报告框架等
我的印象是我可以使用CFFI做到这一点。这是一个示例C文件:
// magic.c
// Implementation of magic.
int add(int a, int b)
{
return a;
}
header :
// 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()
将通过add()
对象调用并检查C函数ffi
的结果,该对象是在测试设置中构造的。上面的脚本似乎有效;它运行无误,它创建了一个
_magic_tests.c
文件,一个_magic_tests.cp35-win32.pyd
文件和一个Release
目录。我也可以import _magic_tests
没有错误。但是我不知道如何通过CFFI实际调用C函数。我找不到有关
set_source()
函数的任何文档,并且它似乎是整个过程不可或缺的一部分。 overview提到很多,但是reference包含零次出现。 docs do 的一节介绍了calling functions,但它引用了lib
对象,但未显示其创建方式。如果我看前面的示例,有一个从lib
创建的ffi.dlopen()
对象,但是我看不到如何将其应用于CFFI本身正在生成的内容。我的大问题(即我的X problem)是:
我当前的方法(即我的Y problems)引起的问题是:
set_source()
的文档在哪里?我如何找出需要哪些论点? lib
对象? 我当前的设置是:
我正在使用Christoph Gohlke's repository的CFFI和pycparser。
最佳答案
对于我的项目,我使用cffi
测试我的C代码。 IMHO cffi
是为C代码生成python绑定(bind)的好工具,因此认为它是用于从python调用和测试C函数的合理工具。但是,由于您必须编译每个平台的绑定(bind),因此您的代码将仅与C代码一样跨平台。
您可以在下面找到一些应回答您问题的文档引用。另外,我编写了一些示例代码来说明如何使用cffi
。对于较大的示例,您可以在https://github.com/ntruessel/qcgc/tree/master/test上找到我的项目。
set_source()
的文档https://cffi.readthedocs.io/en/latest/cdef.html 在您的示例四个中,
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)