Lua编译器及Lua与C相互调用
2015-03-17何鹏
Lua是一门小巧强大的编程语言,很多开发工具都对Lua源码进行了封装,本文用VS2012编译了Lua源码,并详细讲述了Lua和C的互相调用。本文使用的是Lua5.1
一、Lua编译成解释器
1.官网上下载源码:http://www.lua.org/
2.用VS2012新建一个解决方案,在解决方案里新建一个项目LuaTest
3.在项目目录LuaTest文件夹下新建一个目录Lua,将Lua源码src文件夹下的文件都复制到LuaTest/Lua目录
4.右键点击vs2012中的LuaTest项目,--添加--新建筛选器--命名为Lua,右击该筛选器,添加--现有项--将LuaTest/Lua文件夹全选导入
5.右击LuaTest项目,点击生成,即在Debug目录下生成了Lua编译器LuaTest.exe
运行该编译器,在窗口输入print(loadlib()):
该编译器不支持动态连接库,将项目中的luaconf.h中的
#undef LUA_COMPAT_LOADLIB
改为
#define LUA_COMPAT_LOADLIB
重新生成,即可支持动态链接库
二,将Lua编译成静态库使用
将上面项目第四步完成后:
将源码中lua.c文件中main()函数改名(Lua5.3中还需将luac.c中的main()函数改名),这两个文件的main函数主要是生成解释器程序
右击项目--属性--配置属性--常规下的配置类型设为.lib
完成后右击项目--重新生成则生成了LuaTest.lib静态库
三、将Lua编译成动态库使用
四、C中调用Lua(可以使用Lua静态库,也可以使用Lua源码一同编译)
1.新建一个项目LuaLua,同上,在第四步时只导入头文件,不导入.c文件
2.在项目中新建一个文件,LuaLua.cpp输入:
/////////////////////////////////////////////////////////////////////////////////////////
extern"C"
{
#include"Lua/lua.h"
#include"Lua/lauxlib.h"
#include"Lua/lualib.h"
#include<stdio.h>
}
#pragma comment(lib,"LuaTest.lib")
void load (char*filename,int*width,int*height) {
lua_State *L =lua_open();
//luaopen_base(L);
//luaopen_io(L);
//luaopen_string(L);
//luaopen_math(L);
luaL_openlibs(L);
if(luaL_loadfile(L,filename) || lua_pcall(L, 0, 0, 0))
luaL_error(L,"cannot run configuration file: %s",lua_tostring(L, -1));
lua_getglobal(L,"width");
lua_getglobal(L,"height");
if(!lua_isnumber(L, -2))
luaL_error(L,"width' should be a number\n");
if(!lua_isnumber(L, -1))
luaL_error(L,"height' should be a number\n");
*width= (int)lua_tonumber(L, -2);
*height= (int)lua_tonumber(L, -1);
lua_close(L);
}
double f (doublex,doubley){
doublez;
lua_State *L =lua_open();
luaL_openlibs(L);
if(luaL_loadfile(L,"wo.lua") ||lua_pcall(L, 0, 0, 0))
luaL_error(L,"cannot run configuration file: %s",lua_tostring(L, -1));
/*push functions and arguments */
lua_getglobal(L,"f");/*function to be called */
lua_pushnumber(L,x);/*push 1st argument */
lua_pushnumber(L,y);/*push 2nd argument */
/*do the call (2 arguments, 1 result) */
if(lua_pcall(L, 2, 1, 0) != 0)
luaL_error(L,"error running function `f': %s",
lua_tostring(L, -1));
/*retrieve result */
if(!lua_isnumber(L, -1))
luaL_error(L,"function `f' must return a number");
z =lua_tonumber(L, -1);
lua_pop(L, 1);/* pop returned value */
lua_close(L);
returnz;
}
int main(intargc,char*argv[])
{
inta = 0;
intb = 0;
int*pw = &a;
int*ph = &b;
load("wo.lua",pw,ph);
printf("w = %d,h= %d\n",*pw,*ph);
printf("%f\n",f(c,d));
return0;
}
/////////////////////////////////////////////////////////////////////////////////////////
wo.lua文件中
width = 100
height = 300
function f(a,b)
return a^2*math.sin(b)/(1-a)
-- body
end
可以调用相应的Lua函数和Lua全局变量
会有相应的输出:
/////////////////////////////////////////////////////////////////////////////////////////
w = 100,h= 300
-10.103305
请按任意键继续. . .
注:Lua5.1中只能使用luaL_openlibs(L);代表打开所有库,否则会报错:unprotected error in call to lua api <no calling environment> 。Lua5.3可以分别使用打开各个库的函数luaopen_math(L),但Lua5.3不能使用Lua_open(),应该直接使用lua_State* L = luaL_newstate();
应当把LuaTest.lib包放到本项目所在目录下
五:在C中调用Lua脚本,Lua脚本调用的是C函数
extern"C"
{
#include"Lua/lua.h"
#include"Lua/lauxlib.h"
#include"Lua/lualib.h"
#include<stdio.h>
}
#pragma comment(lib,"LuaTest.lib")
int foo(lua_State *L)
{
int n = lua_tonumber(L, 1);
lua_pushnumber(L, n + 1);
return 1;
}
int main()
{
lua_State *L = lua_open();
luaL_openlibs(L);
lua_register(L,"foo", foo);
luaL_dofile(L,"wo.lua");
lua_close(L);
printf("over----\n");
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
wo.lua文件中
print(foo(2))
会有相应的输出:
/////////////////////////////////////////////////////////////////////////////////////////
3
over----
请按任意键继续. . .
六、将C中的函数建成一个动态库,在Lua中调用该库
新建一个项目LuaDll,项目类型选择动态库,并且勾选空项目,在项目中新建Lua筛选器,将Lua的头文件都导入
新建一个cpp文件LuaDll.cpp,输入:
////////////////////////////////////////////////////////////////////////////////////////////////////
extern"C"
{
#include"Lua/lua.h"
#include"Lua/lauxlib.h"
#include"Lua/lualib.h"
#include<stdio.h>
}
#pragma comment(lib,"LuaTest.lib")
extern"C"__declspec(dllexport)int luaopen_LuaDll(lua_State* L);
staticint isquare(lua_State *L){ /* C中的函数名 */
float rtrn = lua_tonumber(L, -1);
printf("Top of square(), nbr=%f\n",rtrn);
lua_pushnumber(L,rtrn*rtrn); /*将返回值压回Lua虚拟机的栈*/
return 1;
}
int luaopen_LuaDll(lua_State *L){
lua_register(
L, /* Lua状态机 */
"square", /*Lua中的函数名 */
isquare /*当前文件中的函数名 */
);
return 0;
//luaL_openlib(L,"LuaDll", mylib, 0);
//return0;
}
/////////////////////////////////////////////////////////////////////////////////////////
右击生成,即编译好了动态库,生成LuaDll.dll
使用动态库:
将以上生成的Lua解释器,LuaDll.dll动态库拷贝到到统一目录,在同目录下新建一个Lua文件a.lua,输入
loadlib第一个参数是动态库的名字,第二个表示入口函数
local d = package.loadlib("LuaDll.dll","luaopen_LuaDll")
d()
print(square(2))
或者是:
require "LuaDll"
print(square(2))
保存。
运行Lua解释器,输入dofile("a.lua"),即可得到结果:
> dofile("a.lua")
Top of square(), nbr=2.000000
4
>
注:此处调用的square是全局函数,如果需要将其设置为一个函数包,则修改动态库源文件为:
/////////////////////////////////////////////////////////////////////////////////////////
extern"C"
{
#include"Lua/lua.h"
#include"Lua/lauxlib.h"
#include"Lua/lualib.h"
#include<stdio.h>
}
#pragma comment(lib,"LuaTest.lib")
extern"C"__declspec(dllexport)int luaopen_LuaDll(lua_State* L);
staticint isquare(lua_State *L){ /* C中的函数名 */
float rtrn = lua_tonumber(L, -1);
printf("Top of square(), nbr=%f\n",rtrn);
lua_pushnumber(L,rtrn*rtrn); /*将返回值压回Lua虚拟机的栈*/
return 1;
}
staticconststructluaL_reg mylib [] = {
{"square", isquare},
{NULL,NULL}/*sentinel */
};
int luaopen_LuaDll(lua_State *L){
luaL_openlib(L,"LuaDll", mylib, 0);
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////
重新生成LuaDll.dll,并且a.lua文件改为:
local d = package.loadlib("LuaDll.dll","luaopen_LuaDll")
d()
print(LuaDll.square(2))
或者是:
require "LuaDll"
print(LuaDll.square(2))
保存。
运行Lua解释器,输入dofile("a.lua"),即可得到结果:
> dofile("a.lua")
Top of square(), nbr=2.000000
4
>
requrie函数会默认去打开luaopen_"文件名"的函数,加载动态库