• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

examples/H10-Sep-2021-348249

CHANGELOG.mdH A D10-Sep-20212.8 KiB4437

LICENSE.mdH A D10-Sep-20211.5 KiB2622

MakefileH A D10-Sep-20211.7 KiB7454

README.mdH A D10-Sep-202115 KiB468334

lautoc.cH A D10-Sep-202135.6 KiB1,305955

lautoc.hH A D10-Sep-202110.5 KiB215138

lautoc.luaH A D10-Sep-20212.4 KiB10661

lautocall.hH A D10-Sep-202133.2 KiB518418

package.jsonH A D10-Sep-2021301 109

README.md

1LuaAutoC
2========
3
4Automagically use C Functions and Structs with the Lua API
5
6Version 2.0.1
7
8```c
9#include "lautoc.h"
10
11int fib(int n) {
12  if (n == 0) { return 1; }
13  if (n == 1) { return 1; }
14  return fib(n-1) + fib(n-2);
15}
16
17int main(int argc, char** argv) {
18
19  /* Init Lua & LuaAutoC */
20  lua_State* L = luaL_newstate();
21  luaA_open(L);
22
23  /* Register `fib` function */
24  luaA_function(L, fib, int, int);
25
26  /* Push integer onto stack and call `fib` */
27  lua_pushinteger(L, 25);
28  luaA_call(L, fib);
29
30  /* Print result & pop */
31  printf("Result: %i\n", (int)lua_tointeger(L, -1));
32  lua_pop(L, 1);
33
34  luaA_close(L);
35  lua_close(L);
36
37  return 0;
38}
39```
40
41Features
42--------
43
44* Friendly API.
45* Easy to integrate (1 source file, 2 headers).
46* Existing code is unaffected.
47* Flexible, Extensible and Powerful.
48* Provides dynamic runtime reflection.
49
50
51Usage
52-----
53
54### Functions
55
56At 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 `luaA_function`, and then at any point later it can be called with `luaA_call`.
57
58```c
59#include "lautoc.h"
60
61float power(float val, int pow) {
62  float x = 1.0;
63  for(int i = 0; i < pow; i++) {
64    x = x * val;
65  }
66  return x;
67}
68
69int main(int argc, char **argv) {
70
71  lua_State* L = luaL_newstate();
72  luaA_open(L);
73
74  luaA_function(L, power, float, float, int);
75
76  lua_pushnumber(L, 4.2);
77  lua_pushinteger(L, 3);
78  luaA_call(L, power);
79
80  printf("Result: %f\n", lua_tonumber(L, -1));
81  lua_pop(L, 1);
82
83  luaA_close(L);
84  lua_close(L);
85
86  return 0;
87}
88```
89
90### Structs
91
92LuaAutoC 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.
93
94```c
95typedef struct {
96  float x, y, z;
97} vec3;
98```
99
100As with functions first they need to be registered.
101
102```c
103luaA_struct(L, vec3);
104luaA_struct_member(L, vec3, x, float);
105luaA_struct_member(L, vec3, y, float);
106luaA_struct_member(L, vec3, z, float);
107```
108
109And then they can be used with the Lua API.
110
111```c
112vec3 pos = {1.0f, 2.11f, 3.16f};
113
114luaA_struct_push_member(L, vec3, x, &pos);
115printf("x: %f\n", lua_tonumber(L, -1));
116lua_pop(L, 1);
117
118lua_pushnumber(L, 0.0);
119luaA_struct_to_member(L, vec3, x, &pos, -1);
120lua_pop(L, 1);
121
122luaA_struct_push_member(L, vec3, x, &pos);
123printf("x: %f\n", lua_tonumber(L, -1));
124lua_pop(L, 1);
125```
126
127### Conversion
128
129To use LuaAutoC with non-native types it is possible to register your own conversion functions.
130
131```c
132typedef struct {
133  int fst, snd;
134} pair;
135
136static int luaA_push_pair(lua_State* L, luaA_Type t, const void* c_in) {
137  pair* p = (pair*)c_in;
138  lua_pushinteger(L, p->fst);
139  lua_pushinteger(L, p->snd);
140  return 2;
141}
142
143static void luaA_to_pair(lua_State* L, luaA_Type t, void* c_out, int index) {
144  pair* p = (pair*)c_out;
145  p->snd = lua_tointeger(L, index);
146  p->fst = lua_tointeger(L, index-1);
147}
148```
149
150These are registered with `luaA_conversion`.
151
152```c
153luaA_conversion(L, pair, luaA_push_pair, luaA_to_pair);
154```
155
156And 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 `luaA_push` and `luaA_to`. For example to push a pair onto the stack...
157
158```c
159pair p = {1, 2};
160luaA_push(L, pair, &p);
161```
162
163Essentially registering a conversion is all that is required to make that type available from the whole of LuaAutoC.
164
165But 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!
166
167```c
168typedef struct {
169  int id;
170  int legs;
171  float height;
172} table;
173```
174
175```c
176luaA_struct(L, table);
177luaA_struct_member(L, table, id, int);
178luaA_struct_member(L, table, legs, int);
179luaA_struct_member(L, table, height, float);
180```
181
182```c
183table t = {0, 4, 0.72};
184
185luaA_push(L, table, &t);
186
187lua_getfield(L, -1, "legs");
188printf("legs: %i\n", (int)lua_tointeger(L, -1));
189lua_pop(L, 1);
190
191lua_getfield(L, -1, "height");
192printf("height: %f\n", lua_tonumber(L, -1));
193lua_pop(L, 1);
194
195lua_pop(L, 1);
196```
197
198This is very useful, but a few words of warning.
199
200* Be careful with circular references. The conversion is recursive and given the chance will happily run forever!
201* Be careful of pointer types such as `char*`. An automatic conversion may just assign a new pointer and might not do the intended behaviour, of copying the contents pointed to. This can sometimes screw up the garbage collector.
202
203### Enums
204
205Enums can be used too. They are transformed into string, value mappings.
206
207Again 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.
208
209```c
210typedef enum {
211  DIAMONDS,
212  HEARTS,
213  CLUBS,
214  SPADES,
215  INVALID = -1
216} cards;
217```
218
219```c
220luaA_enum(L, cards);
221luaA_enum_value(L, cards, DIAMONDS);
222luaA_enum_value(L, cards, HEARTS);
223luaA_enum_value(L, cards, CLUBS);
224luaA_enum_value(L, cards, SPADES);
225luaA_enum_value(L, cards, INVALID);
226```
227
228```c
229cards cval = SPADES;
230const char* lval = "SPADES";
231
232luaA_push(L, cards, &cval);
233printf("%i pushed as %s\n", cval, lua_tostring(L, -1));
234lua_pop(L, 1);
235
236lua_pushstring(L, lval);
237luaA_to(L, cards, &cval, -1);
238printf("%s read back as %i\n", lval, cval);
239lua_pop(L, 1);
240```
241
242### Quick & Dirty Interface
243
244Because 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.
245
246Given some set of functions.
247
248```c
249/* Hello Module Begin */
250
251void hello_world(void) {
252  puts("Hello World!");
253}
254
255void hello_repeat(int times) {
256  for (int i = 0; i < times; i++) {
257    hello_world();
258  }
259}
260
261void hello_person(const char* person) {
262  printf("Hello %s!\n", person);
263}
264
265int hello_subcount(const char* greeting) {
266  int count = 0;
267  const char *tmp = greeting;
268  while((tmp = strstr(tmp, "hello"))) {
269    count++; tmp++;
270  }
271  return count;
272}
273
274/* Hello Module End */
275```
276
277We 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.
278
279```c
280int C(lua_State* L) {
281  return luaA_call_name(L, lua_tostring(L, 1));
282}
283```
284
285We then just need to register those functions, and also register the `C` function to be avaliable from Lua.
286
287```c
288luaA_function(L, hello_world, void);
289luaA_function(L, hello_repeat, void, int);
290luaA_function(L, hello_person, void, const char*);
291luaA_function(L, hello_subcount, int, const char*);
292
293lua_register(L, "C", C);
294```
295
296And now we can call our C functions from Lua easily!
297
298```c
299luaL_dostring(L,
300  "C('hello_world')\n"
301  "C('hello_person', 'Daniel')\n"
302  "C('hello_repeat', C('hello_subcount', 'hello hello'))\n"
303);
304```
305
306You can then wrap this function in whatever Lua interface you like. One nice idea is to create a table and set it's `__index` metamethod to return the C function of the same name.
307
308```lua
309Hello = {}
310Hello.__index = function (table, key)
311  return function (...)
312    return C(key, ...)
313  end
314end
315
316setmetatable(Hello, Hello)
317
318Hello.hello_world()
319Hello.hello_person('Marcelo')
320```
321
322### Advanced Interface
323
324Using LuaAutoC it is easy to wrap pointers to structs so that they act like object instances. All we need to do is set `__index` and `__newindex` in the metatable.
325
326```lua
327Birdie = {}
328setmetatable(Birdie, Birdie)
329
330function Birdie.__call()
331  local self = {}
332  setmetatable(self, Birdie)
333  return self
334end
335
336Birdie.__index = birdie_index
337Birdie.__newindex = birdie_newindex
338
339bird = Birdie()
340print(bird.name)
341print(bird.num_wings)
342bird.num_wings = 3
343print(bird.num_wings)
344```
345
346Now we just define `birdie_index` and `birdie_newindex` in the C API as shown below. Alternatively developers can define the whole metatable in C and hide the `birdie_newindex` and `birdie_index` functions altogether.
347
348```c
349typedef struct {
350  char* name;
351  int num_wings;
352} birdie;
353
354int birdie_index(lua_State* L) {
355  const char* membername = lua_tostring(L, -1);
356  birdie* self = get_instance_ptr(L);
357  return luaA_struct_push_member_name(L, birdie, membername, self);
358}
359
360int birdie_newindex(lua_State* L) {
361  const char* membername = lua_tostring(L, -2);
362  birdie* self = get_instance_ptr(L);
363  luaA_struct_to_member_name(L, birdie, membername, self, -1);
364  return 0;
365}
366```
367
368```c
369luaA_struct(L, birdie);
370luaA_struct_member(L, birdie, name, char*);
371luaA_struct_member(L, birdie, num_wings, int);
372
373lua_register(L, "birdie_index", birdie_index);
374lua_register(L, "birdie_newindex", birdie_newindex);
375```
376
377This is a great way to avoid having to write a bunch of getters and setters!
378
379The `get_instance_ptr` function is left for the user to implement and there are lots of options. The idea is that somehow the Lua table/instance should tell you how to get a pointer to the actual struct instance in C which it represents. A good option is to store C pointers in the Lua table.
380
381It 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!
382
383The true power of Lua AutoC comes if you look a level deeper. If you use `luaA_struct_push_member_name_type` or `luaA_truct_to_member_name_type` you can even generalize the above code to work for arbitrary structs/classes/types. Then when other developers create new structs and types, they can register them with your system to make them trivial to access from Lua.
384
385For this to work you need to get a `luaA_Type` value. This can be found by feeding a string into `luaA_type_find` which will lookup a string and see if a type has been registered with the same name. This means that if you give it a string of a previously registered data type E.G `"birdie"`, it will return a matching id. One trick is to feed it with the name of the instance's metatable. This means it is possible to create a new Lua object with defined `__index` and `__newindex`, it will automatically act like the corresponding C struct of the same name.
386
387### Managing Behaviour
388
389Often in C, the same types can have different meanings. For example an `int*` could either mean that a function wants an array of integers or that it outputs some integer. We can change the behaviour of Lua AutoC without changing the function signature by using typedefs and new conversion functions. Then on function registration you just use the newly defined type rather than the old one. Providing the types are true aliases there wont be any problems with converting types.
390
391```c
392static void print_int_list(int* list, int num_ints) {
393  for(int i = 0; i < num_ints; i++) {
394    printf("Int %i: %i\n", i, list[i]);
395  }
396}
397
398typedef int* int_list;
399
400static int list_space[512];
401static void luaA_to_int_list(lau_State* L, luaA_Type t, void* c_out, int index) {
402  for(int i = 1; i <= luaL_getn(L, index); i++) {
403    lua_pushinteger(L, i);
404    lua_gettable(L, index-1);
405	  list_space[i] = lua_tointeger(L, index); lua_pop(L, 1);
406  }
407  *(int_list*)c_out = list_space;
408}
409
410luaA_conversion_to(int_list, luaA_to_int_list);
411
412luaA_function(print_int_list, void, int_list, int);
413```
414
415As you can probably see, automatic wrapping and type conversion becomes hard when memory management and pointers are involved.
416
417
418Headers
419-------
420
421It 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.
422
423```
424$ lua lautoc.lua ../Corange/include/assets/sound.h
425
426luaA_struct(sound);
427luaA_struct_member(sound, data, char*);
428luaA_struct_member(sound, length, int);
429
430luaA_function(wav_load_file, sound*, char*);
431luaA_function(sound_delete, void, sound*);
432```
433
434Internals
435---------
436
437LuaAutoC works by storing meta-information about C types, structs, and functions in the Lua registry.
438
439This 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.
440
441It 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!
442
443
444FAQ
445---
446
447* How do unions work?
448
449  They work the same way as structs. All the `luaA_struct` functions should be fine to use on them. Like in C though, accessing them "incorrectly" in Lua will result in the raw data being interpreted differently. Lua AutoC doesn't do any clever checking for you.
450
451* Function Pointer Casts?
452
453  LuaAutoC casts function pointers to `void*` so that they can be used in the Lua ecosystem. For this reason it may not work on a platform that disallows these sorts of casts.
454
455* Nested Functions?
456
457  By standard LuaAutoC makes uses of nested functions. Almost all compilers support these, but if not LuaAutoC can still be used. Instead functions must be "declared" outside of the program, and then "registered" in the runtime. See `example_unnested.c` for a clear example.
458
459* Is LuaAutoC slow?
460
461  The short answer is no. For most uses LuaAutoC has to lookup runtime information in the Lua registry, and for calling functions it has to duplicate some of the process involved in managing the stack, but for any normal codebase this overhead is minimal. If you are concerned about performance you can still wrap your functions manually, but perhaps if you are using a scripting language like Lua it wont be worth it anyway.
462
463* Is this just macro hacks? Can I really use it in production code?
464
465  There are certainly some macro tricks going on, but the backbone code is very simple. The macros just save typing. I know that it has been used successfully in production in [darktable](https://github.com/darktable-org/darktable) and probably elsewhere. Even so, if you are worried send me an email and I'll explain the internals so that you can decide for yourself. I've also written a short blog post about it [here](http://theorangeduck.com/page/autoc-tools).
466
467
468