Search code examples
clualua-apilua-5.2

Calling Lua Function from C: Minimal example results in LUA_ERRRUN


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?


Solution

  • 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.