我有一个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)是:
  • CFFI是在跨平台(Windows 7-10,Linux,OS X)中用于调用和测试C函数的合理工具吗?

  • 我当前的方法(即我的Y problems)引起的问题是:
  • set_source()的文档在哪里?我如何找出需要哪些论点?
  • 如何生成包含要调用的函数的lib对象?
  • 这是使用CFFI调用C函数的最简单方法吗?我不是特别需要或不希望产生共享库或可再发行软件包。如果必须发生,那很好,但这不是必需的。我还可以尝试其他什么方法?

  • 我当前的设置是:
  • 操作系统:Windows 10
  • Python:CPython 3.5.1 32位
  • 点子:8.1.2
  • CFFI:1.6.0
  • C编译器:从this MSDN post链接到
  • 的Visual C++ Build Tools 2015附带的任何内容

    我正在使用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
  • https://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)
    

    10-05 20:30