使用swig集成lua
戴维营教育原创文章,转载请注明出处。我们的梦想是做最好的iOS开发培训!
项目需要在应用中集成Lua脚本,这个问题不大,因为Lua解释器是用C写的,直接将源码引入工程就可以了。麻烦的是实际编写代码的时候,经常需要在Lua中调用C的一些函数。当然可以自己编写中间代码进行黏合,但抱着能省就省的心态,找到了SWIG(Simplified Wrapper and Interface Generator)。SWIG允许C/C++代码向多种脚本提供接口,包括Ruby、Perl、Python等。下面简单介绍一下如何用SWIG将C语言函数和数据类型向Lua公开。在Mac下面需要事先安装SWIG。我们可以使用HomeBrew或者MacPort进行安装。
SWIG接口文件一般用.i
或者.swig
作为扩展名。下面我们先简单的了解一下它的语法规则。SWIG会将我们的C函数库封装为Lua的模块。
%module cg
CGRect CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height);
在Lua中可以使用下面的代码进行调用。
local rect = cg.CGRectMake(0, 0, 100, 200)
当然,在使用项目中是不能直接使用这些接口文件进行编译的。我们需要通过swig命令进行转换。
$ swig -lua test.i
处理结果是名为test_wrap.c
的C语言源文件,可以直接在项目中使用。可以通过-o
参数指定输出文件的名称。
$ swig -lua -o test.c test.i
对于希望直接引入到处理结果中的代码,应该将它们写在%{ %}
之间。
%module cg
%{
#import <CoreGraphics/CGGemetry.h>
void printInLua(void) {
printf("Hello: %s", __func__);
}
%}
struct CGPoint {
CGFloat x;
CGFloat y;
};
typedef struct CGPoint CGPoint;
void printInLua(void);
extern double Foo;
处理后,上面的#import
语句和printInLua
函数都会被拷贝到目标文件中。但是对于需要在Lua中调用的函数或类型,需要在下面声明一下。
处理完后的结果中可以看到如下代码,SWIG通过一系列的宏减少了我们编写交互代码的工作量:
static int _wrap_printInLua(lua_State* L) {
int SWIG_arg = 0;
SWIG_check_num_args("printInLua",0,0)
printInLua();
return SWIG_arg;
if(0) SWIG_fail;
fail:
lua_error(L);
return SWIG_arg;
}
在项目中使用时需要引入Lua的一些头文件,并且调用一个生成的函数extern int luaopen_test(lua_State *L);
来载入刚才的cg
模块。
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
//引入外部函数(swig自动生成的)
extern int luaopen_test(lua_State *L);
- (void)viewDidLoad {
[super viewDidLoad];
lua_State *L = luaL_newstate();
luaL_openlibs(L);
//加载刚才的cg模块,必须调用
luaopen_test(L);
NSString *path = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"lua"];
if (luaL_loadfile(L, [path UTF8String])) {
lua_close(L);
}
else {
lua_pcall(L, 0, 0, 0);
}
}
这里用到了一个Lua脚本“test.lua“。
local p = test.CGPoint
p.x = 120
p.y = 32
print(p.x, p.y)
test.printInLua()
编译运行的结果为:
120 32
Hello: printInLua
这样就可以为Lua新增一些函数、数据类型或者是变量。
下面是引入CGGemetry.h中大部分函数到Lua中的一个SWIG文件。
%module cg
%{
#import <CoreGraphics/CGGeometry.h>
%}
typedef float CGFloat;
typedef struct CGPoint CGPoint;
struct CGPoint {
CGFloat x;
CGFloat y;
};
typedef struct CGSize CGSize;
struct CGSize {
CGFloat width;
CGFloat height;
};
typedef struct CGRect CGRect;
struct CGRect {
CGPoint origin;
CGSize size;
};
CGPoint CGPointMake(CGFloat x, CGFloat y);
CGSize CGSizeMake(CGFloat width, CGFloat height);
CGRect CGRectMake(CGFloat x, CGFloat y, CGFloat width,
CGFloat height);
CGFloat CGRectGetMinX(CGRect rect);
CGFloat CGRectGetMidX(CGRect rect);
CGFloat CGRectGetMaxX(CGRect rect);
CGFloat CGRectGetMinY(CGRect rect);
CGFloat CGRectGetMidY(CGRect rect);
CGFloat CGRectGetMaxY(CGRect rect);
CGFloat CGRectGetWidth(CGRect rect);
CGFloat CGRectGetHeight(CGRect rect);
bool CGPointEqualToPoint(CGPoint point1, CGPoint point2);
bool CGSizeEqualToSize(CGSize size1, CGSize size2);
bool CGRectEqualToRect(CGRect rect1, CGRect rect2);
bool CGRectIsEmpty(CGRect rect);
const CGPoint CGPointZero;
const CGSize CGSizeZero;
const CGRect CGRectZero;
const CGRect CGRectNull;
const CGRect CGRectInfinite;
通过处理后,就可以在Lua中通过cg模块使用上面所有的函数和结构体类型了。
参考资料
戴维营学院(高级开发视频): http://v.diveinedu.com
潜心俱乐部(iOS面试必备): http://divein.club