C++ & Lua - Functions

Skill

C++ & Lua - Functions

Posted in:

So in our last Lua tutorial, we went over a basic way to get information from lua and use it inside C++ code. This time, we are going to use the same principals to run a lua function from C++ and a C++ function from lua. This opens up endless possibilities for communication between the two. So, how about we get started then.

In the last tutorial, we used a small script that allowed us to get variables from lua quite easily. Today, we are going to use the basic lua libraries to start from the beginning, giving us full control over how we use our functions. It is quite simple once you realize how to get things going.

The first thing you have to do is get a C++ project going, just don't forget to disable pre-compiled headers. Once you do have one up and running, you have to include the lua libraries in your project. There are actually several ways to do this, but for now we are going to go with the fool proof way. All you have to do is get the lua libraries and includes, and stick them in your project folder. You don't even to include all of them in the project itself. The last lua tutorial went through where to get the lua libraries and where to put the files. Just remember that we are not using the "script" class in this tutorial.

Now that you have a project with the lua libraries, we can start getting C++ to use it. We are going to start with some compiler directives that will allow us to load in the lua library a little more easier. We will be using the #pragma directive in this case, which deals with machine and operating system-specific features. The first directive is the once command, which means that our main header file will only be included by the compiler once. This just speeds up the compiling a bit, not a huge deal, but it helps.

The next pre-processor directive we are using is the big one. It is going to do a library search for us and include the lua library. It will look something like so:

#pragma comment(lib, "lua5.1.lib")

What the comment directive does is add a comment to the executable, which will run a command based on the comment type. In our case, it will do a library search for lua5.1.lib. This makes loading in the lua library all that easier. All we have to do now is include lua.hpp and some basic libraries. Our final "includes" block will look like this:

#pragma once
#pragma comment(lib, "lua5.1.lib")

#include <iostream>
#include <string>
#include <stdio.h>
#include "lua.hpp"

Pretty simple in form, but what this does is allows us to communicate with the lua interpreter. To start this party, we first need one thing above all else, a lua state object. This will be our doorway into lua. We need to create a pointer first of all, then open up a new lua state. But, in order to make C++ functions to lua in our lua script, we have to make this one lua state global. Of course this is really as easy as just creating it right below our "includes" block. The object itself can be created like so:

lua_State *L;

This lua_state object is required for just about every operation we are going to do, so keep it close. Right now, however, all we have is a pointer. We need an actual lua_state object. This can be remedied using the lua_open() method. Here is the basic of how we start:

int main ( int argc, char *argv[] )
{      
  L = lua_open();

  lua_close(L);

  printf( "Press enter to exit..." );
  getchar();
}

So what is happening here is exactly what it looks like. We are opening a new lua state, they closing it. Then, so we can see what is going on, we pause the console. Anything we do will be while the lua state is open. So let's get started.

Let's start with a basic lua function:

function lFunction()
  print("Hello From Lua!")
end

I put this function inside a script called "test.lua" and I included it in my c++ project. For more details on how to do this, just look over our last lua tutorial, which takes a little more time on how to include the lua files. Once you have your lua file with the function, we need to load in the file and use the function. Luckily, this is not that difficult:

int main ( int argc, char *argv[] )
{      
  L = lua_open();

  luaL_openlibs(L);

  luaL_dofile(L, "test.lua");

  lua_getglobal(L, "lFunction");
  lua_call(L, 0, 0);

 
  lua_close(L);

  printf( "Press enter to exit..." );
  getchar();

  return 0;
}

So what we add was first loading in the base lua libraries. This allows our lua scripts to use the libraries you would use in even the most basic lua functions. Once we load in the libraries, we use the luaL_dofile() function to load in our script. Once loaded, we have to get the function, then call it. That's what the last two lines in our additions do. The lua_getglobal() function is pretty strait forward, but the lua_call function is slightly tricky. It has three arguments, the first is the lua state object, then two numbers. The first int is the number of arguments the lua function will be passed, then how many things will be returned. Actually passing arguments is a little more difficult, but for now this is what we will work with.

So if we run this application, we will see "Hello from LUA!" in our console window. It is all pretty strait forward. But next on the list is getting a C++ function to work inside of lua. This is a little more tricky, but still pretty easy. To make it easier on us, there is what the function will look like:

static int cppFunction(lua_State *L)
{
  lua_pushstring(L, "Hello from C++!");

  return 1;
}

So what is happening is that we are taking in a lua state we we call the function. This will actually end up being a function that takes no arguments in lua. In order to return a value from the function, we use the lua_push functions. For this small function, we are just going to return a string. One really important factor here, it the returning of a 1. This number represents the number of variables the function returns. If it is wrong, then it will not work properly.

To use this in lua, we have to register it with the lua state. Like you may think, there is a simple function to do that. Our new C++ will look something like this:

int main ( int argc, char *argv[] )
{      
  L = lua_open();

  luaL_openlibs(L);

  lua_register(L, "cppFunction", cppFunction);

  luaL_dofile(L, "test.lua");

  lua_getglobal(L, "lFunction");
  lua_call(L, 0, 0);

  lua_close(L);

  printf( "Press enter to exit..." );
  getchar();

  return 0;
}

If you look closely, you will notice just one tiny line that we added. The lua_register() call. It takes in the lua state, a string, and the function to register. The string is what the function will be called in lua, so you can really name it anything. For the sake of making things easy, let's just keep with the same name.

In order for this to all make sense, we have to use this function in our lua script. As you might have thought, all we have to do is call it like any other function:

function lFunction()
  print (cppFunction())
end

All we changed here is that we are printing the results of the function we registered, rather than just a strait string. If we run the application, we will get a "Hello from C++!" message. This is what we want, calling a lua from C++, which calls a C++ function inside that lua function. This gives us a basic understanding on how to get started with functions between lua and C++.

Well, I think this is where we wrap up this tutorial. We went over a lot here, and all that we have left is to include arguments either way, which is a beast in itself. This will be the subject of our next tutorial. Just remember, when you need programming help, just Switch On The Code.

Add Comment

Put code snippets inside language tags:
[language] [/language]

Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]

See here for supported languages.

Javascript must be enabled to submit anonymous comments - or you can login.

Sponsors