编译器插件(1)

一个语言的编译器往往都支持所谓的 plugin,它们存在的理由大概是编译器本身是一个非常复杂的东西,如果只能借助它完成语言的翻译(一种语言到另一种语言),有点大材没有尽用。因此通过 plugin 可以为高端用户提供一次搭顺风车的机会。我们这里简单的看三个例子,算是初来练手了。

这里我们先看 protobuf 的 plugin。作为一个定义数据类型的语言,它可以为多种语言生成数据在该语言中的类型、容器,并提供对应 serialize/deserialize 的代码。那么在处理 protobuf 的定义过程中,我们怎么建立一个 plugin 呢?

一个简单的 python plugin 可以参看这里,最核心的部分就是将 CodeGenerationRequest 转换到 CodeGenerationRequest 对象的过程。这最终是一个 binary,通过 –plugin=protoc-gen-NAME 传递给 protoc,同时可以指定 –NAME_out 作为 plugin 的输出。比较有意思的是我们可以看到,在 traverse proto 文件的过程中我们实际是通过 proto 的 descriptor API 来判断处理的是什么类型的信息。这跟我们使用 reflection API 来操纵 proto 是非常类似的。

比较复杂的 plugin 我们可能还是希望使用 C/C++ 来实现,这部分一般通过 plugin.h 提供的 API 来完成。

试想如果我们希望为每个被标注过的 message 类型生成一些额外的 C++ 代码,比如将某个 proto message 关联到某个类,这样可以提供一些额外的 accessor 方便我们使用,那么我们大致如何处理这样一个事情呢?

  • 引入我们自己的 options,在 message 里面通过诸如 binding_class 指定一个需要生成的 C++ 类
  • 为我们生成的 binding class 提供一个公用的基类,这样可以减少一些重复性的代码,很显然这个会使用 CRTP
  • plugin 的实现其实挺直接,拿到 message 看有没有我们的 options,有的话就写 CodeGenerationResponse

又比如说,如果我们需要为 proto 定义的数据提供一个 query engine,某些数据其实可以通过 options 标注其表达(比如 uint64 可能是一个 timestamp 而通过 query 显示出来的时候可能就当个日期显示比较合理)。我们是否也可以通过 plugin 来 customize 这些 field 对应的 rendering 的代码呢?

通过这个例子我们可以清楚的看到一个 compiler 的 plugin 本身就是在 inspection 过程中嵌入的一些 user hook。对于更加复杂的 compiler/language,这个 plugin 获得的功能会更加广泛。

Advertisements
编译器插件(1)

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s