如何在Lua中包装一个C库:我如何创建嵌套的函数表?

与此问题相关的代码在这里:https://github.com/jchester/lua-polarssl/tree/master/src

目前,我正在尝试包装PolarSSL库的一部分(http://polarssl.org),以便我可以访问SHA-512 HMACs(luacrypto不提供此功能)。

我希望的API的形式为:

a_sha512_hash = polarssl.hash.sha512('text')

或者更完整地写为:

local polarssl = require 'polarssl'
local hash = polarssl.hash

a_sha512_hash = hash.sha512('test')

如果你参考上面链接中的 polarssl.c,你会看到我已经编写了包装 PolarSSL 代码的函数。然后我试图构建函数表,如下所示:

LUA_API int luaopen_polarssl( lua_State *L ) {
  static const struct luaL_Reg core[] = {
    { NULL, NULL }
  };

  static const struct luaL_Reg hash_functions[] = {
    { "sha512", hash_sha512 },
    { "sha384", hash_sha384 },
    { NULL, NULL }
  };

  static const struct luaL_Reg hmac_functions[] = {
    { "sha512", hmac_sha512 },
    { "sha384", hmac_sha384 },
    { NULL, NULL }
  };

  luaL_register( L, CORE_MOD_NAME, core );
  luaL_register( L, HASH_MOD_NAME, hash_functions );
  luaL_register( L, HMAC_MOD_NAME, hmac_functions );

  return 1;
}

其中 CORE_MOD_NAME = 'polarssl',HASH_MOD_NAME = 'polarssl.hash',HMAC_MOD_NAME = 'polarssl.hmac'。

当我运行类似于本问题顶部的Lua代码的测试脚本时,我得到以下结果:

lua: test.lua:23: attempt to index global 'polarssl' (a nil value)
stack traceback:
    test.lua:23: in main chunk
    [C]: ?

我尝试寻找实现这种模块.子模块方法的示例(例如 naim vs luasockets),但似乎每个人都有不同的实现方式。我完全迷失了。

原文链接 https://stackoverflow.com/questions/9527417

点赞
stackoverflow用户734069
stackoverflow用户734069

那就是 Lua,每个人都有自己的方式。这是 Lua 的最大优点和最大弱点:语言提供机制,而不是 _策略_。

你需要做的第一件事就是停止使用 luaL_register。是的,我知道它很方便。但你想要特别的东西,而 luaL_register 无法帮助你获得它。

你所想要的是创建一个包含一个或多个函数的表。所以 …… 就这么做吧。

创建一个表。

lua_newtable(L);

很容易。该函数将一个表推送到堆栈上,所以我们的堆栈现在有一个表在其顶部。这是我们将要返回的表。

现在,我们需要创建一个新表来放在旧表里。

lua_newtable(L);

同样很容易。接下来,我们要把要放入该表中的函数推入堆栈。

lua_pushcfunction(L, hash_sha512);

所以堆栈有三个东西:目标表,"哈希"表(我们将在下文中"命名"它),以及我们想要放进 "哈希"表中的函数。

那么就把这个函数放入哈希表中吧。

lua_setfield(L, -2, "sha512");

这会将堆栈上最顶部的东西取出,并将其设置为名为 "sha512" 的字段,该字段所在的是堆栈上从-2开始的表。这就是我们的"哈希"表。该函数完成后,它会从堆栈上移除顶部项目。这将把我们的"哈希"表放在顶部。

我们可以重复第二个函数的这个过程:

lua_pushcfunction(L, hash_sha384);
lua_setfield(L, -2, "sha384");

现在,我们想将"哈希"表放入要返回的表中。这可以通过另一个 lua_setfield 调用轻松完成:

lua_setfield(L, -2, "hash");

记住:这个函数将_任何_在堆栈顶部的东西取走。此时,我们要返回的表(也将是我们的模块表)位于堆栈上。

我们可以为"hmac"表重复此过程:

lua_newtable(L); //创建"hmac"表
lua_pushcfunction(L, hmac_sha512);
lua_setfield(L, -2, "sha512");
lua_pushcfunction(L, hmac_sha384);
lua_setfield(L, -2, "sha384");
lua_setfield(L, -2, "hmac"); //将"hmac"表放入我们的模块表中

该模块表现在有两个条目:"哈希"和"hmac"。两者都是具有两个函数的表。

我们可以用以下代码将其放入全局表中:

lua_pushvalue(L, -1);
lua_setfield(L, LUA_GLOBALSINDEX, "polarssl");

并非每个模块制作者都想这样做。有些人更喜欢强制使用 local polarssl = require "polarssl" 语法,以避免污染全局命名空间。这取决于你。

但无论如何,你必须_返回_此表。从你的 luaopen 函数中返回 1,以让 Lua 知道有一个返回值。上述的 lua_pushvalue 调用仅用于复制表(记住:表是引用的,因此就像复制指针一样)。这样,当你使用 lua_setfield 时,副本就从堆栈中被移除,而原始的表仍然可以用作返回值。

2012-03-02 04:17:33
stackoverflow用户221509
stackoverflow用户221509

虽然与问题不直接相关,但以下陈述并不完全正确:

目前我正在尝试包装 PolarSSL 库 (http://polarssl.org),以便我可以访问 SHA-512 HMAC(luacrypto 不提供此功能)。

我不知道您所指的 LuaCrypto 版本是哪个,但是此 LuaCrypto 分支 确实提供了 SHA-512 HMACs,还自动支持 OpenSSL 支持的任何其他摘要类型。只需将 "sha512" 作为摘要类型传递给 hmac.digest

hmac.digest("sha512", message, key)

文档仅说明了支持的部分摘要类型,完整列表可以通过调用 crypto.list("digests") 来检索。

table.foreach(crypto.list("digests"), print)

想想看,即使是原始的 LuaCrypto 应该也支持 SHA-512。

2012-03-02 18:07:15