Racket ffi
_今天花了些时间了解了Racket的FFI用法,只是初步的了解.所谓的FFI是指 foreign fuction interface.ok FFI让racket程序可以调用基于c的api而不用去写一行的c.
以下内容大部分来自对于这篇文章的翻译,当然不会全是完全一样,其实我也有自己的私心—学好一样东西最好的办法就是将他教授给别人.
学习FFI最好的方式是去看文档.但是对于一个初学者来说文档的信息量可能太大.
这篇教程会手把手地教会你关于FFI的一些使用,你需要准备的就是在你的电脑上安装好Drracket.
在开始之前,先声明一件事情.感谢Eli Barzilay和Dmitry Orlovsky的工作让我们可以在racket中使用FFI.如果你对于FFI的设计实现好奇的话可以参考这篇论文.
这篇教程主要会使用 Cairo图形库,主要是因为它是和Racket一起捆绑安装的.
我们的目标就是用racket复刻Cairo官网上的样例
为了实现上述c代码所具有的功能,我们需要做一些准备工作.
首先需要导入FFI
接下来就是导入Cairo库了
提取函数
在cairo的链接库中存在这样的api接口
现在就可以用ffi将cairo_create转换为racket的函数,让我们可以在racket调用
get-ffi-obj拿到函数的名字和它所在的库就可以拿到这个函数了,但是并不知道这个函数的调用参数.最后的那部分就是说明cairo_create的参数和返回值的 -> 的作用只是分隔参数的返回值
到这里对于ffi就有一个大致的了解了
_pointer是导入FFI之后就可使用的,对应的是c中的指针,类似的基本数据类型都有对应,例如_int
,_double等等.
只有_pointer类型的话也带来了一个问题,你很容易将不同的指针类型搞混,毕竟™都是指针.
插曲 类型安全
先定义一下指针类型,再去使用他们
用新的指针类型来定义cairo_create
使用宏来减少重复劳动
有了上面的经验,接下来就可以实现其他的函数,将我们要用到的函数通通转化到Racket可以调用的形式
那么就从 cairo_move_to下手好了,就像之前那么做
似乎每次都要写一遍 (get-ffi-obj xxx cairo-lib (…)),实际上ffi提供了define-ffi-definer来简化函数的定义
如果你喜欢原来的函数名子的话定义还可以更加简单
接下啦如法炮制
比较有意思的是cairo_set_line_cap,它的参数中出现了cairo_line_cap_t,这是一个枚举对象.Rackt的FFI可以让你方便的定义枚举对象
这里的符号并不重要,因为他们会与一个整数对应(其实我不太明白,也许枚举类型会有一个编号,这些符号最终也只是这些编号的助记符).有了这个枚举类那么cairo_set_line_cap也就可以轻松的定义出来了
ok,看看我们都完成了些什么
在这里我们用cairo的函数库已经绘制到bt中了,now看看结果吧
没有什么意外的话会看到
现在将完整的代码放在下面
ok了,第一部分就这样.