以自定义方式加载 lua 模块[云风blog]
今天我们的一个小项目开始做内部测试发布前的资源打包。这个项目基本上是用 lua 做开发的。整个开发过程中,我们的代码是直接把 Lua 源代码放在项目的发布目录下的。发布版因为安全或是整洁等种种原因,我们必须给所有的脚本代码打包。
这种事情以前在大话2 里也干过,当时用的 lua 4.0 而且也没多少经验,我们是直接去修改的 lua 的代码,适应我们的打包格式。这次,不想这么干了。希望能够完全不动 lua 官方发布的源代码,来最终完成这项工作。
简单分析了一下,发现实现起来非常简单:
从 Lua 5.1 以后,Lua 有了标准的模块管理库。所以所有的模块加载都是通过 require 来完成。 require 的设计是颇具扩展性的,它会从若干个定义好的 loader 中逐个尝试加载新的模块。系统库中提供了四个 loader ,分别实现已加载模块,Lua 模块,和 C 扩展模块(用了两个 loader 来实现 C 扩展模块的加载)。这些 loader 以 CFunction 的形式放在 require 的环境中的一个 table 里。
如果我们想改变 lua 模块的加载形式,只需要替换或增加一个新的 loader 就可以了。
要做的只需要模仿 loadlib.c 中的 loader_Lua
函数做一个自己的实现,比如在我们的项目中,就允许从自定义格式数据包中,加载一个被加密过的 Lua 代码文件。然后写几行 C 代码,获得 require 的环境(使用 lua_getfenv
),然后取出其中 "loaders" 这个 table ,把新的自定义 loader 插入到 index 2 的地方。
具体的代码就不详述了,仔细阅读一下 ll_require
的实现(在 loadlib.c 中)就很容易明白。我们的整个工作从分析到实现没有超过两个小时,这真是得益于 Lua 良好的设计啊 :D 甚至如果你想从一个网络连接的数据流中加载 Lua 模块,或是通过 http/ftp 协议下载,也是行的通的吧。