使用Common-Lisp调用C语言函数

前言

我们知道在emacs实现中使用的lisp和c语言。这个设计使得emacs成了一件不折不扣的艺术品。这样的好处是将两种语言的长处发挥到了极致。当然其中还有一些设计哲学要去学习。不过我们先看看在common lisp中调用到c语言的函数。

我的环境

  • MacOS
  • SLIME (emacs + spacemacs 配置)
  • mac自带的gcc
  • quicklisp

以上这些的教程都可以在我之前的博客中找到,我就不写传送门了。

准备过程(其中可能有方法论)

接触这个问题的过程是从我希望使用common lisp写出GUI来开始的。那么我有什么路可以走呢?自己写一个图像化接口几乎是不可能的。其实如果哪天我疯了或许会开始这样的一个项目:P 那么现在有一条路可以走,就是调用已经有的跨平台图像化接口。第一个想到的竟然是openGL,额。尴尬的是OpenGL来做这个活并不是很开心。而且在我面前还有一个重要的问题,那就是怎么用CL调用到C语言实现的文件。(动态和静态链接库)
于是我百度谷歌使用CL调用C语言函数,结果有一个人问:用cffi和ffi那个好?额。这个是什么呢?结果一查我发现这个是Common Foreign Function Interface的缩写。外部函数接口。这个不就是我想要的吗?简单的看一下英文这个不就有C的支持吗~于是欣喜若狂,的打开了文档。这里有传送门
所以让我们写一个小的demo来调用,自己使用c写的一个测试方法吧。

完成c文件

新建一个项目。建立一个叫做testlib.c的文件。现在我们就定义一个简单的函数吧。如下:

1
2
3
4
5
6
7
8
#include <stdio.h>
#include <stdlib.h>
#define MIX 100
int test_fn(int x){
return MIX;
}

要记住我们是没有办法直接使用c语言的源码的。我们需要先编译了才可以了。运行下面的命令就可以生成必要的文件了。

1
2
3
$ gcc -c testlib.c
# 这将生成 .o 文件 然后我们要的是 .so 文件
$ gcc -shared -fPIC -o testlib.so testlib.o

使用common lisp 来调用这个文件

现在在同级的目录下建立一个叫做test.lisp的文件。文件里的内容如下:

1
2
3
4
5
6
7
8
9
10
11
;; test cffi
(ql:quickload "cffi")
(cffi:define-foreign-library testlib
(:unix "testlib.so")
(t (:default "testlib")))
(cffi:use-foreign-library testlib)
(cffi:defctype back-max :int)
(cffi:defcfun "test_fn" back-max
(x :int))

简单的介绍一下这些代码在做什么。define-foreign-library是在定义一个C语言的库。这个方法用来指定库的位置和在不同环境中的位置。然后use-foreign-library加载这个库。现在直接调用时调用不到的。我们需要定义这个c中的函数到lisp中,同样要定义好入参和出参的值。
现在SPC-m-'打开一个REPL,然后逐条的对上面的语句使用C-c C-c。如果没有错的话现在就可以调用这个函数了。
我们在REPL中输入(test_fn 1)就可以看到返回了我们在c中定义好的100了。

Learn More

现在就可以写我们自己的c语言的函数,然后使用lisp优雅的调用他们。但是单单是我上面的介绍肯定远远不够。我们还需要在必要的时候阅读上面传送门中的文档才行的

写在最后

我本来是想在这个过程中使用lisp调用有名的gtk。虽然我现在还是不了解那是个啥。安装也没有成功。但是并不影响我在成功调用到c语言时的激动。相信我可以使用CL的这个功能在以后带来更加精彩的应用。谢谢读者们。

我将一直的迷惑与无知,我是黄油香蕉君,再见。

给作者买杯咖啡吧。喵~