Is C++ Like Lua

I wrote some examples of basic operations like running Lua code from a string, loading a script file, exposing variables and C functions to Lua code, recovering the values from global variables inside the Lua code and calling Lua function in C. Initializing Lua VM. Here is our first example, it is a starting point for using Lua with C.

The lua source can be found at the lua website here. We'll be using the latest version, 5.2.3 (though other recent versions of Lua will behave similarly).

Once you have the latest lua source, it's time to build it. (Yes, you could just download header files and the .dll, but what's the fun in that? When available, it's always better to have the source, that way you can see how things are really working -- and you can debug more easily). Using visual studio:

  • Open up Visual Studio, and create a new project
    • Create a win 32 console application
    • In the Project Creation wizard, check the 'static library' radio button to build as a static library.
  • Add the lua source to the project. Just dragging the files directly from their folders into the project works well for this.
  • There are two source files that you don't need: lua.c and luac.c. These files contain the main program for the command line interpreter and the bytecode compiler, respectively. You can remove this files from the project if you wish. If you are building as a static library, having more than one main won't be a problem. However, if you are building as an executable, then you will need to exclude one of these files from the project. Right-click on them in the project explorer and select 'Exclude from Project'

You now have a project that you can add to any solution that needs lua. Once you have added the lua project to your game, you need to do a few more steps:

  • In the properties for the project that is using lua, be sure that the directory that contains the lua .h files is included in the set of include paths. If at all possible, make these paths relative, and not absolute
  • Your project will need to get at the .lib files for the lua. There are a few ways to do this:
    • Add a reference from your project to the lua project. Right-click on your project in the project explorer, and select References:
      Add a new reference:
      Select the lua project:
    • Or, add Lua.lib to 'Additional Dependencies' (in the Librarian/Genrerl tab of the Project Property Pages) and add the directory where Lua.lib lives to 'Additional Library Directories' (also in the Librarian/Genrerl tab of the Project Property Pages).

Once we have build Lua, and set up our project dependencies correctly, we are ready to use in on our application,


First off, we need to include the proper header files. Since Lua is ANSI C, if we are coding in C++, we will need to enclose the #includes in extern 'C':

Everything that we need to mantain the current state of the interprer (all global tables, etc) is stored in a variable of type lua_State. The first thing we need to do is create an initial state (essentially, an instantiation of the lua interpreter), which is done by the call:


Every time we want to access the interpreter, we need to pass in this state variable. We can actually have as many instances of Lua state variables as we like (for instance, if we wanted to run separate instances of the interpreter on separate processors, or we wanted different scripts to have different global namespaces), though typically people just use one instance of the interpreter that all scripts use. The global tables in this state variable contain all 'core' functions, but none of the libraries. The libraries contain a bunch of important functions -- including everything in math, and i/o functions like print -- so we'd like to load them. We can load libraries with the call:


So, now we have the skeleton of a main function:

We are ready to start using lua!


We will start with the simplest way to use lua -- have the interpreter execute a file. This is functionally equivalent to the dofile command from within lua (and unsurprisingly, has the same name!). To execute the file 'test.lua', we can use the call:

Note that if we are using relative paths other than absolute paths under windows, then the system will look in the current working directory -- which is the directory that the executable file is in (if you double-click on the executable), or the directory that the project is in (if you run from within Visual Studio) You can, of course, change the working directory that the debugger uses under the project settings in Visual Studio.

So, if we use the following myFile.lua:

when the command luaL_dofile(L, 'myFile.lua') is executed, the following will be printed out

Note that the dofile command not only computes these values and prints them out, it also adds the fib function to the global namespace of our lua enviornment (stored in the C variable L).

We can also call lua functions directly from C/C++, and get back the return values to use in our C/C++ code. To call a lua function we:

  • Push the function on the top of the lua stack, using a call to
    • lua_getGlobal(lua_state *L, char *globalName)
  • Push the arguments to the function on the lua stack, using the functions:
    • lua_pushnumber(lua_state *L, float number)
    • lua_pushstring(lua_state *L, char *str)
    • lua_pushboolean(lua_state *L, bool)
    • lua_pushuserdata(lua_state *L, void *userdata)
    • lua_pushnil(lua_state *L)
  • Call the function, using the function:
    • lua_call(lua_state *L, int numArguments, int numReturnValues)
      We need to pass in both the number of arguments that we are passing in, and the number of arguments that we expect in return. Lua is very loose about the number of arguments and return value, but C/C++ is less so -- hence we need to be explicit when calling lua from C/C++.
  • Extract the return values, using the functions:
    • int lua_tointeger(lua_state *L, int stackLocation)
      Grab an integer value off the lua stack. The first return value is at index -1, the second return value is at index -2, and so on.
    • double lua_tonumber(lua_state *L, int stackLocation)
      Grab a double value off the lua stack. The first return value is at index -1, the second return value is at index -2, and so on.
    • const char *lua_tolstring(lua_state *L, int stackLocation)
      Grab a string value of the lua stack
    • int lua_toboolean(lua_state *L, int stackLocation)
      Grab a boolean value off the lua stack
      Note that these functions 'peek' at the lua stack, they don't actually remove any values from the stack. (That is done by the next function)
  • Pop the return value(s) off the top of the sack (this is just to clean up) with a call to
    • lua_pop(lua_state *L, int numReturnValsToPop);
Let's take a look at how we might call the fib function defined in the previous section to find the 13th Fibonacci number:

Let's look at a second example. Assume that we had defined the following lua function add (that we could define by calling lua_dofile):

We could call this function to add from C/C++ with the code:

So now you could write scripts that you can call from your game engine. However, these scripts won't be very useful if they can't interact with your game objects -- you need a way for your scripts to affect the game world. To do that, you need to be able to call C/C++ functions from lua. Since Lua and C++ have very different conventions for how functions are called, there is a little bit of wrapper work that needs to be done. First, write a C function that takes as input a Lua state variable (the parameters for the function will need to be extracted by hand from the lua stack -- this is slightly tedious, but not too difficult.) Then, the function will need to be registered with lua.

Step 1: Writing a C function that Lua can call

C/C++ functions that are called from lua need to take as an input parameter the lua state. The parameters can be examined on the call stack using the functions lua_tointeger, lua_tonumber, etc (described above). The first parameter is at index 1, the second parameter is at index 2, and so on. Once we have extracted the parameters, we do our calculation, and then push the result on the top of the stack.

Is Lua Like C++

Let's look at a slightly more complicated C function. We can write C functions that takes a variable number of parameters, and returns more than one return value. While the previous function assumed that we were passed in two parameters, we can instead query the lua state to see how many parameters were actually passed into the function. The number of parameters is stored on the top of the stack, which can be accessed by a call to lua_gettop(lua_state *L). Let's look at a function that takes in multiple parameters, and calculates the sum and average of all parameters that were passed in:

Step 2: Registering the C function for lua

Once we have written the function, we just need to register it with lua. That is, we need to add the name of the function to the global lua namespace, and provide a pointer to the function so that lua cal access it. There is a helpful macro for this: lua_register(lua_state *L, const char *name, functionPointer fn). So, to register the above two functions:

Step 3: Calling the C funcion from lua

This part is easy -- once the function is registered, lua can call it like any other function.

So, the complete round trip is:

  • Start the lua interpreter
  • Register the C functions you want lua to use
  • Call a lua function from within C, either by a call to luaL_dofile, or by calling a lua function directly
  • The lua function that you called from C can access the C function

We can also send a string straight to the lua interpreter, and it will be executed just as if that string was in a file that was executed with a dofile. So, we could do something like:

Like

and we would get the output:

We could thus create a braindead interpreter as follows:

Note that this would not work at all in a game environment! We will look at how to embed a command-line lua interpreter within a game next time. For now, this is enough for us to play around with a bit.

Now we are ready to get our fingers dirty!

  1. Download the following project, which contains a basic skeleton lua framework
  2. Write a function in C (exposed to Lua, much like average and cAdd) that takes as input an integer n, and returns all prime numbers less than or equal to n.
    • Test your primes function in the interpreter with 'print(primes(100))'
  3. Write a function in lua nthPrime, that takes as input a number n, and returns the nth prime number. So, nthPrime(6) should return 13. We'll define nthPrime(1) to be 2, and nthPrime(0) will be undefined. Your lua function should call the c primes function
    • Small change in how lua does variable numbers of arguments: From the notes

      Alas, this does not work. But we can fix it with a simple change:

  4. Write C code that computes the 100th prime number by calling the lua nthPrime function, and prints the value out using printf. So, C calling Lua that calls C.

This is Part 1b of my Integrating Lua into C++ Tutorial series.

Now that we have everything set up, let’s start!

Running a simple Lua-code from c++

First off, let’s try doing something simple. Let’s try running a Lua code from a string.

This should print out:

Hello World!

Congratulations! You have run your first Lua-code in c++! As you can see, you don’t really need all these fancy ‘.lua’ files to run Lua-code. You can just use strings for the trivial stuffs.

You might be wondering what the code snippet above is doing.

sol::state state;

This line creates a lua state to be used in the codebase. Any functions or variables you define would ‘live in’ the state that it’s created in.

state.open_libraries(sol::lib::base, sol::lib::package);

This line loads up the default libraries that gives you certain functionalities of the Lua language. This includes I/O and other important functionalities. For our test case, we load up these libraries in order to run Lua’s print function.

If you are intending to create a sandbox for your game, you might not want to load up these libraries as you would essentially be giving your players too much power. You wouldn’t really want to give your modders functionalities to access I/O as it could lead to a security risk.

state.do_string('print('Hello World!')');

This line would run the Lua code snippet from a string. As you might guess, looking at the code, this line would print “Hello World!” to the console window.

What Language Is Lua Similar To

Now let’s try running the same code snippet from a ‘.lua’ file.

In the default directory of your project, create a ‘scripts’ folder to store all your scripts.

Create a file ‘HelloWorld.lua’ in the script folder and add this code inside:

Now try running this code in c++:

This should also print out:

Hello World!

state.do_file('scripts/HelloWorld.lua');

You might notice the slight change of code here. Instead of do_script, we used do_file, to indicate that we want to run the code from a ‘.lua’ file instead of a string.

Accessing Lua variables from c++

In this part of the tutorial, we will be covering on how to access lua variables in c++ code.

Accessing lua variables from c++ is fairly simple.

Here we have a numeric lua variable named ‘luaNum’. As you can see, in the snippet code above, we are able to both set and get the value just like a normal variable in c++ just by knowing the lua variable’s name.

If nothing goes wrong, you’ll see:

printing in Lua: 3
printing in c++: 3

state['luaNum'] = 3;

This line defines a numeric lua value with the variable name of “luaNum”. As stated above, every time you reference “luaNum” in your lua codebase, you would be referencing this variable.

state.do_string(std::string('print('printing in Lua: ' .. luaNum)');

This line prints the value of “luaNum”. This might be off topic but “..” is the concatenation operator for strings in lua.

Running c++ functions from Lua

We shall first try calling c++ functions from lua. Right now we’ll only run normal functions. We shall look at classes later in part 2 of the tutorial.

Since we already covered that whatever we can do in the ‘.lua’ files can also be done using strings, we shall just cover the topic using strings in order to simplify the tutorial.

Let’s run this code!

If you run this code correctly, you should print out:

Called testCppFunction with return value (1)!

lua.set_function('testCppFunction', testCppFunction);

This lines binds the c++ function into the Lua state with the alias “testCppFunction”

state.do_string('num = testCppFunction(1); print(': Called testCppFunction! Return value:' .. num)');

This line calls the testCppFunction by calling “testCppFunction(1)” in the string.

You can also do this with functional objects, lambda, etc. Try it out!

Running Lua functions from c++

Is C++ Like Java

Before we do anything fancy like running the lua function from c++, let’s first run the code from a Lua file.

Create a Lua file called “testLuaFunction1.lua” in your scripts folder with the following code snippet:

If you did everything right, running this should print out “Calling testLuaFunction1!”.

In this lua file, we can see definition of the function testLuaFunction1 as well as a call to run the actual function.

Now let’s try running the Lua function from c++ code!

create a new lua file called ‘testLuaFunction2’ in your scripts folder with the following code snippet:

As you can see, the difference between this function and the previous function is that this function takes in a number and return said number + 10.

Alternatively, you can just remove the function call from ‘testLuaFunction1.lua’ and do all the tests by calling the function there.

There are multiple ways of calling a lua function from C++ code. Lets do the easiest way first. Im pretty sure that you already know how.

Well, you know the drill.

Running this code, you should get:

Calling testLuaFunction2 with input value (1)!

In the string, we used ‘1’ as the argument and as such, we printed ‘1’ as the prefix in the output.

Now we shall encapsulate the lua function into a c++ object and call the function in c++.

This should be pretty useful for you. Let’s do this!

Now you should get:

Calling testLuaFunction2 with input value (2)!

sol::function testLuaFunction2 = state['testLuaFunction2'];

This sol::function is a functional object referencing to the lua function “testLuaFunction2” in the lua state. Invoking the function would invoke the referenced lua function.

Nice, isn’t it? Now you can have a functional object in c++ behave like and look like a c++ function but is a lua function.

If you’ve really been observant, you would had noticed that ‘testLuaFunction2’ returns a value, more specifically the input value + 10.

Let’s try printing the return value of the function.

Now you should get:

Calling testLuaFunction2 with input value (1)!
Return value: 11
Calling testLuaFunction2 with input value (2)!
Return value: 12

Summary

This part of the tutorial is a lot longer than I wanted it to be. It’s also not so interesting but well, it’s a necessary evil as you need the knowledge here before you can continue on to the next part.

Codes:

main.cpp

HelloWorld.lua

testLuaFunction1.lua

testLuaFunction2.lua

Previous (Part 1a: Introduction and Setting Up) Next(Part 2: Interacting with Classes)