Lua编译器及Lua与C相互调用

本文详细介绍了如何使用VS2012编译Lua源码,生成解释器和静态库,并展示了C如何调用Lua以及Lua调用C函数的方法。通过示例代码展示了C中调用Lua脚本以及创建C动态库供Lua调用的过程。

Lua编译器及LuaC相互调用

2015-03-17何鹏

 

   Lua是一门小巧强大的编程语言,很多开发工具都对Lua源码进行了封装,本文用VS2012编译了Lua源码,并详细讲述了LuaC的互相调用。本文使用的是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_"文件名"的函数,加载动态库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值