« 数学运算模块的改进 | 返回首页 | 不同虚拟机间共享不变的 Table »

为 bgfx 设计了一个 IDL

上个月为 bgfx 贡献了一周多的工作时间,起因是 bgfx 的作者在我的 sproto 项目下发了个 issue (现在已经转到 bgfxidl 项目下)。他想为 bgfx 的接口设计一个 Interface Description Language ,这样可以避免手工维护多语言接口文件,还可以方便做许多代码生成的工作。

我在 2006 年左右尝试利用 COM 的 IDL 做过一些工作,想来这和 COM 面临的问题是一样的。我认为 lua 是一个可以用来做 DSL/IDL 非常好的工具,所以我向 bgfx 项目推荐了它。而且 bgfx 用的构建工具 Genie 就是基于 lua 的,这样工具链就比较统一。

一开始的需求仅仅是生成 C99 的 API 描述 .h 文件。lua 的函数调用,如果只有一个参数,且参数类型字符串常量或表,可以省略括号。这使得它的语法天生适合做数据描述语言,所以我给了这么一个方案:

func.createShader
    "ShaderHandle"
    .mem "const Memory*"

这样就定义了一个函数 createShader ,返回值为 ShaderHandle ,参数为 mem 其类型为 const Memory * 。一开始我觉得也就是一个下午的事情,在周末哄小孩午休后,就花了半天时间搞定了基本功能。

可能是做的太顺利,需求接踵而来。在接下来的一周多时间,我们增加了 Enum 定义、struct 定义、类方法定义、函数参数默认值、等等特性。

idl 的功能也不限于生成 C/C++ 的 .h 文件,还自动生成了 C 的 bindings 函数。其中,像 handle 这样的, bgfx 自己特别定义的特殊类型的转换部分是最麻烦的。

另一个麻烦的东西是代码注释。我们希望在 IDL 里维护接口文档,又希望在生成的代码上也能看到漂亮的 Doxygen 风格文本。Lua 原有的语法有点不够用。

经过几次修订,我最终定下的方案是,使用 Lua 的中括号风格的长字符串来书写文档。但又额外提供一个模块,在 Lua 文件被加载前,可以把源码中的三个减号开头的单行注释全部转换为长字符串。两种方案可以共存。如果不使用文档预处理模块,那么注释可以被自然忽略掉,使用的话,就把文档加入 IDL 的数据结构中,供代码生成器调用。

现在,IDL 语法看起来丰富多了。这里可以看到 bgfx api 的完整 IDL 描述

最终的 IDL 变成了一个上千行代码的小型项目。它在这里 ,和 bgfx 使用一致的 License 。虽然这个项目是为 bgfx 深度定制的,但我认为核心模块可以被其它有 IDL 需求的大项目借鉴。


目前,bgfx 的接口文件已经完全由代码生成了。btw, bgfx 的作者还特别嘱咐我来提交相关内容的 PR ,再合并。他希望我的工作可以反应在最终 bgfx 的仓库里。

下一步,bgfx 会利用代码生成器生成一个动态库的封装,把所有 api 通过一个单一接口加载,并提供 api 调用的 log 功能。python 的 bindings 也会逐步从手工维护转移到利用 IDL 做代码生成。


bgfx 的作者也写了一篇关于它的 blog

Comments

Cehis
感觉能写 数学运算模块 都是技术大神,好厉害
漂亮的工作, 为两个大牛点赞!👍

Post a comment

非这个主题相关的留言请到:留言本