创建二进制扩展模块 |
|
Lua 5.0 引入了 'loadlib' 函数,它允许 Lua 在运行时加载二进制扩展(实现是特定于平台的)。本文档展示了一个扩展模块的简单示例,并展示了如何在 Windows 下构建 Lua 以用于扩展模块。
在 Windows 下,'loadlib' 是根据 DLL(动态链接库)实现的。以下是一个提供名为 'msgbox' 的 Lua 函数的扩展 DLL 的完整源代码
#include <windows.h> #include "lauxlib.h" /* Pop-up a Windows message box with your choice of message and caption */ int lua_msgbox(lua_State* L) { const char* message = luaL_checkstring(L, 1); const char* caption = luaL_optstring(L, 2, ""); int result = MessageBox(NULL, message, caption, MB_OK); lua_pushnumber(L, result); return 1; } int __declspec(dllexport) libinit (lua_State* L) { lua_register(L, "msgbox", lua_msgbox); return 0; }
在将其构建到 Windows DLL(msgbox.dll)中后,您可以在 Lua 脚本中像这样使用它(省略了错误检查)
libinit = loadlib("msgbox.dll", "_libinit") libinit() msgbox("Hey, it worked!", "Lua Message Box")
它使在运行时向支持 Lua-5.0 的应用程序添加扩展变得容易——无需重新构建甚至重新启动应用程序——这是一个非常方便的功能。但是,我忽略了一个重要的细节。
在构建扩展时,链接器必须解析 Lua/Luax API 函数(如 'lua_pushnumber' 或 'luaL_checkstring')的地址。如果这些函数存在于宿主应用程序(如 lua.exe)中,我们无法链接扩展模块。我们必须将 Lua API 移动到 DLL 中,以便宿主应用程序和扩展 DLL 可以共享相同的 Lua API 代码副本。
[* 更正:在 Windows 下,可以从 exe 文件导出函数,就像它是一个 dll 一样。因此,您可以从 lua.exe 导出函数(使用以下说明)并使用生成的导出库链接到新的 DLL *]
[* 如何?以下说明不起作用。在原型中使用 __declspec(dllexport) 不会导致这些函数从可执行文件中导出。我该怎么办? *]
[* 在 Windows 下,您不会从 exe 文件导出。虽然从技术上讲这是可能的,因为它们具有相同的格式,但您永远不会以这种方式设计 Windows 应用程序。将 lua 放入 DLL 中,设置 -DLUA_API=__declspec(dllexport),然后将生成的 lib 链接到您的 exe 和其他 DLL(如本页面所述),是正确的方法。顺便说一句,您可以*使用 implib 在 exe 文件上获取 .lib 文件,然后像使用普通 .lib 文件一样使用它们。 *]
这些说明适用于 Borland 的出色(且免费)Windows 命令行 ANSI C|C++ 编译器 [在此下载]。
从 Lua 发行版的根目录开始
lua-5.0.2> bcc32 -elua.dll -WD -Iinclude;C:\Program\borland\Include -LC:\Program\borland\lib -DLUA_API=__declspec(dllexport) src\*.c src\lib\*.c lua-5.0.2> implib lua lua.dll
这将提供给我们 lua.dll
,其中包含 Lua API 和标准库;以及 lua.lib
,一个导入库,我们可以将其静态链接到其他应用程序,以通过 lua.dll
为它们提供对 Lua API 的访问权限。
注意:__declspec(dllexport)
是 Microsoft 语言扩展(Borland 支持),它简化了 DLL 的创建和使用。它消除了提供“模块定义文件”的需要,该文件显式枚举了我们的 DLL 导出的每个函数。LUA_API
宏使我们有机会将 __declspec(dllexport)
插入到每个 Lua API 函数的函数原型中,自动将它们从生成的 DLL 中导出。
例如,要构建 lua.exe
(在 Lua 发行版中)的版本,以便它使用 lua.dll
,我们可以这样说(从发行版的根目录开始)
bcc32 -elua.exe -Iinclude -DLUA_API=__declspec(dllimport) lua.lib src\lua\*.c
注意,我们将 LUA_API
更改为 '__declspec(dllimport)',并将 lua.lib
链接进来。现在 lua.exe
将在运行时从 lua.dll
动态链接 Lua API 代码。
假设 msgbox.c
(上面)是 Lua 发行版的根目录
bcc32 -w -tWD -Iinclude -DLUA_API=__declspec(dllimport) lua.lib msgbox.c
同样,我们将 LUA_API
设置为 '__declspec(dllimport)' 并链接 lua.lib
。就这样。现在我们有了 msgbox.dll
,一个可与 'loadlib' 一起使用的二进制扩展。
构建二进制扩展并使用 loadlib 很容易,但我们必须确保 Lua API 在它自己的 DLL 中,以便宿主应用程序和任何扩展模块都可以共享它。