目录文件结构
project
│ cffi_test.py
│ make_cdef.py
│
└───source_files
│ call_back.h
│ call_back.lib
│ hello_world.c
│ hello_world.h
cffi_test.py:
import cffi
ffi = cffi.FFI()
from _test_cffi import ffi, lib
string_data = ffi.new("char[]", b"hello")
print("字符串长度:", len(string_data), " 字符串第一个字符:", string_data[0], " 字符串内容:", ffi.string(string_data))
num = ffi.new("int *", 520)
lib.HelloWorld(num)
struct_data = ffi.new("struct_test *", [1, 2])
print(f"struct_data.y: {struct_data.y}")
lib.PrintTest()
@ffi.callback("void (*CallBack)(int num)")
def PrintNum(num):
print(f"\r\nThe Num Is: {num}", num)
lib.call(PrintNum, 520)
make_cdef.py(自动编译 .h 文件):
import cffi
from pathlib import Path
SCRIPT_DIR = Path(__file__).parent
ffi = cffi.FFI()
def mkcdef(headerfile: str):
import tempfile
temp_file = tempfile.mktemp(".c")
open(temp_file, 'w').write(headerfile)
import re
LINE_REGEX = re.compile(r'[\s]*#')
import distutils.ccompiler
comp = distutils.ccompiler.new_compiler()
ccname = distutils.ccompiler.get_default_compiler()
cflags = {'msvc': ['/P'], 'unix': ['-E']}[ccname]
call_back_dir = SCRIPT_DIR / 'source_files'
tmpdir = tempfile.mkdtemp()
comp.compile([temp_file], debug=1, output_dir=tmpdir, include_dirs=[call_back_dir], extra_postargs=cflags)
cdefList = []
if ccname == 'msvc':
IFile = f'{Path(temp_file).stem}.i'
elif ccname == 'unix':
IFile = list(Path(tmpdir).glob('**/*.*'))[0]
for line in open(IFile, 'r'):
if not LINE_REGEX.match(line) and not line.strip() == '' and '__pragma' not in line:
cdefList.append(line)
import os
os.remove(IFile)
cdefList.append("void PrintTest(void);\n")
cDef = ''.join(cdefList)
with open("CDEF.txt", "w") as f:
f.write(cDef)
return cDef
cdef = mkcdef(open('.//source_files//hello_world.h', 'r', encoding='utf-8').read())
ffi.cdef(cdef)
ffi.set_source("_test_cffi", '''
#include <stdio.h>
#include "./source_files/hello_world.c"
void PrintTest(void)
{
printf("Your_name666");
}
''', libraries=["./source_files/call_back"])
ffi.compile(verbose=True)
import os
all_file = os.listdir(SCRIPT_DIR)
for index in range(len(all_file)):
file = all_file[index]
if file[-2:] == '.i':
os.remove(SCRIPT_DIR / all_file[index])
call_back.h
typedef void (*CallBack)(int num);
void call(CallBack func, int num);
call_back.c(生成call_back.lib)
#include "call_back.h"
void call(CallBack func, int num)
{
func(num);
}
hello_world.c
#include "hello_world.h"
#include <stdio.h>
void HelloWorld(int *num)
{
printf("%d.Hello World\r\n", *num);
}
hello_world.h
# include "call_back.h"
typedef struct { int x, y; } struct_test;
void HelloWorld(int *num);
运行 make_cdef.py 生成的 CDEF.txt 内容如下:
typedef void (*CallBack)(int num);
void call(CallBack func, int num);
typedef struct { int x, y; } struct_test;
void HelloWorld(int *num);
void PrintTest(void);