Introduction

Lua is a pretty straight forward simple scripting language that can be implemented in a number of languages.  Today I’m going to show you how easy it is to embed Lua in C++.  First thing you’re going to need to do is create a sane build environment by installing the Lua programming language and development packages.  Depending on the OS and version you are using this can vary, for simplicity sake I’m going to assume your using linux with RPM support and I’ll be using the 5.1 version of Lua.

Getting Started

First let’s download and install the Lua packages:
(Please note these are the 64-bit library versions, you may need a different version depending on your distro and architecture)

cd /usr/src

wget http://dl.fedoraproject.org/pub/epel/5/x86_64/lua-5.1.4-4.el5.x86_64.rpm

wget http://dl.fedoraproject.org/pub/epel/5/x86_64/lua-devel-5.1.4-4.el5.x86_64.rpm

rpm -i lua-5.1.4-4.el5.x86_64.rpm lua-devel-5.1.4-4.el5.x86_64.rpm

Creating The App

Next let’s create a host application to execute our Lua code:

mkdir lua-host

cd lua-host

Create a lua-host.cpp file and add the following contents:

extern "C" {
    #include "lua.h"
    #include "lauxlib.h"
    #include "lualib.h"
}

#include "stdio.h"

int main(int argc, char ** argv){

    //iterate all files and execute
    for(int n=1; n<argc; n++){
        const char * file = argv[n];

        //create a new lua state
        lua_State * L = luaL_newstate();

        //open all libraries
        luaL_openlibs(L);

        int s = luaL_loadfile(L, file);

        if(!s)
            s = lua_pcall(L, 0, LUA_MULTRET, 0);

        //show any errors
        if(s){
            printf("Error: %s \n", lua_tostring(L, -1));
            lua_pop(L, 1);
        }

        lua_close(L);
    }

    return 0;
}

Diving In

Now let’s examine the above C++ code.  The first thing we do is iterate over the passed in arguments in this case expected to be file names (ie. ./lua-host test.lua). For each passed in file we create a new state or context for the execution of the Lua script files.  Next we make a call to openlibs which allows access to all the standard Lua libraries from the passed in files.  Next, we check the return value of the loadfile call to ensure everything is still a go, then we invoke pcall which executes the chunk of code contained within the file.  Lastly, we check for any errors that might have occurred and display them, then close that instance of the Lua state.  Wash, rinse, repeat for all the files passed in along the command line.

Compiling

Now, let’s go ahead and compile the lua-host application.

g++ lua-host.cpp -o lua-host -llua

Hopefully if all when well and you are sans typos, you should now have a shiny new lua-host executable at your disposal. So next, let’s test it.

Start by creating a simple “Hello World” script in Lua, create a new file called hello_world.lua and put the following in it:

print("Lua says: Hello World")

Running

Next, let’s execute the hello_world.lua file against our new host application:

./lua-host hello_world.lua

Lua says: Hello World

Booyah! Well that was easy. Now how about adding a custom function in C++ that can be make callable from Lua. This is actually very simple as well.

Adding Custom Methods

Let’s modify our lua-host.cpp file and add a custom method called hello:

extern "C" {
    #include "lua.h"
    #include "lauxlib.h"
    #include "lualib.h"
}

#include "stdio.h"

//new custom hello method
int hello(lua_State * L){
    printf("C++ says: Hello World\n");

    return 1;
}

int main(int argc, char ** argv){

    //iterate all files and execute
    for(int n=1; n<argc; n++){
        const char * file = argv[n];

        //create a new lua state
        lua_State * L = luaL_newstate();

        //open all libraries
        luaL_openlibs(L);

        //register new custom method
        lua_register(L, "hello", hello);

        int s = luaL_loadfile(L, file);

        if(!s)
            s = lua_pcall(L, 0, LUA_MULTRET, 0);

        //show any errors
        if(s){
            printf("Error: %s \n", lua_tostring(L, -1));
            lua_pop(L, 1);
        }

        lua_close(L);
    }

    return 0;
}

So what did we just do? We defined a new hello method and had it’s implementation just do a printf of “C++ says: Hello World”, then in the body of the main method we added a call to lua_register(L, "hello", hello), which as you might have guessed registers the hello method as “hello” in Lua. This simply maps the hello() Lua call to the C++ hello method.

Now let’s compile it:

g++ lua-host.cpp -o lua-host -llua

Hopefully once again no typos. Next, let’s update the hello_world.lua and add a call to the new C++ hello method.

Edit the hello_world.lua file and ensure it has the following:

print("Lua says: Hello World")
hello()

Now that we have the new hello method call added to our Lua script, let’s execute it in our host application:

./lua-host hello_world.lua

Lua says: Hello World
C++ says: Hello World

Booyah part 2! Now we’ve successfully added a custom method to our Lua host application. I think the last thing we should do is make the custom method a bit more intelligent. Let’s add parameters to the function and a return value.

Custom Method Parameters

Once again edit the lua-host.cpp file and modify to the following:

extern "C" {
    #include "lua.h"
    #include "lauxlib.h"
    #include "lualib.h"
}

#include "stdio.h"

//new custom hello method
int hello(lua_State * L){
    printf("C++ says: Hello World\n");

    //get the count of arguments passed to the hello function
    int argc = lua_gettop(L);

    //iterate the arguments as display them
    for(int n=1; n<=argc; ++n)
        printf("argument received - index: %d - value: %s\n", n, lua_tostring(L, n));

    //let's return a value - it's the answer to the universe
    lua_pushnumber(L, 42);

    return 1;
}

int main(int argc, char ** argv){

    //iterate all files and execute
    for(int n=1; n<argc; n++){
        const char * file = argv[n];

        //create a new lua state
        lua_State * L = luaL_newstate();

        //open all libraries
        luaL_openlibs(L);

        //register new custom method
        lua_register(L, "hello", hello);

        int s = luaL_loadfile(L, file);

        if(!s)
            s = lua_pcall(L, 0, LUA_MULTRET, 0);

        //show any errors
        if(s){
            printf("Error: %s \n", lua_tostring(L, -1));
            lua_pop(L, 1);
        }

        lua_close(L);
    }

    return 0;
}

Now let’s compile it:

g++ lua-host.cpp -o lua-host -llua

Finally, let’s add some parameters to our hello call in Lua and check the return value.

Edit the hello_world.lua file and ensure it has the following:

print("Lua says: Hello World")
r = hello("booyah!", "biscuits!")
print("The value returned from the hello call was: ", r)

So we’ve added two parameters to our C++ hello call, “booyah!” and “biscuits!”. We’re also storing the return value in the variable r and displaying it by way of the print() call. Now, let’s run it and see what we get:

./lua-host hello_world.lua

Lua says: Hello World
C++ says: Hello World
argument received – index: 1 – value: booyah!
argument received – index: 2 – value: biscuits!

The value returned from the hello call was: 42

Conclusion

Perfection is the key! Hopefully that wasn’t too confusing and will help you get started in implementing Lua into your applications. Let me know if you have any issues or questions in the comments below.


0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *