El mié, 20 de oct. de 2021 a la(s) 15:01, Sean Conner (
sean@conman.org) escribió:
It was thus said that the Great Jairo A. del Rio once stated:
> Hi, list. I'm trying to understand how to write Lua modules from C (I use
> GSL as an example). Code is below.
I have many C based Lua modules written by hand, you can look at:
https://github.com/spc476/lua-conmanorg/tree/master/src
Cool. I'm gonna take a look at them soon.
The closest one I have to what you are trying to do is tcc.c. I don't
think you need to really understand what it does (it wraps the Tiny C
compiler as a Lua module).
In any case, let's go through your code:
> #include <gsl/gsl_vector.h>
> #include "lua.h"
> #include "lauxlib.h"
>
> #define VECTOR_MT "GSL vector"
>
> static int vector_new(lua_State *L)
> {
> int i;
> int n = lua_gettop(L);
> gsl_vector *t = gsl_vector_alloc(n);
> for (i = 0; i < n; i++)
> {
> gsl_vector_set(t, i, luaL_checknumber(L,i+1));
> }
> //Is this right?
> gsl_vector *r = (gsl_vector *)lua_newuserdata(L, sizeof(gsl_vector));
> *r = *t;
> luaL_getmetatable(L, VECTOR_MT);
> lua_setmetatable(L, -2);
> return 1;
> }
Almost there---
static int vector_new(lua_State *L)
{
int i;
int n = lua_gettop(L);
gsl_vector *v = gsl_vector_alloc(n);
for (i = 0 ; i < n ; i++)
gsl_vector_set(v,i,luaL_checknumber(L,i + 1));
gal_vector **r = lua_newuserdata(L,sizeof(gsl_vector *)); /* [1] */
*r = v;
luaL_setmetatable(L,VECTOR_MT); /* [2] */
return 1;
}
[1] Since the GLS library is doing the allocation, let it. Here, we are
defining r to be a pointer to a pointer to a GSL vector, which is
the space that Lua will manage. You will need to add a __gc
metamethod though. This will work:
static int vector___gc(lua_State *L)
{
gsl_vector **v = luaL_checkudata(L,1,VECTOR_MT); /* [3] */
if (*r != NULL)
{
gsl_vector_free(*r); /* [4] */
*r = NULL;
}
return 0;
}
[2] If you are using Lua 5.1, you can replace this function with:
luaL_getmetatable(L,VECTOR_MT);
lua_setmetatable(L,-2);
[3] If you are using a C compiler (and NOT a C++ compiler) you don't
need the pointer casts. Also, what you are getting back here is a
pointer to a pointer to a GSL thing.
It makes sense
[4] Since we have a pointer to a pointer to a GSL objet, this will
dereference the pointer-to-pointer to get the pointer.
> static int vector_get(lua_State *L)
> {
> gsl_vector *v = (gsl_vector *)lua_touserdata(L,1);
> int max = (int)v->size;
> int n = luaL_checkinteger(L,2)-1;
> if ((0<=n) && (n <= max))
> lua_pushnumber(L, gsl_vector_get(v,n));
> else
> lua_pushnil(L);
> return 1;
> }
gsl_vector **r = luaL_checkudata(L,1,VECTOR_MT);
gsl_vector *v = *r; /* get to the actual object */
The rest is fine.
> static int vector_m_add(lua_State *L)
> {
> gsl_vector *v1 = (gsl_vector *)lua_touserdata(L,1);
> gsl_vector *v2 = (gsl_vector *)lua_touserdata(L,2);
> if ((v1 -> size) == (v2 -> size))
> {
> // I'm not sure whether this is right or not, but it seems to work so far
> gsl_vector *t = gsl_vector_alloc(v1 -> size);
> gsl_vector_memcpy(t, v1);
> gsl_vector_add(t,v2);
> gsl_vector *r = (gsl_vector *)lua_newuserdata(L, sizeof(gsl_vector));
> luaL_getmetatable(L, VECTOR_MT);
> lua_setmetatable(L, -2);
> *r = *t;
> }
> else
> {
> lua_pushnil(L);
> }
> return 1;
> }
Follow the code in vector_new().
[ snip rest of code---no comments, looked decent ]
> I have two questions:
>
> 1. Am I right wrt "new", i.e., the way userdata is created?
Not quite. You're close though.
> 2. According to some docs I've read, userdata content should be freed by
> defining a function for __gc. However, I don't understand when or how to do
> that, as defining a function using gsl_vector_free in the case above is
> giving me an error prompt complaining about an invalid pointer.
That's probably because you're passing in memory allocated by Lua and the
GSL library is getting confused. See the vector___gc() function for how to
do this safely.
> I don't want a ready-made application to create bindings to GSL or an
> already existing one (I think two are freely available in GitHub) as I only
> use it as an example. I don't want a Lua solution, either (I know how to do
> that using pure Lua). Instead, I want to better understand the way Lua
> modules are defined when C is used, and perhaps to better understand C
> given that pointers are not intuitive for me. Thank you in advance and
> sorry for any inconvenience caused by this noob question.
Don't apologize---you tried, and you showed your work. That's commendable
in and of itself. Yes, pointers in C can be confusing, especially pointers
to pointers (which, unfortunately, you need here). I hope the code I
presented will help you in your endevour.
Yes. In fact, by reading your code I think I understand C pointers a bit better. With Luiz's comments and yours included, my module finally works! Thank you very much.
Best regards,
Jairo
-spc