在Lua中调用c++函数
来源:互联网 发布:日志记录访问次数java 编辑:程序博客网 时间:2024/06/05 13:48
现在我们需要在Lua中调用c++的函数,完成Lua语言实现起来不太方便的功能,这种方法网上有很多说明,但是写得不够详细,初学者看了一头雾水,下面我写一下自己的方法,目的仅仅是让我们先把程序跑起来!
首先来看下代码,然后说配置(在Mac下演示),再解释代码。
1
#include <iostream>
2
3
#ifdef __cplusplus
4
extern
"C"
5
{
6
#endif
7
8
#include <lua.h>
9
#include <lualib.h>
10
#include <lauxlib.h>
11
12
#ifdef __cplusplus
13
}
14
#endif
15
16
//要想注册进lua,函数的定义为 typedef int (*lua_CFunction)(lua_State* L)
17
int
printHello(lua_State * l)
18
{
19
lua_pushstring(l,
"hello lua"
);
20
21
//返回值代表向栈内压入的元素个数
22
return
1;
23
}
24
25
int
foo(lua_State * l)
26
{
27
//获得Lua传递过来的参数个数
28
int
n = lua_gettop(l);
29
if
(n != 0)
30
{
31
//获得第一个参数
32
int
i = lua_tonumber(l,1);
33
//将传递过来的参数加一以后最为返回值传递回去
34
lua_pushnumber(l,i+1);
35
return
1;
36
}
37
38
return
0;
39
}
40
41
//相加
42
int
add(lua_State * l)
43
{
44
int
n = lua_gettop(l);
45
int
sum = 0;
46
for
(
int
i=0;i<n;i++)
47
{
48
sum += lua_tonumber(l,i+1);
49
}
50
if
(n!=0)
51
{
52
lua_pushnumber(l,sum);
53
return
1;
54
}
55
56
return
0;
57
}
58
59
//把需要用到的函数都放到注册表中,统一进行注册
60
const
luaL_Reg lib[]=
61
{
62
{
"printHello"
,printHello},
63
{
"foo"
,foo},
64
{
"add"
,add},
65
{nullptr,nullptr}
66
};
67
68
int
main(
int
argc,
const
char
* argv[])
69
{
70
//创建一个新的Lua环境
71
lua_State * l= lua_open();
72
73
//打开需要的库
74
luaL_openlibs(l);
75
76
//把foo函数注册进lua,第二个参数代表Lua中要调用的函数名称,第三个参数就是c层的函数名称
77
//单独注册一个函数
78
// lua_register(l,"foo",foo);
79
80
//统一注册lua中调用的函数
81
const
luaL_Reg* libf =lib;
82
for
(; libf->func; libf++)
83
{
84
//把foo函数注册进lua,第二个参数代表Lua中要调用的函数名称,第三个参数就是c层的函数名称
85
lua_register(l,libf->name,libf->func);
86
//将栈顶清空
87
lua_settop(l,0);
88
}
89
90
//加载并且执行lua文件
91
luaL_dofile(l,
"test.lua"
);
92
//使用dostring直接执行字符串代表的内容,是一段Lua代码
93
// luaL_dostring(l,"print(foo(100))");
94
95
//关闭
96
lua_close(l);
97
98
return
0;
99
}
如果你运行这个程序,会发现编译错误,连头文件都找不到的,所以,我们就要配置一下环境了。首先我们需要下载lua源码,然后解压出来进入Lua的目录,打开控制台切换到Lua目录下,输入make macosx。学过Linux的人就知道这个命令是什么意思,他会编译源码,产生我们要得库,最后会在src目录下产生三个文件lua (the interpreter), luac (the compiler), and liblua.a (the library)。最后为了验证编译的正确性,可以运行make test,过程如图所示。
接下来打开Mac的工程,我们需要进行如图所示的配置。我们需要做的就是对工程配置一下头文件的路径和库的路径,大家根据自己刚才存放的源码目录进行配置,我把用到的库放到了工程下,所以库的路径就是工程的路径。
完成了以上的工作就需要解释一下代码的含义了。头文件的包含这个就不用说了,然后在main函数中,执行了打开lua环境,打开需要用到的库,将要被Lua调用的函数注册一下,然后调用Lua文件,最后关闭Lua环境。代码上都有注释,大家可以查看。而我们注册给Lua使用的函数,必须采用以下的定义方式,typedef int (*lua_CFunction)(lua_State* L),返回值代表的就是要返回给Lua层多少个返回值,这些返回值都使用push压入了栈中,而函数的参数代表的是Lua的全局状态。涉及到得具体函数作用,代码已经有说明,test.lua如下。
1
print
(printHello())
2
print
(foo(99))
3
print
(add(1,5,3,6))
为了打印出结果,我们还需要做的一个步骤如图。
然而为了更好的理解编译链接库的原理,我们在控制台下对刚才的工程做一个编译,其实用到的仅仅就是工程中得一个main函数。我们用到的编译工具是gcc,而不是Xcode集成好的环境。直接使用g++ main.cpp -o main编译main.cpp,希望产生的可执行文件是main。然后接着就报错了,说没有找到lua.h的头文件,好吧,那我们就使用一个-I参数,后边跟上头文件所在的路径,就是你下载下来的源码src文件夹所在的路径:g++ main.cpp -I /Users/mac/Documents/lua-5.1/src -o main(-I参数的含义就是指定头文件的路径),想不到继续报错,说链接失败,原因当然是没有找到Lua库了,所以我们使用-l参数加上库的名称来指定一下库名,接着报错,说库名没有找到,好吧,继续加上-L指定你的库路径。最后的命令是g++ main.cpp -I /Users/mac/Documents/lua-5.1/src -o main -llua -L .这次真的是OK了,然后运行程序,出现了我们要得结果。
现在我们需要将我们用到的这些函数封装到一个模块中,就像cocos的做法一样,使用模块名来调用这些函数,这样组织代码看起来才会好一点。
1
//要想注册进lua,函数的定义为 typedef int (*lua_CFunction)(lua_State* L)
2
int
printHello(lua_State * l)
3
{
4
lua_pushstring(l,
"hello lua"
);
5
6
//返回值代表向栈内压入的元素个数
7
return
1;
8
}
9
10
int
foo(lua_State * l)
11
{
12
//获得Lua传递过来的参数个数
13
int
n = lua_gettop(l);
14
if
(n != 0)
15
{
16
//获得第一个参数
17
int
i = lua_tonumber(l,1);
18
//将传递过来的参数加一以后最为返回值传递回去
19
lua_pushnumber(l,i+1);
20
return
1;
21
}
22
23
return
0;
24
}
25
26
//相加
27
int
add(lua_State * l)
28
{
29
int
n = lua_gettop(l);
30
int
sum = 0;
31
for
(
int
i=0;i<n;i++)
32
{
33
sum += lua_tonumber(l,i+1);
34
}
35
if
(n!=0)
36
{
37
lua_pushnumber(l,sum);
38
return
1;
39
}
40
41
return
0;
42
}
43
44
//把需要用到的函数都放到注册表中,统一进行注册
45
const
luaL_Reg lib[]=
46
{
47
{
"printHello"
,printHello},
48
{
"foo"
,foo},
49
{
"add"
,add},
50
{nullptr,nullptr}
51
};
52
53
//把上边的函数封装到一个模块里边
54
int
luaopen_tt(lua_State * l)
55
{
56
//首先创建一个table,然后把成员函数名做key,成员函数作为value放入该table中
57
luaL_newlib(l,lib);
58
59
return
1;
60
}
61
62
int
main(
int
argc,
const
char
* argv[])
63
{
64
//创建一个新的Lua环境
65
lua_State * l= luaL_newstate();
66
67
//打开需要的库
68
luaL_openlibs(l);
69
70
//注册模块
71
luaL_requiref(l,
"tt"
,luaopen_tt,1);
72
73
//执行test2.lua文件
74
luaL_dofile(l,
"test2.lua"
);
75
76
//关闭
77
lua_close(l);
78
79
return
0;
80
}
上边的代码有俩处比较重要,一个是模块注册函数luaopen_tt,我想注册一个tt模块,所以这个模块的名字就叫做luaopen_tt,在Lua层require一个模块名的时候其实是去找一个函数名叫luaopen_模块名的函数,所以你的模块名的函数也需要按照这种格式来写,包括参数和返回值。在这个函数中,使用luaL_newlib函数,把用到的c++函数都放到了全局的表里边,这样就可以使用模块名调用了。另一个重要的地方是函数luaL_requiref(l,"tt",luaopen_tt,1),第二个参数是模块的名字,要和你上边的luaopen后边的名字相同。这样我们在test2.lua文件中就可以这么使用了。通过这种方法,我们就将c++要导出来的函数封装到一个模块中了。
1
require
"tt"
2
print
(tt.printHello())
现在需要做的一件事是,在Cocos2d-x的函数代码中导出函数给Lua用,这个过程是相同的,只不过要看看Cocos给我们提供了什么。使用Cocos Code IDE创建一个Cocos Lua工程,默认情况下工程下是没有c++层的源代码的,所以我们要让这些c++的源代码出来。点击工程选择Cocos Tools,然后选择Add Native Codes Support。这样,在你工程的目录下就会出现一个frameworks的目录,里边放的就是c++的源码。
有必要了解一下Cocos Code IDE生成的工程的目录都是神马意思,如下图所示。res和src不用说了,config.json文件是一个配置文件,配置窗口的大小和窗口标题以及调试的端口号等等这些东西,还有很多内容,需要我们配置的时候就去这里找好了。framework就是源码了,里边的cocos2d-x就是cocos的源码了,runtime-src下得classes下就是c++层用到的源码。其实我们使用Cocos Code IDE来做游戏开发,程序的启动是从c++层启动的,有时候虽然我们整个游戏项目写的都是Lua脚本,没写过一行c++代码,但是,程序启动是从c++代码启动的,是从c++层调用的Lua脚本,然后Lua脚本调用cocos绑定的函数。所以最后的那个runtime文件夹就是编译出来得运行环境,每当我们c++层改变代码的时候都需要借助Cocos Code IDE这个工具来重新生成一个runtime。
现在言归正传,打开AppDelegate.cpp文件,在applicationDidFinishLaunching函数的如下地方注册我们得导出函数。
我将要导出的函数写到了一个新的.cpp文件中了,单击工程创建一个.cpp文件和一个.h文件,我的文件内容如下。
1
#ifndef __Test10__TestLua__
2
#define __Test10__TestLua__
3
4
extern
"C"
{
5
#include "lua.h"
6
#include "lualib.h"
7
#include "lauxlib.h"
8
}
9
10
int
test(lua_State * l);
1
#include "TestLua.h"
2
3
int
test(lua_State * l)
4
{
5
lua_pushstring(l,
"单独的c文件"
);
6
return
1;
7
}
AppDelegate.cpp文件一定要包含TestLua.h文件哈,要不注册的时候怎么知道有test这个函数。关于导出函数的写法和在AppDelegate中怎么注册我就不用说了吧,和前边的一样,使用stack->getLuaState()就是获得运行时的全局环境,有了这个全局的环境就可以注册了。这里需要注意的是,新建的TestLua.h和TestLua.cpp文件一定是加入到这个工程中得,否则编译的时候不会编译这俩个文件,没有加入进去相信AppDelegate中就会报错了,这里个文件的创建就和我们平时写c++代码一样使用同样的方法做就OK了。接下来比较重要的是,在Lua工程中,我们需要重新编译一下runtime(在Cocos Tools菜单中找),原因我想不用说了吧,最后在工程的debug配置中看看是不是用的是新编译出来的runtime,不要用错了。
最后我们只需要在工程中简单得测试一下就OK了。
版权声明:本文由( 小塔 )原创,转载请保留文章出处!
本文链接:http://www.zaojiahua.com/c-functions.html
- Lua 在Lua中调用C函数
- 在Lua中调用C函数
- Lua 在C程序中调用Lua函数
- C中调用Lua函数
- Lua中调用C函数
- C中调用Lua函数
- c中调用Lua函数
- 在LUA脚本中调用C/C++函数
- 如何在c/c++中调用LUA函数
- 在c中调用lua函数,获取返回值等
- 在C中调用lua的内置函数string.gsub
- 在c中调用lua函数,获取返回值等
- 在Lua代码中调用c/C++函数
- cocos2dx关于在c/c++中调用lua函数
- 在Lua代码中调用c/C++函数
- Lua教程(四):在Lua中调用C语言、C++的函数
- C/C++中调用LUA函数
- Lua中调用C/C++函数
- PHP搭建自己的web框架-控制器
- 一维元胞自动机 Python 实现
- linux c socket之异步IO
- spring mvc web应用程序框架的搭建
- mysql 删除重复数据只保留一条
- 在Lua中调用c++函数
- Apache与Nginx的优缺点比较
- cocos2d-3.8.1版本tableview的使用(怎么取消弹簧效果);
- Linux设置socket客户端的连接超时(转)
- 用setsockopt()来控制recv()与send()的超时
- struts2对action指定方法进行校验(人工编码)
- 秒杀系统架构分析与实战
- [时空与预测]星际迷航-暗黑无边
- android实现双轮联动选择器