Calling a function defined in lua from C/C++

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Calling a function defined in lua from C/C++

Turgut Hakkı ÖZDEMİR
Greetings,

I saw lua used on a cpu-hunger project, loved it (speed issues (another nearly same project, using python is running several times slower...(needless to say, i'm involved))) and start to tinker with it to embed it my own projects but i've ended up with several problems.

Issue one :) :  When i try to call lua functions from C++ code it is complaining about "attempt to call a nil value" or something similar. I've checked reference manual and wiki several times but it did not changed anything. Finally i've noticed all functions defined in lua scripts has nil values but C++, functions registered to lua are callable. Also other global variables (non function ones) appearing as they have to be.

Following code represents the problem.

Code is compiled using msvc++ 2005 express edition and lua 5.1 (compiled as c++ and linked as a static library) (i've tried whole thing also in c but the result is same)

stringf class is provided for compilation reasons and does not related with our subject :)

--- test.lua ---------------------------------
function funk()

end

msg(funk) -- will be nil
msg(msg) -- displays functions address
-------------------------------------------------

and the code

--- blabla.cpp  ----------------------------
#include <stdio.h>
#include <string>

#include <windows.h>

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

// --- printf like string formatter --------------------------
class stringf
{
  protected :
    std::string str;
  public :
    stringf(const char *fmt, ...) {
      va_list va;
      char *tmp;

      va_start(va, fmt);
      tmp = new char [vsnprintf(0, 0, fmt, va) + 1];
      vsnprintf(tmp, vsnprintf(0, 0, fmt, va) + 1, fmt, va);
      str = tmp;
      delete [] tmp;
      va_end(va);
    }

    operator const char * () {
      return str.c_str();
    }
    operator std::string () {
      return str;
    }
};

// --- Message box emulation ----------------------
int msg(lua_State *L)
{
int n = lua_gettop(L);
std::string msg;

  for (uint i = 1; i <= n; i++) {
    switch(lua_type(L, i)) {
      case LUA_TFUNCTION :
          msg += (const char *) stringf("(function) : 0x%x", lua_tocfunction(L, i));
        break;
    }

  }

  MessageBox(0, msg.c_str(), "Message", MB_OK);

return 0;
}

// --- Start crying here --------------------------
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    lua_State *L = lua_open();
    luaL_openlibs(L);
   
    luaL_loadfile(L, "test.lua");
  
    lua_register(L, "msg", msg);
   
    lua_call(L, 0, 0); // when i use lua_pcall instead of lua_call here, surrounded with error handling functionality it complains about nil values
  
    lua_close(L);
}
-----------------------------------


Issue two : How can i convert exceptions (derived from std::exception) to lua? Well, i can do it by altering luaconf.h (i think) but how are you doing this?

  C++ code starts a script
  script calls a C++ function
  C++ function gets frightened and raises an exception
  How the script can handle thrown exception?

Issue four : What about C++ interoperatability? Any wrappers? (Actually i saw one but ended up with 404 error), How can i represent my classes/objects in lua in a little bit reasonable way (saw wiki). Where is the gooooooood sample "let's involve c++" code? :)

Issue three: Unicode?



Reply | Threaded
Open this post in threaded view
|

Re: Calling a function defined in lua from C/C++

Alex Queiroz
Hallo,

On 5/10/06, Turgut Hakkı ÖZDEMİR <[hidden email]> wrote:

>
> // --- Start crying here --------------------------
> int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
> int nCmdShow)
> {
>     lua_State *L = lua_open();
>     luaL_openlibs(L);
>
>     luaL_loadfile(L, "test.lua");
>
>     lua_register(L, "msg", msg);
>
>     lua_call(L, 0, 0); // when i use lua_pcall instead of lua_call here,
> surrounded with error handling functionality it complains about nil values
>
>     lua_close(L);
> }

     After loading the test.lua file, you must run it because it's
just a function on the stack at this point. After running it your
declarations will have effects.

--
-alex
http://www.ventonegro.org/
Reply | Threaded
Open this post in threaded view
|

Re: Calling a function defined in lua from C/C++

David Burgess
In reply to this post by Turgut Hakkı ÖZDEMİR
 Turgut Hakkı ÖZDEMİR wrote:
> Issue two : How can i convert exceptions (derived from std::exception) to
> lua? Well, i can do it by altering luaconf.h (i think) but how are you doing
> this?
>
>   C++ code starts a script
>   script calls a C++ function
>   C++ function gets frightened and raises an exception
>   How the script can handle thrown exception?
>
What I do is with VCn

1) Compile lua.c and ldo.c as C++
2) Compile with /GX /EHsc-
3) Patch luaconf.h and ldo.c like:

luaconf.h

#undef luai_jmpbuf
#define luai_jmpbuf int  /* dummy variable */
#undef LUAI_THROW
#define LUAI_THROW(L,c) throw lua_exception(errcode)

#if defined(__cplusplus) && defined(ldo_c)
class lua_exception {
  int status;
public:
  lua_exception(int status_) : status(status_) { };
  int get_status() { return status; }
};
#endif


#undef LUAI_TRY
#define LUAI_TRY(L,c,a) \
  try { a }  catch (lua_exception &e) \
    { (c)->status = e.get_status();if ((c)->status == 0) (c)->status = -1; } \
  catch (...) { throw; }

ldo.c
starts with

/*
** $Id: ldo.c,v 2.37 2005/12/22 16:19:56 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/


#if !defined(__cplusplus)
#include <setjmp.h>
#else
#pragma warning(disable : 4514)
#endif
#include <stdlib.h>
#include <string.h>
/* include all of these so that they get included before lua.h */
#if defined(__cplusplus)
#include <stdio.h>
#include <stdarg.h>
#include <stddef.h>
#include <math.h>
#include <limits.h>
#include <stdarg.h>
#include <io.h>
#endif


#define ldo_c
#define LUA_CORE

#if defined(__cplusplus)
extern "C" {
/*
** These modifications were required against the orig ldo.c becoz
** we needed the extern "C" wrapper and we need the lua_exception class
** to catch just lua errors
*/

#endif

#include "lua.h"

[rest of ldo.c]
#if defined(__cplusplus)
}
#endif


DB
Reply | Threaded
Open this post in threaded view
|

Re: Calling a function defined in lua from C/C++

Turgut Hakkı ÖZDEMİR
Greetings,


> What I do is with VCn
>
And how do you handle that exception in your scripts? (I meant lua code :))

> #define LUAI_TRY(L,c,a) \
>  try { a }  catch (lua_exception &e) \
>    { (c)->status = e.get_status();if ((c)->status == 0) (c)->status =
> -1; } \

Is this code passing exceptions to lua?

Reply | Threaded
Open this post in threaded view
|

Re: Calling a function defined in lua from C/C++

Turgut Hakkı ÖZDEMİR
In reply to this post by Turgut Hakkı ÖZDEMİR
Greetings,

>>>
>>>     lua_call(L, 0, 0); // when i use lua_pcall instead of lua_call here,
>>> surrounded with error handling functionality it complains about nil values
>>>
>>>     lua_close(L);
>>> }
>>    
>>

>>     After loading the test.lua file, you must run it because it's
>>just a function on the stack at this point. After running it your
>>declarations will have effects.
>>
>>    
>>
Does'nt lua_*call functions do it?

------------------------ some lua code ----------------------
function funk()

end
--- If the body of script does not have any code it works
------------------------ some c code -------------------------

luaL_loadfile(L, "test.lua"); // Ok
lua_call(L, 0, 0);  // Works as expected with 1st script (does nothing)
2nd script fails here

// My first message does not contains following since it failed above
lua_getglobal(L, "funk"); // funk is on top of the stack?
lua_call(L, 0, 0); // Ok, funk being called

------------------------ end of some c code ------------


but... when i run above code with this script, int msg(lua_State *L);
function gets 0x0 as function address

------------------------ another lua code ---------------
function funk()

end

msg(funk) -- msg will fail to receive address
----------------------------------------------------------------------

so lua scripts can't register their functions as callbacks :)






Reply | Threaded
Open this post in threaded view
|

RE: Calling a function defined in lua from C/C++

Jerome Vuarand-2
In reply to this post by Turgut Hakkı ÖZDEMİR
Answer to Issue One :
 
The problem with your example is that in your c code you are calling lua_tocfunction (look at the "c" between "to" and "function"), which explicitly return a pointer to a C function as Lua likes them (that is taking a lua_State* and returning an int). funk is a pure Lua function, so lua_tocfunction returns NULL.
 


De : [hidden email] [mailto:[hidden email]] De la part de Turgut Hakki ÖZDEMIR
Envoyé : 10 mai 2006 09:19
À : [hidden email]
Objet : Calling a function defined in lua from C/C++

Greetings,

I saw lua used on a cpu-hunger project, loved it (speed issues (another nearly same project, using python is running several times slower...(needless to say, i'm involved))) and start to tinker with it to embed it my own projects but i've ended up with several problems.

Issue one :) :  When i try to call lua functions from C++ code it is complaining about "attempt to call a nil value" or something similar. I've checked reference manual and wiki several times but it did not changed anything. Finally i've noticed all functions defined in lua scripts has nil values but C++, functions registered to lua are callable. Also other global variables (non function ones) appearing as they have to be.

Following code represents the problem.

Code is compiled using msvc++ 2005 express edition and lua 5.1 (compiled as c++ and linked as a static library) (i've tried whole thing also in c but the result is same)

stringf class is provided for compilation reasons and does not related with our subject :)

--- test.lua ---------------------------------
function funk()

end

msg(funk) -- will be nil
msg(msg) -- displays functions address
-------------------------------------------------

and the code

--- blabla.cpp  ----------------------------
#include <stdio.h>
#include <string>

#include <windows.h>

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

// --- printf like string formatter --------------------------
class stringf
{
  protected :
    std::string str;
  public :
    stringf(const char *fmt, ...) {
      va_list va;
      char *tmp;

      va_start(va, fmt);
      tmp = new char [vsnprintf(0, 0, fmt, va) + 1];
      vsnprintf(tmp, vsnprintf(0, 0, fmt, va) + 1, fmt, va);
      str = tmp;
      delete [] tmp;
      va_end(va);
    }

    operator const char * () {
      return str.c_str();
    }
    operator std::string () {
      return str;
    }
};

// --- Message box emulation ----------------------
int msg(lua_State *L)
{
int n = lua_gettop(L);
std::string msg;

  for (uint i = 1; i <= n; i++) {
    switch(lua_type(L, i)) {
      case LUA_TFUNCTION :
          msg += (const char *) stringf("(function) : 0x%x", lua_tocfunction(L, i));
        break;
    }

  }

  MessageBox(0, msg.c_str(), "Message", MB_OK);

return 0;
}

// --- Start crying here --------------------------
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    lua_State *L = lua_open();
    luaL_openlibs(L);
   
    luaL_loadfile(L, "test.lua");
  
    lua_register(L, "msg", msg);
   
    lua_call(L, 0, 0); // when i use lua_pcall instead of lua_call here, surrounded with error handling functionality it complains about nil values
  
    lua_close(L);
}
-----------------------------------


Issue two : How can i convert exceptions (derived from std::exception) to lua? Well, i can do it by altering luaconf.h (i think) but how are you doing this?

  C++ code starts a script
  script calls a C++ function
  C++ function gets frightened and raises an exception
  How the script can handle thrown exception?

Issue four : What about C++ interoperatability? Any wrappers? (Actually i saw one but ended up with 404 error), How can i represent my classes/objects in lua in a little bit reasonable way (saw wiki). Where is the gooooooood sample "let's involve c++" code? :)

Issue three: Unicode?



Reply | Threaded
Open this post in threaded view
|

Re: Calling a function defined in lua from C/C++

Turgut Hakkı ÖZDEMİR
Greetings,

> The problem with your  example is that in your c code you are calling lua_tocfunction (look at the "c"  between "to" and "function"), which explicitly return a pointer to a C function  as Lua likes them (that is taking a lua_State* and returning an int). funk is a  pure Lua function, so lua_tocfunction returns NULL.
>
> In manual there : http://www.lua.org/manual/5.1/manual.html#lua_tocfunction

Hmm... where is that 'c' came from :). Sorry bothering but is there
any similar function for pure lua functions? or how can i convert them
to strings? Replacing lua_tocfunction with lua_tostring giving another
null.

Another... is it possible to get from global index (lua_getglobal)
without running the script? (And without using lua internals)

It is better if i do some goooogling isn't it? :)
Reply | Threaded
Open this post in threaded view
|

RE: Calling a function defined in lua from C/C++

Jerome Vuarand-2
In reply to this post by Turgut Hakkı ÖZDEMİR
The function is not a C one, but it is on the stack. You can call it with lua_*call functions. Use lua_tostring to get a text representation of the Lua function:
int msg(lua_State *L)
{
int n = lua_gettop(L);
std::string msg;

  for (uint i = 1; i <= n; i++) {
    switch(lua_type(L, i)) {
      case LUA_TFUNCTION :
          msg += (const char *) stringf("(function) : %s", lua_tostring(L, i));
        break;
    }

  }

  MessageBox(0, msg.c_str(), "Message", MB_OK);

return 0;
}

-----Message d'origine-----
De : [hidden email] [mailto:[hidden email]] De la part de Turgut Hakki Ozdemir
Envoyé : 10 mai 2006 14:40
À : [hidden email]
Objet : Re: Calling a function defined in lua from C/C++

Greetings,

>>>
>>>     lua_call(L, 0, 0); // when i use lua_pcall instead of lua_call
>>> here, surrounded with error handling functionality it complains
>>> about nil values
>>>
>>>     lua_close(L);
>>> }
>>    
>>

>>     After loading the test.lua file, you must run it because it's
>>just a function on the stack at this point. After running it your
>>declarations will have effects.
>>
>>    
>>
Does'nt lua_*call functions do it?

------------------------ some lua code ---------------------- function funk()

end
--- If the body of script does not have any code it works
------------------------ some c code -------------------------

luaL_loadfile(L, "test.lua"); // Ok
lua_call(L, 0, 0);  // Works as expected with 1st script (does nothing) 2nd script fails here

// My first message does not contains following since it failed above lua_getglobal(L, "funk"); // funk is on top of the stack?
lua_call(L, 0, 0); // Ok, funk being called

------------------------ end of some c code ------------


but... when i run above code with this script, int msg(lua_State *L); function gets 0x0 as function address

------------------------ another lua code --------------- function funk()

end

msg(funk) -- msg will fail to receive address
----------------------------------------------------------------------

so lua scripts can't register their functions as callbacks :)





Reply | Threaded
Open this post in threaded view
|

Re: Calling a function defined in lua from C/C++

mark gossage
In reply to this post by Turgut Hakkı ÖZDEMİR
Hello,
I will try to anwser some of these area's

> Issue two : How can i convert exceptions (derived from std::exception) to
> lua? Well, i can do it by altering luaconf.h (i think) but how are you doing
> this?
>
>   C++ code starts a script
>   script calls a C++ function
>   C++ function gets frightened and raises an exception
>   How the script can handle thrown exception?
>

I maintain the Lua part of SWIG, which it as tool for wrappering C/C++ code to make it callable from within scripting languages. So this is how SWIG handles it.

Assuming I have a function
void fn() throw (std::out_of_range);

the wrappering looks a little like this

static int _wrap_fn(lua_State* L) {
  try {
    fn();
  }
  catch(std::out_of_range &_e) {
    lua_pushfstring(L,"std::out_of_range:%s",e.what());
    lua_error(L);
  }
  return 0;
}

This code will happily catch the std::out_of_range's, print the error and then calls lua_error() to report it.

> Issue four : What about C++ interoperatability? Any wrappers? (Actually i
> saw one but ended up with 404 error), How can i represent my classes/objects
> in lua in a little bit reasonable way (saw wiki). Where is the gooooooood
> sample &quot;let's involve c++&quot; code? :)
>

This gets a bit harder, I suggest either looking in PIL (Programming In Lua, http://www.lua.org/pil/), or you could look at one of the Lua wrappering tools (SWIG, tolua++, LuaBind, etc.)

Hope this helps,
Mark Gossage