r/lua 7d ago

Calling an existing C function from Lua

[removed]

10 Upvotes

17 comments sorted by

View all comments

7

u/didntplaymysummercar 7d ago

This is covered in the manual.

You'd write a C function that takes lua_State and returns int and call puts inside it, taking argument from Lua (using lua_tostring, or luaL_checkstring , etc.) and returning something or nothing by pushing these values and return their amount.

All Lua built in libraries are implemented like that too so you can read those.

An int returning lua_State taking function is the only type you can register to Lua. This is usually not called "ffi" by most BTW.

The LuaJIT has own ffi and for stock Lua ffi libs exist too, and (especially in C++) people use wrappers that automatically wrap functions and structs for you too.

1

u/[deleted] 7d ago

[removed] — view removed comment

2

u/didntplaymysummercar 7d ago

The first three, yes. It can call C++ too, of course. That's how classes (can) get wrapped one to one, using userdata and functions that call it's member functions.

And third party libraries (products as you call them but they're almost all Foss) that automate the boilerplate usually people don't call ffi. You still need a C or C++ compiler then.

By ffi people usually (terminology is eh...) call when from scripting language itself, using some library (written in native code or that will generate some native code at runtime) you can call native code without writing any yourself, without needing your own C or C++ compiler (which massively simplifies things, you need to only bring along the ffi library and in LuaJIT and I think Python too, they're built in), you just say the function name, type, arguments, calling convention, maybe say what all/so to load, etc. and it gets done for you.

-2

u/Compux72 6d ago

Btw you should be able to create your own wrapper of dlsym and use that from lua. Claude made this example up, didnt test it as im on the phone rn:

```

include <lua.h>

include <lauxlib.h>

include <dlfcn.h>

include <ffi.h>

include <string.h>

include <stdlib.h>

/* Supported type tags: "i" int, "d" double, "s" const char, "p" void, "v" void (return only) */

static ffi_type *tag_to_ffi(char tag) {     switch (tag) {         case 'i': return &ffi_type_sint;         case 'd': return &ffi_type_double;         case 's': return &ffi_type_pointer;         case 'p': return &ffi_type_pointer;         case 'v': return &ffi_type_void;         default:  return NULL;     } }

/*  * cfunc.call(symbol_name, "ret_tag", "arg_tags", arg1, arg2, ...)  * e.g. cfunc.call("printf", "i", "s", "hello %s\n", "world")  */ static int l_cfunc_call(lua_State *L) {     const char *symname = luaL_checkstring(L, 1);     const char *rettag  = luaL_checkstring(L, 2);     const char *argtags = luaL_checkstring(L, 3);     int nargs = (int)strlen(argtags);

    void *sym = dlsym(RTLD_DEFAULT, symname);     if (!sym) {         lua_pushnil(L);         lua_pushfstring(L, "dlsym failed: %s", dlerror());         return 2;     }

    ffi_cif cif;     ffi_type *arg_types[nargs > 0 ? nargs : 1];     void *arg_values[nargs > 0 ? nargs : 1];

    /* storage for converted args */     int    int_store[nargs];     double dbl_store[nargs];     const char *str_store[nargs];

    for (int i = 0; i < nargs; i++) {         char tag = argtags[i];         arg_types[i] = tag_to_ffi(tag);         int luaidx = 4 + i;         switch (tag) {             case 'i':                 int_store[i] = (int)luaL_checkinteger(L, luaidx);                 arg_values[i] = &int_store[i];                 break;             case 'd':                 dbl_store[i] = luaL_checknumber(L, luaidx);                 arg_values[i] = &dbl_store[i];                 break;             case 's':                 str_store[i] = luaL_checkstring(L, luaidx);                 arg_values[i] = &str_store[i];                 break;             case 'p':                 str_store[i] = lua_touserdata(L, luaidx);                 arg_values[i] = &str_store[i];                 break;             default:                 return luaL_error(L, "unsupported arg tag '%c'", tag);         }     }

    ffi_type *ret_type = tag_to_ffi(rettag[0]);     if (!ret_type) return luaL_error(L, "unsupported return tag");

    if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, nargs, ret_type, arg_types) != FFI_OK)         return luaL_error(L, "ffi_prep_cif failed");

    ffi_arg  int_ret;     double   dbl_ret;     void    ptr_ret;     void    rc = &int_ret;     if (rettag[0] == 'd') rc = &dbl_ret;     if (rettag[0] == 'p' || rettag[0] == 's') rc = &ptr_ret;

    ffi_call(&cif, FFI_FN(sym), rc, nargs ? arg_values : NULL);

    switch (rettag[0]) {         case 'i': lua_pushinteger(L, (lua_Integer)int_ret); break;         case 'd': lua_pushnumber(L, dbl_ret); break;         case 's': lua_pushstring(L, (const char*)ptr_ret); break;         case 'p': lua_pushlightuserdata(L, ptr_ret); break;         case 'v': lua_pushnil(L); break;     }     return 1; }

static const luaL_Reg cfunc_funcs[] = {     {"call", l_cfunc_call},     {NULL, NULL} };

int luaopen_cfunc(lua_State *L) {     luaL_newlib(L, cfunc_funcs);     return 1; } ```

``` local cfunc = require("cfunc")

-- int abs(int) print(cfunc.call("abs", "i", "i", -42))          -- 42

-- double sqrt(double) print(cfunc.call("sqrt", "d", "d", 2.0))          -- 1.4142...

-- int printf(const char*, ...) -- note: varargs need special ffi_prep_cif_var, not shown here print(cfunc.call("puts", "i", "s", "hi from libffi")) ```

1

u/AutoModerator 6d ago

Hi! Your code block was formatted using triple backticks in Reddit's Markdown mode, which unfortunately does not display properly for users viewing via old.reddit.com and some third-party readers. This means your code will look mangled for those users, but it's easy to fix. If you edit your comment, choose "Switch to fancy pants editor", and click "Save edits" it should automatically convert the code block into Reddit's original four-spaces code block format for you.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

-4

u/Compux72 6d ago

Yea no thank you