Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Untangling Lua & C code to make Lua dependency optional

Tags:

c

sqlite

lua

I have written a little program in C to manage a bibliography database in SQLite3. So far, this is only a command line tool that allows importing and exporting BibTeX data. To make the export/import functionality more customizable (e.g. always combine year&month fields in the date field on import, or skip certain fields on export) these functions are written in Lua and called from C. Now I want Lua to be an optional dependency. What's a good way to do that? I.e. if at compile time Lua is not found, fall back to more basic import/export functionality.

Right now, e.g. on export I get the data from SQL (sqlite3_exec) and write it directly to a Lua table in the callback function, like so (stripped stackoverflow-handling ;-) ):

int db_meta_cb(void *udata, int n, char **cval, char **ckey) {
  while (n-- > 0) {
    lua_pushstring(L, cval[n]);
    lua_setfield(L, -2, ckey[n]);
  };
};

Then there is a Lua function that takes such a table as an argument and pretty-prints a BibTeX entry. Similar story on import: the BibTeX parser (Lex/YACC generated C code) writes a Lua table and calls a 'cleanup' Lua function, then reads the result from the same Lua table and inserts it into the database.

Now this feels wrong in the sense that I use Lua too much, I guess because the data consists of (key,value)-pairs.

Note that one reason for this project is to experiment with/learn about embedding Lua in C, so please don't suggest (a) using one of the available Bibliography managers, or (b) rewriting everything in Python or Lua entirely... (Which I have already done btw)

like image 549
1k5 Avatar asked Nov 11 '22 05:11

1k5


1 Answers

The most elegant way I have seen this issue approached is via dynamic loading. Instead of linking your program against lua, at runtime, attempt to load the library manually using the dlopen family of functions.

If this then fails you can set a global flag that you will need to resort to the other method of providing the functionality but if it succeeds use the dlsym function to get the functions out of the lua shared object and use them. You can produce a very elegant solution in which you populate some function pointers with either the lua or legacy versions, then you can simply make the decisions once and call the functions not caring which implementation is in use.

like image 178
Vality Avatar answered Nov 15 '22 10:11

Vality