在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):orangeduck/LuaAutoC开源软件地址(OpenSource Url):https://github.com/orangeduck/LuaAutoC开源编程语言(OpenSource Language):C 95.1%开源软件介绍(OpenSource Introduction):LuaAutoCAutomagically use C Functions and Structs with the Lua API Version 2.0.1 #include "lautoc.h"
int fib(int n) {
if (n == 0) { return 1; }
if (n == 1) { return 1; }
return fib(n-1) + fib(n-2);
}
int main(int argc, char** argv) {
/* Init Lua & LuaAutoC */
lua_State* L = luaL_newstate();
luaA_open(L);
/* Register `fib` function */
luaA_function(L, fib, int, int);
/* Push integer onto stack and call `fib` */
lua_pushinteger(L, 25);
luaA_call(L, fib);
/* Print result & pop */
printf("Result: %i\n", (int)lua_tointeger(L, -1));
lua_pop(L, 1);
luaA_close(L);
lua_close(L);
return 0;
} Features
UsageFunctionsAt its most basic, LuaAutoC can be used to automatically call C functions from the Lua API. Lua stack arguments are automatically popped and converted to C types, the function is executed, and the return value is then converted back to a Lua type and placed on top the stack. First the function must be registered with #include "lautoc.h"
float power(float val, int pow) {
float x = 1.0;
for(int i = 0; i < pow; i++) {
x = x * val;
}
return x;
}
int main(int argc, char **argv) {
lua_State* L = luaL_newstate();
luaA_open(L);
luaA_function(L, power, float, float, int);
lua_pushnumber(L, 4.2);
lua_pushinteger(L, 3);
luaA_call(L, power);
printf("Result: %f\n", lua_tonumber(L, -1));
lua_pop(L, 1);
luaA_close(L);
lua_close(L);
return 0;
} StructsLuaAutoC also provides functions to deal with structs. Their members can be pushed onto or read from the stack, with automatic conversion of types between Lua and C provided. typedef struct {
float x, y, z;
} vec3; As with functions first they need to be registered. luaA_struct(L, vec3);
luaA_struct_member(L, vec3, x, float);
luaA_struct_member(L, vec3, y, float);
luaA_struct_member(L, vec3, z, float); And then they can be used with the Lua API. vec3 pos = {1.0f, 2.11f, 3.16f};
luaA_struct_push_member(L, vec3, x, &pos);
printf("x: %f\n", lua_tonumber(L, -1));
lua_pop(L, 1);
lua_pushnumber(L, 0.0);
luaA_struct_to_member(L, vec3, x, &pos, -1);
lua_pop(L, 1);
luaA_struct_push_member(L, vec3, x, &pos);
printf("x: %f\n", lua_tonumber(L, -1));
lua_pop(L, 1); ConversionTo use LuaAutoC with non-native types it is possible to register your own conversion functions. typedef struct {
int fst, snd;
} pair;
static int luaA_push_pair(lua_State* L, luaA_Type t, const void* c_in) {
pair* p = (pair*)c_in;
lua_pushinteger(L, p->fst);
lua_pushinteger(L, p->snd);
return 2;
}
static void luaA_to_pair(lua_State* L, luaA_Type t, void* c_out, int index) {
pair* p = (pair*)c_out;
p->snd = lua_tointeger(L, index);
p->fst = lua_tointeger(L, index-1);
} These are registered with luaA_conversion(L, pair, luaA_push_pair, luaA_to_pair); And are then automatically used in the calling of functions, or in the conversion of structs and their members. Registered conversions are also available directly for manipulation of the Lua stack using pair p = {1, 2};
luaA_push(L, pair, &p); Essentially registering a conversion is all that is required to make that type available from the whole of LuaAutoC. But who wants to write a bunch of conversion functions? When structs are registered with LuaAutoC, if no conversion functions are registered, automatic conversion to a Lua table is performed. So in reality writing conversions is a rare thing! typedef struct {
int id;
int legs;
float height;
} table; luaA_struct(L, table);
luaA_struct_member(L, table, id, int);
luaA_struct_member(L, table, legs, int);
luaA_struct_member(L, table, height, float); table t = {0, 4, 0.72};
luaA_push(L, table, &t);
lua_getfield(L, -1, "legs");
printf("legs: %i\n", (int)lua_tointeger(L, -1));
lua_pop(L, 1);
lua_getfield(L, -1, "height");
printf("height: %f\n", lua_tonumber(L, -1));
lua_pop(L, 1);
lua_pop(L, 1); This is very useful, but a few words of warning.
EnumsEnums can be used too. They are transformed into string, value mappings. Again they need to be registered. Multiple strings can be registered for a single value, and any matching Lua string will be transformed into the C value. But if a value has multiple strings, the last registered string will be used when transforming from C to Lua. typedef enum {
DIAMONDS,
HEARTS,
CLUBS,
SPADES,
INVALID = -1
} cards; luaA_enum(L, cards);
luaA_enum_value(L, cards, DIAMONDS);
luaA_enum_value(L, cards, HEARTS);
luaA_enum_value(L, cards, CLUBS);
luaA_enum_value(L, cards, SPADES);
luaA_enum_value(L, cards, INVALID); cards cval = SPADES;
const char* lval = "SPADES";
luaA_push(L, cards, &cval);
printf("%i pushed as %s\n", cval, lua_tostring(L, -1));
lua_pop(L, 1);
lua_pushstring(L, lval);
luaA_to(L, cards, &cval, -1);
printf("%s read back as %i\n", lval, cval);
lua_pop(L, 1); Quick & Dirty InterfaceBecause LuaAutoC stores meta-information and registered functions and types, this lets you call C functions just by providing a string of their name. Using this it is really easy to make a quick and dirty interface to your C library, which can later be extended and wrapped nicely on the Lua side of things. Given some set of functions. /* Hello Module Begin */
void hello_world(void) {
puts("Hello World!");
}
void hello_repeat(int times) {
for (int i = 0; i < times; i++) {
hello_world();
}
}
void hello_person(const char* person) {
printf("Hello %s!\n", person);
}
int hello_subcount(const char* greeting) {
int count = 0;
const char *tmp = greeting;
while((tmp = strstr(tmp, "hello"))) {
count++; tmp++;
}
return count;
}
/* Hello Module End */ We can create a Lua function that takes some function name as a string, and some other arguments, and calls the matching C function with that name. int C(lua_State* L) {
return luaA_call_name(L, lua_tostring(L, 1));
} We then just need to register those functions, and also register the luaA_function(L, hello_world, void);
luaA_function(L, hello_repeat, void, int);
luaA_function(L, hello_person, void, const char*);
luaA_function(L, hello_subcount, int, const char*);
lua_register(L, "C", C); And now we can call our C functions from Lua easily! luaL_dostring(L,
"C('hello_world')\n"
"C('hello_person', 'Daniel')\n"
"C('hello_repeat', C('hello_subcount', 'hello hello'))\n"
); You can then wrap this function in whatever Lua interface you like. One nice idea is to create a table and set it's Hello = {}
Hello.__index = function (table, key)
return function (...)
return C(key, ...)
end
end
setmetatable(Hello, Hello)
Hello.hello_world()
Hello.hello_person('Marcelo') Advanced InterfaceUsing LuaAutoC it is easy to wrap pointers to structs so that they act like object instances. All we need to do is set Birdie = {}
setmetatable(Birdie, Birdie)
function Birdie.__call()
local self = {}
setmetatable(self, Birdie)
return self
end
Birdie.__index = birdie_index
Birdie.__newindex = birdie_newindex
bird = Birdie()
print(bird.name)
print(bird.num_wings)
bird.num_wings = 3
print(bird.num_wings) Now we just define typedef struct {
char* name;
int num_wings;
} birdie;
int birdie_index(lua_State* L) {
const char* membername = lua_tostring(L, -1);
birdie* self = get_instance_ptr(L);
return luaA_struct_push_member_name(L, birdie, membername, self);
}
int birdie_newindex(lua_State* L) {
const char* membername = lua_tostring(L, -2);
birdie* self = get_instance_ptr(L);
luaA_struct_to_member_name(L, birdie, membername, self, -1);
return 0;
} luaA_struct(L, birdie);
luaA_struct_member(L, birdie, name, char*);
luaA_struct_member(L, birdie, num_wings, int);
lua_register(L, "birdie_index", birdie_index);
lua_register(L, "birdie_newindex", birdie_newindex); This is a great way to avoid having to write a bunch of getters and setters! The It is also possible to make the Lua metatable allocation and deallocation functions call some C functions which allocate and decallocate the structure you are emulating, storing the instance pointer to let you identify it later! Not only that. It isn't difficult to make methods available too! The true power of Lua AutoC comes if you look a level deeper. If you use For this to work you need to get a Managing BehaviourOften in C, the same types can have different meanings. For example an static void print_int_list(int* list, int num_ints) {
for(int i = 0; i < num_ints; i++) {
printf("Int %i: %i\n", i, list[i]);
}
}
typedef int* int_list;
static int list_space[512];
static void luaA_to_int_list(lau_State* L, luaA_Type t, void* c_out, int index) {
for(int i = 1; i <= luaL_getn(L, index); i++) {
lua_pushinteger(L, i);
lua_gettable(L, index-1);
list_space[i] = lua_tointeger(L, index); lua_pop(L, 1);
}
*(int_list*)c_out = list_space;
}
luaA_conversion_to(int_list, luaA_to_int_list);
luaA_function(print_int_list, void, int_list, int); As you can probably see, automatic wrapping and type conversion becomes hard when memory management and pointers are involved. HeadersIt isn't any fun writing out all the registration functions, so I've included a basic Lua script which will auto-generate LuaAutoC code for structs and functions from C header files. In general it works pretty well, but it is fairly basic, not a C parser, and wont cover all situations, so expect to have to do some cleaning up for complicated headers.
InternalsLuaAutoC works by storing meta-information about C types, structs, and functions in the Lua registry. This allows it to automatically do conversions at runtime. In my opinion this is a far better approach than compile-time wrapping such as is available from programs such as SWIG. Because all the type information is stored in the Lua registry this allows for the use reflection techniques to ensure you build a Lua API that really does match the concepts of your C program. In essence LuaAutoC lets you build a powerful and complex API on the C side of things. It also means that LuaAutoC is completely un-intrusive, and can be used without touching your original codebase. There is no marking it up or wrapping to be done. Finally, because it is a runtime system, it can be changed, adapted and extended by other developers. You can actually provide functions for developers to use that generate new bindings for their functions, types, or structs, without them having to know a thing about Lua! FAQ
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论