How to expose C++ functions to a lua script? - c++

I just successfully created an lua project. (A simple code that runs an lua script so far.)
But how would I make a c++ function and a c++ variable available for the lua script now?
As an example:
int Add(int x, int y) {
return x + y;
}
and
float myFloatValue = 6.0
I'm very new to c++ so I really hope that it won't be too complicated. Here is the code I got so far btw:
#include "stdafx.h"
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
using namespace System;
int main(array<System::String ^> ^args)
{
lua_State* luaInt;
luaInt = lua_open();
luaL_openlibs (luaInt);
luaL_dofile (luaInt, "abc.lua");
lua_close(luaInt);
return 0;
}

I'll go with John Zwinck's answer as experience has proven to me that using Lua all by itself is a pain in the butt. But, if you want to know the answer check the rest.
For registering C/C++ functions you need to first make your function look like a standard C function pattern which Lua provides:
extern "C" int MyFunc(lua_State* L)
{
int a = lua_tointeger(L, 1); // First argument
int b = lua_tointeger(L, 2); // Second argument
int result = a + b;
lua_pushinteger(L, result);
return 1; // Count of returned values
}
Every function that needs to be registered in Lua should follow this pattern. Return type of int, single parameter of lua_State* L. And count of returned values.
Then, you need to register it in Lua's register table so you can expose it to your script's context:
lua_register(L, "MyFunc", MyFunc);
For registering simple variables you can write this:
lua_pushinteger(L, 10);
lua_setglobal(L, "MyVar");
After that, you're able to call your function from a Lua script. Keep in mind that you should register all of your objects before running any script with that specific Lua state that you've used to register them.
In Lua:
print(MyFunc(10, MyVar))
Result:
20

Rather than doing it using the Lua C API, I suggest using Luabind.
Luabind is a reasonably high-level library specifically built to expose C++ classes and functions to Lua. Without using the Lua C API functions, without manipulating the Lua stack, etc. It's inspired by Boost Python, so if you learn one you'll mostly understand the other.

Related

C++ Creating Objects as Static - advice needed on good practice

I am a mainly C programmer building a prototype on a Raspberry Pi. I'm making extensive use of some open source C code, but also a Raspberry Pi hardware add on which comes with C++ drivers. So I need them to work together. I did some research and got them to work together by writing a C++ function with an extern "C" declaration, compiling this as a shared library and linking it with my C program.
I need the C++ function to instantiate an object the first time it is called and then to be able to interact with this object on subsequent calls to the function. I was slightly overwhelmed by the instructions for how to create and access C++ objects directly in C, so I tried simply adding "static" before the creation of the object - and interacting with the object through the mediation of the C wrapper. This seems to working perfectly but I'm slightly worried that this is not routinely given as the answer to the "using C++ objects in C" and so I wonder if I am going to end up with unforeseen problems? I don't need my code at this stage to be high quality, but I don't want to end up with segmentation errors because I have done something foolish. Any advice would be really appreciated.
Here is a cut down version to show what I am doing. In this example I create a simple c++ function that takes an int argument from the calling C program. If the argument is 0 it creates the objects and sets all the leds in array to 0. If I call this a second time with the argument = 1, it instructs the same object to light all the red leds. This code works.
#include <string.h>
#include <matrix_hal/everloop.h>
#include <matrix_hal/everloop_image.h>
#include <matrix_hal/matrixio_bus.h>
extern "C" int led_change(int input_from_c)
{
namespace hal = matrix_hal;
static hal::MatrixIOBus bus;
static hal::EverloopImage image1d(18);
static hal::Everloop everloop;
if (input_from_c == 0)
{
if (!bus.Init()) return false;
// this line just resizes the EverloopImage object to the number of LEDs on the board
everloop.Setup(&bus);
// switch off the leds
for (int i=0;i<18;i++)
{
image1d.leds[i].red = 0;
image1d.leds[i].green = 0;
image1d.leds[i].blue= 0;
image1d.leds[i].white = 0;
}
everloop.Write(&image1d);
}
else if (input_from_c == 1)
{
for (int i=0;i<18;i++)
{
image1d.leds[i].red = 100;
image1d.leds[i].green = 0;
image1d.leds[i].blue= 0;
image1d.leds[i].white = 0;
}
everloop.Write(&image1d);
}
return 1;
}
The calling code in C is just
#include <unistd.h>
#include <stdio.h>
int led_change (int);
int i;
void main () {
i = led_change(0);
printf("returned %d\n",i);
sleep(1);
i = led_change(1);
printf("returned second time %d\n",i);
}
Hope this clear. Thanks for any help.
You need to compile and link all your C code as C++ modules. The reverse doesn't work. C doesn't know about constructors to be called for your static objects in c++ modules... so the linker has to understand the c++ calling sequences. C++ language was designed with compatibility of old C code in mind. But C doesn't have that statement in mind when it was designed.
Despite of this, C++ compilers normally can compile also pure C code (in C language mode) so one of these compilers will be valid. It will generate code that can survive in the same program without any problem.
You can have a C code main() function in a c++ program, but always use a c++ linker to link that code into the program.
When "C" code is linked to C++ code using "extern", C++ compilers stop "name mangling" for those C variables or functions, while creating symbol names in object file. For C++ functions, they mangle names to support function overloading.
When static objects are returned from shared objects, they might create problem in multi-threaded programs, like two or more threads modifying the values in the static objects at the same time.

Lua - set a function from a class [duplicate]

I am trying to register a c++ function in Lua.
But getting this error:
CScript.cpp|39|error: argument of type 'int (CScript::)(lua_State*)' does not match 'int (*)(lua_State*)'|
EDIT:
int CApp::SetDisplayMode(int Width, int Height, int Depth)
{
this->Screen_Width = Width;
this->Screen_Height = Height;
this->Screen_Depth = Depth;
return 0;
}
int CScript::Lua_SetDisplayMode(lua_State* L)
{
// We need at least one parameter
int n = lua_gettop(L);
if(n < 0)
{
lua_pushstring(L, "Not enough parameter.");
lua_error(L);
}
int width = lua_tointeger(L, 1);
int height = lua_tointeger(L, 2);
int depth = lua_tointeger(L, 3);
lua_pushinteger(L, App->SetDisplayMode(width, height, depth));
return 0;
}
And in main:
lua_register(L, "setDisplayMode", Lua_SetDisplayMode);
You can not use a method of a class as a normal function, unless it is declared static. You have to define a normal function, which finds out what object you want the method to be called in, and then call the method.
The main reason it's not possible to use a class method as a callback from a C function (and remember that the Lua API is a pure C library), is because the computer doesn't know which object the method should be called on.
The answer is actually surprisingly simple; if you use lua_pushcclosure instead of lua_pushcfunction, you can pass parameters to your called function:
lua_pushlightuserdata(_state, this);
lua_pushcclosure(_state, &MyClass::lua_static_helper, 1);
int MyClass::lua_static_helper(lua_State *state) {
MyClass *klass = (MyClass *) lua_touserdata(state, lua_upvalueindex(1));
return klass->lua_member_method(state);
}
You cannot directly register a C++ non-static member function in Lua using just the basic Lua C API.
However, any of the various mechanisms that exist for easily associating C++ code with Lua will allow you to do so. toLua++, SWIG, Luabind, etc. If you're serious about using C++ objects with Lua, I suggest picking one of those and using it, rather than writing your own version. I personally use Luabind (most of the time; SWIG has its place in the toolbox), as it is the one that doesn't have some form of code generation. It's all done purely in C++, so there's no pre-pass step that generates a C++ source file.
You can work around the limitation by storing your active this pointer in a static variable as well. This introduces the problem of being unable to have two of these classes operating at the same time, but it works.
static CScript* luaThis; // This is a private variable inside CScript.
Then, inside your CScript constructor (or some kind of 'activate' function), you can just specify:
luaThis = this;
Then, when your static functions are called (they can even be private functions if they are registered from within the class), you have access to all your member information via the luaThis pointer.
lua_pushinteger(L, luaThis->App->SetDisplayMode(width, height, depth));
The problem, as I said, is that this restricts you to one active CScript at a time (since another callback from another Lua state would use luaThis while it is pointing to the wrong things). If you need multiple active instances ever, you can come up with some lookup mechanism using the incoming lua_State* as a key.
std::map<lua_State*, CScript*> lookups; // Just an idea, if it comes to this.
Hope that helps!

How to expose properties to Lua Library from C++

I want to how we can expose properties to lua library.
luaL_openlib( L, kName, kVTable, 1 ); // leave "library" on top of stack
With this, I am able to expose only functions as kVTable refers to luaL_Reg
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;
Eg: With the above code. I can do following.
local myLib = require "plugin.myLib"
myLib.newFunc();
However, I want to expose Lua Table to the library as CONSTANTS variable.
myLib.CONSTANTS.SOME_CONST_1
myLib.CONSTANTS.SOME_CONST_2
etc. Please let me know how can I expose lua Table from my library as property.
As luaL_openlib leaves the library table on top on the stack, you can use regular C API to add new fields and subtables to it:
luaL_openlib( L, kName, kVTable, 1 ); // leaves "library" on top of stack
lua_pushstring(L, "CONSTANTS");
lua_newtable(L); // this will be CONSTANTS subtable
lua_pushstring(L, "SOME_CONST_1");
lua_pushnumber(L, 42); // SOME_CONST_1 value
lua_settable(L, -3); // sets SOME_CONST_1
lua_pushstring(L, "SOME_CONST_2");
lua_pushnumber(L, 12345); // SOME_CONST_2 value
lua_settable(L, -3); // sets SOME_CONST_2
lua_settable(L, -3); // sets CONSTANTS table as field of the library table
return 1;
If you use C++, you can use a binding library, such as the header-only luabridge to bind some data to named tables in Lua. Transforming your example into LuaBridge, call this function after you initialize your Lua state:
void register_constants (lua_State* L) {
luabridge::getGlobalNamespace(L)
.beginNamespace("myLib")
.beginNamespace("CONSTANTS")
.addVariable("SOME_CONST_1",&some_const_1,false/*read-only*/)
.addVariable("SOME_CONST_2",&some_const_2,false/*read-only*/)
.endNamespace()
.endNamespace()
;
}
...
lua_State* L=lua_open();
register_constants(L);
...
you can access the constants as your last code snippet
Caveat, lector, because Lua C API is, well, C API.
The whole burden with loadlib and friends was because functions are much harder to pass using C (C funcions aren't first class values). So my best bet would be to set all those constants using regular stack API.
In general, it is supposed to be used to exchange runtime data, of course, but there's no inherent reason why you shouldn't be able to fill your tables with that when loading the module.

how do I extend Lua with a static c++ library?

I have a Visual Studio 2008 C++03 application that uses Lua 5.2.1. I would like to extend Lua with a module called "foo", but when I call require("foo") in my Lua script, I get the error:
foo_test.lua:1: module 'foo' not found:
no field package.preload['process']
no file '!\lua\process.lua'
no file '!\lua\process\init.lua'
no file '!\process.lua'
no file '!\process\
My Lua script:
foo.bar()
My lua_foo.h file:
#include <lua.h>
extern "C" int luaopen_foo( lua_State* L );
My lua_foo.cpp file:
#include "lua_foo.h"
#include <lua.hpp>
static int l_bar( lua_State *L )
{
puts( "in bar()" );
return 1;
}
int luaopen_foo( lua_State *L )
{
static const luaL_Reg foo[] = {
{ "bar", l_bar },
{ NULL, NULL }
};
luaL_newlib( L, foo );
return 1;
}
These are compiled in to a static library "lua_foo.lib" which is statically linked to my main Lua executable.
Can anybody help me understand where I'm going wrong? thanks. I would prefer to avoid c++ wrappers (for now) and I do not want to package this library as a separate DLL from the main Lua engine.
EDIT
The issue was in the lua engine code. I added the luaL_requiref per #NicolBolas 's suggestion.
lua_State* L = luaL_newstate();
if( NULL != L )
{
luaL_openlibs( L );
luaL_requiref( token.get(), "foo", luaopen_foo, 1 );
luaL_dofile( L, "foo_test.lua" );
lua_close( L );
}
It's important to understand how the require machinery works and therefore why your code doesn't.
require is designed to look for Lua scripts in the file system and DLLs. Static libraries are not DLLs; indeed, as far as C/C++ is concerned, once you've finished linking, static libraries are no different than compiling those .c/.cpp files into your application directly.
When require finds a DLL with the appropriate name, it loads it and attempts to find a function named luaopen_<modname>, where <modname> is the name of the module. When it does, it will execute this function and store the value it returns in an internal database of loaded modules.
Calling require for a module will return whatever this function returned; if the module has already been loaded, then the return value is pulled from the database and returned directly.
Simply calling luaopen_foo will not do any of this. Indeed, simply calling this function is a bad idea; it is a Lua function and needs to be called as a Lua function (ie: you need to push it onto the Lua stack with lua_pushcfunction and call it with lua_call and so forth).
If you want to create a local module (one not in a Lua script or DLL, but exposed from your code), then you need to use the Lua facilities to do that. Specifically, use luaL_requiref:
luaL_requiref(L, "foo", luaopen_foo, 0);
Call this instead of calling luaopen_foo directly. This will automatically register the return value from luaopen_foo with require's internal database of loaded modules. Thus, subsequent calls to require "foo" will return this table.
One more thing: do is a keyword in Lua; you should not use keywords for Lua table key names. You can, but you always have to quote them (ie: your script must do foo["do"](...) to call it).
luaopen_foo creates a table with one function in it, but it doesn't expose it to Lua in any way. You need to assign it to something your scripts can access if you want to access it. You can do this with the package mechanism, or just assign it to a global (which is what Lua's built-in libraries do).
You have a field named do, which is problematic if you want to use foo.do syntax, because do is a keyword.
The return value of a Lua function tells Lua how many values you left on the stack. Your l_do function lies with its return value.
In the case of luaopen_foo, since you're calling it directly and ignoring it's return value, there's no need for it to return anything at all.
Change your code to this:
static int l_bar( lua_State *L )
{
puts("l_bar called.");
return 0;
}
void luaopen_foo( lua_State *L )
{
static const struct luaL_Reg foo[] = {
{ "bar", l_bar },
{ NULL, NULL }
};
luaL_newlib( L, foo ); // create table containing `bar`
lua_setglobal(L, "foo"); // assign that table to global `foo`
}
And change your script to this:
foo.bar()

Register C++ function in Lua?

I am trying to register a c++ function in Lua.
But getting this error:
CScript.cpp|39|error: argument of type 'int (CScript::)(lua_State*)' does not match 'int (*)(lua_State*)'|
EDIT:
int CApp::SetDisplayMode(int Width, int Height, int Depth)
{
this->Screen_Width = Width;
this->Screen_Height = Height;
this->Screen_Depth = Depth;
return 0;
}
int CScript::Lua_SetDisplayMode(lua_State* L)
{
// We need at least one parameter
int n = lua_gettop(L);
if(n < 0)
{
lua_pushstring(L, "Not enough parameter.");
lua_error(L);
}
int width = lua_tointeger(L, 1);
int height = lua_tointeger(L, 2);
int depth = lua_tointeger(L, 3);
lua_pushinteger(L, App->SetDisplayMode(width, height, depth));
return 0;
}
And in main:
lua_register(L, "setDisplayMode", Lua_SetDisplayMode);
You can not use a method of a class as a normal function, unless it is declared static. You have to define a normal function, which finds out what object you want the method to be called in, and then call the method.
The main reason it's not possible to use a class method as a callback from a C function (and remember that the Lua API is a pure C library), is because the computer doesn't know which object the method should be called on.
The answer is actually surprisingly simple; if you use lua_pushcclosure instead of lua_pushcfunction, you can pass parameters to your called function:
lua_pushlightuserdata(_state, this);
lua_pushcclosure(_state, &MyClass::lua_static_helper, 1);
int MyClass::lua_static_helper(lua_State *state) {
MyClass *klass = (MyClass *) lua_touserdata(state, lua_upvalueindex(1));
return klass->lua_member_method(state);
}
You cannot directly register a C++ non-static member function in Lua using just the basic Lua C API.
However, any of the various mechanisms that exist for easily associating C++ code with Lua will allow you to do so. toLua++, SWIG, Luabind, etc. If you're serious about using C++ objects with Lua, I suggest picking one of those and using it, rather than writing your own version. I personally use Luabind (most of the time; SWIG has its place in the toolbox), as it is the one that doesn't have some form of code generation. It's all done purely in C++, so there's no pre-pass step that generates a C++ source file.
You can work around the limitation by storing your active this pointer in a static variable as well. This introduces the problem of being unable to have two of these classes operating at the same time, but it works.
static CScript* luaThis; // This is a private variable inside CScript.
Then, inside your CScript constructor (or some kind of 'activate' function), you can just specify:
luaThis = this;
Then, when your static functions are called (they can even be private functions if they are registered from within the class), you have access to all your member information via the luaThis pointer.
lua_pushinteger(L, luaThis->App->SetDisplayMode(width, height, depth));
The problem, as I said, is that this restricts you to one active CScript at a time (since another callback from another Lua state would use luaThis while it is pointing to the wrong things). If you need multiple active instances ever, you can come up with some lookup mechanism using the incoming lua_State* as a key.
std::map<lua_State*, CScript*> lookups; // Just an idea, if it comes to this.
Hope that helps!