1

I wrote a simple C plugin for Lua:

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

static int bar (lua_State *L) {
  double arg1 = luaL_checknumber(L, 1);
  double arg2 = luaL_checknumber(L, 2);
  lua_Number res = arg1 + arg2;
  lua_pushnumber(L, res);
  return 1;
}

int luaopen_foo (lua_State *L) {
  static const struct luaL_Reg foo [] = {
    {"bar", bar},
    {NULL, NULL}
  };
  lua_newtable(L);
  luaL_setfuncs(L, foo, 0);
  lua_setglobal(L, "foo");
  return 1;
}

The code is compiled successfully with this GCC command:

gcc -W -Wall -g -fPIC -shared -I/usr/include/lua5.3 -o foobar.so foobar.c

In a Lua 5.3 REPL, I'm able to find and import the module successfully as well, but the returned value of the function call is always nil:

root@b1898c1cc270:/# lua5.3
Lua 5.3.3  Copyright (C) 1994-2016 Lua.org, PUC-Rio
> local foo = require "foo"
> local res = foo.bar(3.0, 6.0)
> res
nil

No errors are thrown and since I'm able to printf the result in the C code before returning the value, I know the code is called and the result calculated successfully.

Any ideas?

Edit1: By not using local variables I get this stack trace instead of a nil value:

root@d7340c919be4:/# lua5.3
Lua 5.3.3  Copyright (C) 1994-2016 Lua.org, PUC-Rio
> foo = require "foo"
> res = foo.bar(3.0, 6.0)
stdin:1: attempt to call a nil value (field 'bar')
stack traceback:
    stdin:1: in main chunk
    [C]: in ?
m_vdbeek
  • 3,704
  • 7
  • 46
  • 77
  • 1
    Don't use `local` in an interactive interpreter session. – siffiejoe Apr 06 '18 at 10:10
  • 1
    Also, `lua_setglobal` pops your module table from the Lua stack, so you can't `return 1` from your `luaopen_foo` function unless you duplicate the stack slot first with `lua_pushvalue`. – siffiejoe Apr 06 '18 at 10:18
  • @siffiejoe Thanks for the quick answer. I edited my question with a stack trace I get when not using local variables. Any reasons to not use them in the interpreter (just being curious)? I'm using `lua_setglobal` because I thought this was the correct way to register a module in 5.3 since `register` and `lua_register` was deprecated in 5.2. How should the module be registered normally? – m_vdbeek Apr 06 '18 at 10:29
  • `lua_open` and `lua_register`* – m_vdbeek Apr 06 '18 at 10:37
  • Regarding locals in the interactive interpreter see [this answer](https://stackoverflow.com/a/24901202). – siffiejoe Apr 06 '18 at 12:28
  • 1
    Regarding modules: It is customary to not set globals in Lua modules any more but to use the return value of `require` (and thus of the `luaopen_*` function). So `lua_newtable` + `luaL_setfuncs` is fine, as is using `luaL_newlib` (which is roughly equivalent to the combo above). But if you want to set a global *and* return the module table from the `luaopen_*` function, you have to duplicate it on the stack first. – siffiejoe Apr 06 '18 at 12:35

2 Answers2

3

luaL_setfuncs just registers your functions into a table.

Instead, use luaL_newlib. It creates a new table and registers your functions there. Then you need to push the table on to lua stack.

luaL_newlib (L, foo);
return 1;
Ravi
  • 986
  • 12
  • 18
1

As to what's causing the error, lua_setglobal pops the library table from the stack, so that luaopen_foo does not return it. Then (though I don't understand why) require "foo" returns the file path of the library (a string) instead, and the field ("foo_filepath").bar is nil.

So, removing the call to lua_setglobal fixes the problem, even if you do not use the library-creating macro luaL_newlib as Ravi recommends.

To set the library table as global foo and return it from require, you have to push a second copy of the table to the stack with lua_pushvalue(L, -1) before doing lua_setglobal(L, "foo"), leaving the original copy of the table to be returned by luaopen_foo.

cyclaminist
  • 1,697
  • 1
  • 6
  • 12
  • 1
    Quote from the [`require` manual entry](http://www.lua.org/manual/5.3/manual.html#pdf-require): "Once a loader is found, require calls the loader with two arguments: modname and an extra value dependent on how it got the loader. (If the loader came from a file, this extra value is the file name.)". So the `luaopen_*` function starts with those two values on the stack. Once the module table is popped by `lua_setglobal`, the file name is the top-most element that's left on the stack. – siffiejoe Apr 06 '18 at 22:33