Lua 二进制模块

lua-users home
wiki

此处的约定、文档和代码是 ThatcherUlrich 提出的用于 Lua 的“社区标准”二进制模块系统的提案。将其视为“alpha”版本,可能会发生变化。请将评论和批评发送到 Lua 邮件列表。

版本说明:此页面适用于使用 loadmodule 扩展的早期版本的 Lua(4.0 和 5.0beta)。Lua 5.1 使用 package.loadlibrequire。Lua 5.0 使用 loadlib。)

注意:LuaCheia 是一个可移植的、维护的 Lua 5.0 发行版,它包含并依赖于此处启动的 loadmodule 支持。

此页面包含一个针对 Lua 4.0.1 的补丁,该补丁将 loadmodule 函数添加到默认的 Lua 解释器中。此页面还列出了一些可以使用 loadmodule 加载的二进制模块。这些二进制模块可以通过本机代码扩展默认 Lua 解释器的功能,而无需重新编译任何内容。这使得最终用户可以非常轻松地访问有用的库,尤其是库的组合,否则需要为所需平台重新编译源代码。


带有 loadmodule 的 Lua 4.0.1

需要修改后的解释器才能使用此页面上列出的二进制模块。源代码和二进制文件链接在下面。此代码主要由 IgnacioCastano 编写。它由 ThatcherUlrich 稍微修改。

源代码

[lua-4.0.1-loadmodule.patch]

要应用补丁:将正确的 Lua 发行版解压缩到一个干净的目录中。执行 cd 到目录的顶部并运行 patch。例如,假设您将 lua.tar.gz 和上面的补丁文件保存在 ~/src 中

        cd ~/src
        tar -xzvf lua.tar.gz
        mv lua-4.0.1 lua-4.0.1-loadmodule
        cd lua-4.0.1-loadmodule
        patch -p1 < ../lua-4.0-loadmodule-2002-11-21.patch

在构建之前,请务必查看 config 文件,以确保选项已针对您的平台设置。

二进制文件

下面的二进制文件是使用标准 Lua 4.0.1 发行版编译的,并添加了上面的补丁。下载并按原样使用。

[GNU/Linux-i386] | [Win32] | Mac | *BSD | Solaris

用户说明

在您的 Lua 脚本中,执行

loadmodule("modulename")

这将动态加载模块中的代码,并初始化与 Lua 的绑定。有关如何从 Lua 使用它的详细信息,请参阅每个模块的文档。

loadmodule 函数返回两个值。一个布尔值,用于确定 loadmodule 是否成功,以及一个字符串,用于描述库(如果成功)或描述错误(在其他情况下)。

ok, str = loadmodule "modulename"

if not ok then
	error( str )
else
	print( "using " .. str )
end

或者在大多数情况下,你会这样做

assert( loadmodule "modulename" )

如果 modulename 不存在,它将打印

error: assertion failed! cannot load module 'modulename'

库命名约定

Lua 库被假定以 'lua' 为前缀,以区分包装库及其被包装的对应库。因此,当你执行

loadmodule("SDL")

你正在加载 luaSDL 库。此外,每个平台都有自己的命名。目前,loadmodule 在 Win32 和支持 DLFCN 的系统(Linux、OSX 和大多数 UNIX 变体)下受支持。

例如,在 Win32 上,库具有 '.dll' 扩展名,因此 luaSDL 的库名称将是

luaSDL.dll

而在 Linux 系统上,它将是

libluaSDL.so

但是,在你的 lua 脚本中,你不需要关心系统约定,你只需要执行:loadmodule("SDL")

库搜索路径

库搜索路径取决于系统。

Linux 按以下顺序搜索库

SunOs? 按以下顺序搜索库

Windows 按以下顺序搜索库

此外,luamodule 在预定义的搜索路径之前,会在自定义路径中查找模块。该路径由全局键 LUA_LIBPATH 设置。如果该键不存在,则自定义路径将在 LUA_LIBPATH 环境变量中查找。这应该允许你使用比系统上安装的版本更新的库版本。

模块作者指南

导出函数

Lua 二进制模块是一个平台特定的共享库(例如,大多数 Unix 系统下的 .so,或 Win32 下的 .DLL),它导出这两个特殊函数

    const char* luaLM_version(void);
    int luaLM_import(lua_State* L);

函数 luaLM_version() 应该返回您的模块编译时使用的 LUA_VERSION 的值;例如,它通常应该在您的源代码中看起来像这样

	const char* luaLM_version(void)
	{
		return LUA_VERSION;
	}

loadmodule 首先调用此函数,以确保二进制模块与正在加载它的 Lua 解释器兼容。

函数 luaLM_import(lua_State* L) 是由 loadmodule 调用以实现您的绑定的函数。在这里,您使用常规的 Lua API 将模块的函数和变量绑定到给定的 lua_State

命名空间

强烈建议您将所有绑定放在命名空间中。也就是说,您绑定到 Lua 的所有函数和值都应该包含在一个表中。有关 Lua 命名空间的解释,请参阅 LTN7 [1]。建议此表的名称与您的模块名称相对应。例如,由 loadmodule("SDL") 加载的 luaSDL 模块将其所有绑定放在名为“SDL”的表中。如果需要,用户可以自由地为该表分配不同的名称,以方便使用。

注意:loadmodule 不强制使用命名空间。但如果您坚持使用它们,您的用户可能会更高兴。

待办事项:解释为什么模块中的静态状态很危险

待办事项:使用 tolua 的建议和示例

简单教程

可以在 BinaryModuleTutorial 中找到。它描述了一种将任何给定的 Lua 扩展转换为 loadmocule 准备好的动态链接库的方法。

模块作者:将您的模块添加到下面的列表中,并附上简短说明。包含指向维基或网页的链接,用户可以在其中获取模块的完整描述,并下载模块二进制文件(以及源代码,如果可用)。


二进制模块

以下是可与上述解释器一起使用的二进制模块列表。(这些模块中的许多也可以通过为您的平台编译源代码并与您自己的自定义解释器进行静态链接,以更传统的方式集成到 Lua 中。)


''是否可以成功返回模块自身的版本信息?例如,现在 loadmodule("fuzzy") 打印 "using fuzzy";也许 "fuzzy-x.yy.zz" 更适合版本依赖的使用?或者... 返回一个 "Info" 表,其字段为开发者、版本、许可证、描述等。'' -Hakki Dogusan

我更新了源代码补丁:添加了一些 Makefile 更改以更好地支持 Linux .so 文件。.so 文件和可执行文件现在都附加了 $(V)(因此解释器为 lua-4.0,主库为 liblua-4.0.so)。还有新的二进制文件,一个包含可执行文件和 .so 文件的 tarball。 - ThatcherUlrich

Thatcher:补丁中有一些错误,如果你更改了静态库的名称,你也必须更改 src/Makefile 和 src/lib/Makefile 中的目标。你已经删除了 .def 文件。你实际上可以通过在 Makefile 中注释一行并重新定义 LUA_API 和 LUALIB_API 来生成它们,但我认为直接使用给定的 def 文件而不做任何更改更容易。如果有人在使用新补丁时也遇到问题,之前的补丁仍然在这里: [补丁].- IgnacioCastano

我已经上传了一个 [zip],其中包含我当前的 lua-loadmodule 树的所有源代码和项目文件。 -MartinSpernau

我已经修改了 loadmodule,使其在检查版本时忽略修订号。这是新的 [补丁]。如果没有人报告任何错误,我将在几天后更新上面的链接.- IgnacioCastano

这里有一个用于 lua-5.0-beta 的新补丁: [补丁]。它还没有完全测试,所以请谨慎使用.- IgnacioCastano

用于 lua-5 的 loadmodule 添加非常棒;我正在使用它来制作一个 lua-5 LuaSqlite 可加载的二进制模块。但是,如果语义与 [Import (TN11)] 相同,岂不是更好?这将使模块对全局命名空间的依赖性降低。

说实话,我认为 LTN11 引入了复杂性来解决实际上在实践中并不存在的问题。事实是,模块需要唯一的名称,所以我认为直接解决名称冲突,并坚持 LTN7 约定会更清晰。 -ThatcherUlrich

恕我直言,我认为 LTN11 引入了很少(如果有的话)复杂性,并解决了一些问题——尽管这些问题可能不是每个人的问题。例如,它允许同时使用同一个接口的两个实现(如果你愿意,可以是同一个模块的两个版本),这对测试非常有用。它还使模块沙箱化更加实用,并且它开辟了拥有具有内部状态的模块的多个实例的可能性(例如 readline 或 Lua 本身)。从 C 的角度来看,“额外的复杂性”仅仅是模块打开函数使用作为参数提供的表,而不是直接将其添加到全局命名空间中;该表本身由包系统提供。 -RiciLake


最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2009 年 12 月 24 日下午 5:11 GMT (差异)