编译一个LISP文件,通常得到*.fas和*.lib文件,当LISP文件用到package FFI中的函数时,会生成一个*.c文件
clisp\clisp.exe -K full -c source.lisp
clisp\full\lisp.exe -M lispinit.mem -q -c source.lisp
source.lisp的内容:
(defpackage "test-ffi" (:use "FFI"))
(in-package "test-ffi")
(c-lines "#include <stdio.h>~%")
其中c-lines是包FFI中的一个函数,作用是输出一行到*.c文件。
source.c的内容:
#include "clisp.h"
extern gcv_object_t module__source__object_tab[];
#include <stdio.h>
subr_t module__source__subr_tab[1];
uintC module__source__subr_tab_size = 0;
subr_initdata_t module__source__subr_tab_initdata[1];
gcv_object_t module__source__object_tab[1];
object_initdata_t module__source__object_tab_initdata[1];
uintC module__source__object_tab_size = 0;
void module__source__init_function_1 (module_t* module);
void module__source__init_function_2 (module_t* module);
void module__source__fini_function (module_t* module);
void module__source__init_function_1 (module_t* module)
{
register_foreign_inttype("ssize_t",sizeof(ssize_t),(ssize_t)-1<=(ssize_t)0);
register_foreign_inttype("size_t",sizeof(size_t),(size_t)-1<=(size_t)0);
}
void module__source__init_function_2 (module_t* module)
{
}
void module__source__fini_function (module_t* module)
{
}
其中函数名称中的 __source__ 就取自LISP源文件的文件名。
clisp.h在clisp\linkkit目录中,LISP编译器自动生成的C代码中,用到此头文件中的函数,例如下面几个将C对象注册到LISP环境中。
extern void register_foreign_variable(void* address, const char * name, uintBWL flags, uintL size);
extern void register_foreign_function(void* address, const char * name, uintWL flags);
extern void register_foreign_inttype(const char * name_asciz, uintL size, _Bool signed_p);
clisp.h中还有module_t结构的定义
typedef struct module_t {
const char* name;
subr_t* stab;
const uintC* stab_size;
gcv_object_t* otab;
const uintC* otab_size;
bool initialized;
const subr_initdata_t* stab_initdata;
const object_initdata_t* otab_initdata;
void (*initfunction1) (struct module_t *);
void (*initfunction2) (struct module_t *);
void (*finifunction) (struct module_t *);
} module_t;
联系包FFI的使用说明,可以推测LISP和C对接的方法(个人猜测而已):
(1)编写一个source.lisp文件,描述C提供的函数,以及结构体,结构体通常用做函数参数。
(2)编译source.lisp文件,得到source.c文件
(3)将source.c和其它C代码放在一起编译,得到一个DLL文件
(4)运行LISP,加载source.lisp和DLL文件,便可以使用C提供的函数了
FFI的使用说明,在Common Lisp提供的说明文档impnotes.html中
32.3. The Foreign Function Call Facility