2

I want to call an external lua_5.2 function from C, so I made a minimal example to try it out.

The minimal testfile:

--- filename: play.lua
function hello()
    print("Hello World!\n")
end

Trying to call this function from C:

#include <stdio.h>
#include <stdlib.h>

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


int
main(void) {
    lua_State *L;
    int status;
    int result;

    L = luaL_newstate();
    luaL_openlibs(L);

    status = luaL_loadfile(L, "play.lua");
    if (status != LUA_OK) {
        fprintf(stderr, "Could not load 'play.lua'!");
        exit(1);
    }

    lua_getglobal(L, "hello");
    if (lua_isfunction(L, -1)) {
        fprintf(stderr, "ERROR: Not a function!\n");
        exit(1);
    }

    result = lua_pcall(L, 0, 0, 0);
    if (result!= LUA_OK) {
        fprintf(sterr, "Error running lua: %i\n", result);
        exit(1);
    }
    fprintf(stdout, "lua ran fine\n");
    lua_pop(L, lua_gettop(L));

    lua_close(L);
    return 0;
}

Calling that executable results however in LUA_ERRUN (2)

Error running lua: 2

I am not quite sure what I am doing wrong here, and the documentation is a little bit opaque to me -- according to the 5.2 reference manual I am using pcall correctly (function with zero args and zero return vals), and I apparently grabbed the function from the stack correctly (otherwise they earlier error would have shown).

Any idea what I am doing wrong?

Oka
  • 23,367
  • 6
  • 42
  • 53
kollie
  • 86
  • 5
  • Try `luaL_dofile` instead of `luaL_loadfile`. which only loads but does not run a script. – lhf Jul 03 '23 at 15:05
  • Possible duplicate of https://stackoverflow.com/q/32873597/107090 – lhf Jul 03 '23 at 15:06
  • 1
    The actual error message gets pushed to the stack doesn't it. It should give you more of an idea of what went wrong. – dt192 Jul 03 '23 at 15:13
  • lhf: I dont want to immediatly call that function, they are just close together for the sake of example. As I can tell from the manual (referenced in that answer you linked), `dofile` is equivalent to `define func(); call func()` which I don't want – kollie Jul 03 '23 at 15:18
  • 1
    also shouldn't this be negated `if (lua_isfunction(L, -1))` – dt192 Jul 03 '23 at 15:21
  • Ahhhhhh of course, yes. No wonder if wont work then. I'll look at that, and then will see in the docs how to poke around the stack for the error. thanks! – kollie Jul 03 '23 at 15:25
  • 2
    I think they are probably right about the dofile, as in native lua I had to execute the function returned from load, before being able to execute the hello function. `load(playLuaStr)(); hello();`, so probably your `lua_getglobal` isn't working as `hello` doesn't exist. – dt192 Jul 03 '23 at 16:10
  • 2
    A small problem: `fprintf(sterr, "Error running lua: %i\n", result);` - this example does not compile (`sterr`). Please ensure that you are copying your [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) precisely - avoid transcribing by hand, when possible, and instead copy and paste complete examples immediately after checking their validity. It may seem minor, but typos like this can create doubt as to the correctness of *other* sections of the code! – Oka Jul 03 '23 at 17:02

1 Answers1

2

When the return value of lua_pcall is not LUA_OK, an error message will have been pushed onto the top of the stack.

This value can be manipulated with functions like lua_tostring for use in C.

result = lua_pcall(L, 0, 0, 0);

if (result != LUA_OK) {
    fprintf(stderr, "Error running lua: %s\n", lua_tostring(L, -1));
    exit(1);
}

(You can also propagate the error with lua_error(L), but that may defeat the purpose of the protected call.)

Doing this reveals the error

Error running lua: attempt to call a nil value

which means lua_getglobal(L, "hello"); pushed nil onto the stack.

(Note that we only get this far because if (lua_isfunction(L, -1)) is the inverse condition to check for.)

The value of the global variable hello is nil because the chunk containing its definition was never executed. That is, luaL_loadfile (ultimately lua_load) only loads chunks, it does not execute them.

After loading a chunk, you may execute it like any other function (lua_call, etc.).

For example:

#include <stdio.h>
#include <stdlib.h>

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

int
main(void) {
    lua_State *L = luaL_newstate();

    luaL_openlibs(L);

    int status;
    int result;

    status = luaL_loadfile(L, "play.lua"); /* load the chunk */
    if (status != LUA_OK) {
        fprintf(stderr, "Could not load 'play.lua': %s\n", lua_tostring(L, -1));
        exit(1);
    }

    result = lua_pcall(L, 0, 0, 0); /* execute the chunk */
    if (result != LUA_OK) {
        fprintf(stderr, "Error running lua: %s\n", lua_tostring(L, -1));
        exit(1);
    }

    lua_getglobal(L, "hello");
    if (!lua_isfunction(L, -1)) {
        fprintf(stderr, "ERROR: Not a function!\n");
        exit(1);
    }

    result = lua_pcall(L, 0, 0, 0);
    if (result != LUA_OK) {
        fprintf(stderr, "Error running lua: %s\n", lua_tostring(L, -1));
        exit(1);
    }

    puts("lua ran fine");
    lua_close(L);
}

Output:

Hello World!

lua ran fine

Note that luaL_dofile is a macro defined as

(luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))

and is a convenient way to load and execute a chunk.

Oka
  • 23,367
  • 6
  • 42
  • 53