add.c内容
//你需要include这几个lua头文件
#include
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
lua_State* L;
int
luaadd(int x, int y)
{
int sum;
/*函数名*/
lua_getglobal(L,"add");
/*参数入栈*/
lua_pushnumber(L, x);
/*参数入栈*/
lua_pushnumber(L, y);
/*开始调用函数,有2个参数,1个返回值*/
lua_call(L, 2, 1);
/*取出返回值*/
sum = (int)lua_tonumber(L, -1);
/*清除返回值的栈*/
lua_pop(L,1);
return sum;
}
int
main(int argc, char *argv[])
{
int sum;
L = luaL_newstate(); /* 创建lua状态机 */
luaL_openlibs(L); /* 打开Lua状态机中所有Lua标准库 */
/*加载lua脚本*/
luaL_dofile(L, "add.lua");
/*调用C函数,这个里面会调用lua函数*/
sum = luaadd(99, 10);
printf("The sum is %d \n",sum);
/*清除Lua*/
lua_close(L);
return 0;
}
add.lua放到与C同级的目录下,里面写一个简单的函数,让C调用
function add(x,y)
print("this is a lua script")
return x + y
end
好了,终于到了用GCC编译的阶段了,直接gcc add.c一下看看行不行。
果然报错了!
这是因为没有把add.c里面的函数链接到我们前面编译出来的lua库里导致的。怎么让他指定链接哪个库呢?看GCC的文档得知-l参数可以指定要链接的库
-l参数和-L参数
-l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库文件名有什么关系呢?
就拿数学库来说,他的库名是m,他的库文件名是libm.so,很容易看出,把库文件名的头lib和尾.so去掉就是库名了
原文链接:https://blog.csdn.net/uisoul/article/details/60137134
gcc -o test test.c -llua -lm -ldl
那我们再试一下, 这次编译出来了: test
执行成功!
/usr/local/lib/liblua.a(lobject.o): In function `numarith':
lobject.c:(.text+0xc8d): undefined reference to `fmod'
lobject.c:(.text+0xcb8): undefined reference to `pow'
/usr/local/lib/liblua.a(lvm.o): In function `luaV_execute':
lvm.c:(.text+0x2068): undefined reference to `pow'
lvm.c:(.text+0x211c): undefined reference to `fmod'
/usr/local/lib/liblua.a(lmathlib.o): In function `math_log10':
lmathlib.c:(.text+0x21e): undefined reference to `log10'
/usr/local/lib/liblua.a(lmathlib.o): In function `math_pow':
lmathlib.c:(.text+0x338): undefined reference to `pow'
........
/usr/local/lib/liblua.a(loadlib.o): In function `lookforfunc':
loadlib.c:(.text+0x748): undefined reference to `dlsym'loadlib.c:(.text+0x7b3):
undefined reference to `dlopen'loadlib.c:(.text+0x851): undefined reference to
`dlerror'loadlib.c:(.text+0x871): undefined reference to
`dlerror'/usr/local/lib/liblua.a(loadlib.o): In function `gctm':loadlib.c:
(.text+0xa44): undefined reference to `dlclose'
问题解析
首先这是链接错误,不是编译错误,也就是说如果只有这个错误,说明你的程序源码本身没有问题,是你用编译器编译时参数用得不对,你没有指定链接程序要用到得库,比如你的程序里用到了一些数学函数,那么你就要在编译参数里指定程序要链接数学库,方法是在编译命令行里加入-lm。
-l参数 就是用来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库文件名有什么关系呢?就拿数学库来说,他的库名是m,他的库文件名是libm.so,很容易看出,把库文件名的头lib和尾.so去掉就是库名了。好了现在我们知道怎么得到库名了,比如我们自已要用到一个第三方提供的库名字叫libtest.so,那么我们只要把libtest.so拷贝到/usr/lib里,编译时加上-ltest参数,我们就能用上libtest.so库了(当然要用libtest.so库里的函数,我们还需要与libtest.so配套的头文件)。放在/lib和/usr/lib和/usr/local/lib里的库直接用-l参数就能链接了,但如果库文件没放在这三个目录里,而是放在其他目录里,这时我们只用-l参数的话,链接还是会出错,出错信息大概是:“/usr/bin/ld: cannot find -lxxx”,也就是链接程序ld在那3个目录里找不到libxxx.so,这时另外一个参数-L就派上用场了,比如常用的X11的库,它放在/usr/X11R6/lib目录下,我们编译时就要用-L/usr/X11R6/lib -lX11参数,-L参数跟着的是库文件所在的目录名。再比如我们把libtest.so放在/aaa/bbb/ccc目录下,那链接参数就是-L/aaa/bbb/ccc -ltest另外,大部分libxxxx.so只是一个链接,以RH9为例,比如libm.so它链接到/lib/libm.so.x,/lib/libm.so.6又链接到/lib/libm-2.3.2.so,如果没有这样的链接,还是会出错,因为ld只会找libxxxx.so,所以如果你要用到xxxx库,而只有libxxxx.so.x或者libxxxx-x.x.x.so,做一个链接就可以了ln -s libxxxx-x.x.x.so libxxxx.so
参考资料:
http://blog.csdn.net/uisoul/article/details/60135764
http://blog.csdn.net/uisoul/article/details/60135383
http://blog.csdn.net/uisoul/article/details/60135764
Lua调用C,我了解到的有3种方式
方式1.通过在C中注册函数给lua调用
方式2.封装成c动态链接库,在lua中require
方式3.在LuaJIT里面可以使用ffi高性能的调用C(但是IOS上不支持LuaJIT。。)
lua提供了lua_register函数注册C函数给lua端调用
hello.c
#include
#include
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
static int l_SayHello(lua_State *L)
{
const char *d = luaL_checkstring(L, 1);//获取参数,字符串类型
int len = strlen(d);
char str[100] = "hello ";
strcat(str, d);
lua_pushstring(L, str); /* 返回给lua的值压栈 */
return 1;
}
int
main(int argc, char *argv[])
{
lua_State *L = luaL_newstate(); /* 创建lua状态机 */
luaL_openlibs(L); /* 打开Lua状态机中所有Lua标准库 */
lua_register(L, "SayHello", l_SayHello);//注册C函数到lua
const char* testfunc = "print(SayHello('lijia'))";//lua中调用c函数
if(luaL_dostring(L, testfunc)) // 执行Lua命令。
printf("Failed to invoke.\n");
/*清除Lua*/
lua_close(L);
return 0;
}
gcc -o hello hello.c -llua 编译执行
创建一个mylib.c的文件,然后我们把它编译成动态链接库。
#include
#include
#include
#include
#include
#include
#include
/* 所有注册给Lua的C函数具有
* "typedef int (*lua_CFunction) (lua_State *L);"的原型。
*/
static int l_sin(lua_State *L)
{
// 如果给定虚拟栈中索引处的元素可以转换为数字,则返回转换后的数字,否则报错。
double d = luaL_checknumber(L, 1);
lua_pushnumber(L, sin(d)); /* push result */
/* 这里可以看出,C可以返回给Lua多个结果,
* 通过多次调用lua_push*(),之后return返回结果的数量。
*/
return 1; /* number of results */
}
/* 需要一个"luaL_Reg"类型的结构体,其中每一个元素对应一个提供给Lua的函数。
* 每一个元素中包含此函数在Lua中的名字,以及该函数在C库中的函数指针。
* 最后一个元素为“哨兵元素”(两个"NULL"),用于告诉Lua没有其他的函数需要注册。
*/
static const struct luaL_Reg mylib[] = {
{"mysin", l_sin},
{NULL, NULL}
};
/* 此函数为C库中的“特殊函数”。
* 通过调用它注册所有C库中的函数,并将它们存储在适当的位置。
* 此函数的命名规则应遵循:
* 1、使用"luaopen_"作为前缀。
* 2、前缀之后的名字将作为"require"的参数。
*/
extern int luaopen_mylib(lua_State* L)
{
/* void luaL_newlib (lua_State *L, const luaL_Reg l[]);
* 创建一个新的"table",并将"l"中所列出的函数注册为"table"的域。
*/
luaL_newlib(L, mylib);
return 1;
}
使用gcc -o mylib.so -fPIC -shared mylib.c -llua -ldl编译成so
然后创建一个lua文件,把我们编译出来的c库引入进来。
--[[ 这里"require"的参数对应C库中"luaopen_mylib()"中的"mylib"。
C库就放在"a.lua"的同级目录,"require"可以找到。]]
local mylib = require "mylib"
-- 结果与上面的例子中相同,但是这里是通过调用C库中的函数实现。
print(mylib.mysin(3.14 / 2)) --> 0.99999968293183
执行a.lua文件,后报错,说Lua存在多个虚拟机!
lua: multiple Lua VMs detected
为什么呢?查了一些资料发现因为lua默认编译的是静态链接库,这样会导致链接多个VM冲突。
那么我们自己再编译个lua解释器动态链接一下。
mylua.c
#include
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
int main() {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
if (luaL_loadfile(L, "a.lua") || lua_pcall(L, 0, 0, 0)) {
printf("%s", lua_tostring(L, -1));
}
}
gcc -o mylua mylua.c -llua -ldl -lm -Wall
这样就能编译出mylua可执行文件
在命令行./mylua执行,成功打印出0.99999968293183
gcc命令,编译lua,编译C动态链接库这些之前都接触的比较少。所以也爬了不少坑,哈哈哈。接下来要好好研究下怎么在c中解析二进制协议给lua调用,在c中怎么封装好luatable
参考资料:
https://www.cnblogs.com/pied/archive/2012/10/26/2741601.html
http://blog.csdn.net/vermilliontear/article/details/50947379
http://blog.csdn.net/casularm/article/details/316149
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。