Litt's Lua Laboratory:

Calling a C Function From Lua

(With Snippets)

Contents

Introduction

Anatomy of a Lua to C Call



#!/usr/bin/lua

require("power")

print(square(1.414213598))

print(cube(5))



require("power")

square()

cube()

square()

cube()

require("power")

Looks for something called power.so . Upon finding power.so , it looks for a function within power.so , called luaopen_power() to run. How did Lua magically come up with that particular function name? Simple -- the argument to the Lua require() statement is "power", so it looks for a function with that string appended to "luaopen_".



require()

int luaopen_power(lua_State *L){

lua_register(

L, /* Lua state variable */

"square", /* func name as known in Lua */

isquare /* func name in this file */

);

lua_register(L,"cube",icube);

return 0;

}



lua_register()

lua_register()

The Lua state variable The name of the function as seen from Lua, expressed as a string A pointer to the function in the C program



require("power")

power.so

luaopen_power()

static int isquare(lua_State *L){ /* Internal name of func */

float rtrn = lua_tonumber(L, -1); /* Get the single number arg */

printf("Top of square(), nbr=%f

",rtrn);

lua_pushnumber(L,rtrn*rtrn); /* Push the return */

return 1; /* One return value */

}



lua_tonumber(L,-1)

lua_pushnumber(L,rtrn*rtrn)

slitt@mydesk:~$ gcc -Wall -shared -fPIC -o power.so -I/usr/include/lua5.1 -llua5.1 hellofunc.c

slitt@mydesk:~$



ARG



MEANING

gcc



The compiler

-Wall



Warn on almost anything

-shared



Compile to .so format, and don't error out just because there's no main()

-fPIC



Goes with -shared to tell the executable format. Subtle errors can sometimes creep in if you don't do this.

-o power.so



Name the shared library power.so

-I/usr/include/lua5.1



Look for lua.h etc in /usr/include/lua5.1. Note this will be different on every system.

-llua5.1



Compile with the Lua library. Note this will be different on every system. See here for how you deduce the -l argument.

hellofunc.c



The source file to the power library. It doesn't have to be named "power".



Putting It All Together

/* hellofunc.c (C) 2011 by Steve Litt

* gcc -Wall -shared -fPIC -o power.so -I/usr/include/lua5.1 -llua5.1 hellofunc.c

* Note the word "power" matches the string after the underscore in

* function luaopen_power(). This is a must.

* The -shared arg lets it compile to .so format.

* The -fPIC is for certain situations and harmless in others.

* On your computer, the -I and -l args will probably be different.

*/



#include <lua.h> /* Always include this */

#include <lauxlib.h> /* Always include this */

#include <lualib.h> /* Always include this */



static int isquare(lua_State *L){ /* Internal name of func */

float rtrn = lua_tonumber(L, -1); /* Get the single number arg */

printf("Top of square(), nbr=%f

",rtrn);

lua_pushnumber(L,rtrn*rtrn); /* Push the return */

return 1; /* One return value */

}

static int icube(lua_State *L){ /* Internal name of func */

float rtrn = lua_tonumber(L, -1); /* Get the single number arg */

printf("Top of cube(), number=%f

",rtrn);

lua_pushnumber(L,rtrn*rtrn*rtrn); /* Push the return */

return 1; /* One return value */

}





/* Register this file's functions with the

* luaopen_libraryname() function, where libraryname

* is the name of the compiled .so output. In other words

* it's the filename (but not extension) after the -o

* in the cc command.

*

* So for instance, if your cc command has -o power.so then

* this function would be called luaopen_power().

*

* This function should contain lua_register() commands for

* each function you want available from Lua.

*

*/

int luaopen_power(lua_State *L){

lua_register(

L, /* Lua state variable */

"square", /* func name as known in Lua */

isquare /* func name in this file */

);

lua_register(L,"cube",icube);

return 0;

}



gcc -Wall -shared -fPIC -o power.so -I/usr/include/lua5.1 -llua5.1 hellofunc.c



hellofunc.lua

#!/usr/bin/lua

require("power")

print(square(1.414213598))

print(cube(5))



hellofunc.lua

slitt@mydesk:~$ ./hellofunc.lua

Top of square(), nbr=1.414214

2.0000002687177

Top of cube(), number=5.000000

125

slitt@mydesk:~$



Make an msleep() Function



sleep()

sleep()

usleep()

msleep()

msleep()

sleep()

/*

* gcc -shared -fPIC -o msleep.so -I/usr/include/lua5.1 -llua5.1 msleep.c

* -I and -l may vary on your computer.

* Your computer may use something besides -fPIC

*/



#include <unistd.h>

#include <lua.h>

#include <lauxlib.h>

#include <lualib.h>



static int msleep_c(lua_State *L){

long msecs = lua_tointeger(L, -1);

usleep(1000*msecs);

return 0; /* No items returned */

}



/* Can't name this sleep(), it conflicts with sleep() in unistd.h */

static int sleep_c(lua_State *L){

long secs = lua_tointeger(L, -1);

sleep(secs);

return 0; /* No items returned */

}



/* Register both functions */

int luaopen_msleep(lua_State *L){

lua_register( L, "msleep", msleep_c);

lua_register(L, "sleep", sleep_c);

return 0;

}



gcc -Wall -shared -fPIC -o msleep.so -I/usr/include/lua5.1 -llua5.1 msleep.c



test_msleep.lua

#!/usr/bin/lua

require("msleep")

p = print

sf = string.format



local start = os.time()

p(sf("Started at %d", start))

sleep(1)

local mid = os.time()

p(sf("After sleep(1), time is %d", mid))

msleep(2000)

local endd = os.time()

p(sf("After msleep(2000), time is %d", endd))

print()

p(sf("First interval = %d seconds.", mid - start))

p(sf("Second interval = %d seconds.", endd - mid))

p(sf("Whole interval = %d seconds.", endd - start))



slitt@mydesk:~$ ./test_msleep.lua

Started at 1297165088

After sleep(1), time is 1297165089

After msleep(2000), time is 1297165091



First interval = 1 seconds.

Second interval = 2 seconds.

Whole interval = 3 seconds.

slitt@mydesk:~$



We've Just Scratched the Surface

[ Troubleshooters.com| Code Corner | Email Steve Litt ]

Copyright (C) 2011 by Steve Litt --Legal