I'm developing an iOS app can run Lua
scripts, I can easily integrate the base lua
support with CocoaPods
, but how can I add LuaSocket
library into it? LuaSocket
contains some C
and some Lua
files, does anyone have ideas?Thank you!
With iOS 8 allowing dynamic frameworks (libraries) there may be a more elegant approach, but the following works with Lua 5.2.3 (since you are using Cocoapods, and 5.2.3 is the version the Cocoapod supplies) and LuaSocket 3.0-rc1.
NOTE that I am actually not using the Cocoapod; including Lua in your iOS project is simple enough that I find it not worth the trouble of using Cocoapods. YMMV. You may need to make a few adjustments to what I describe below due to path differences.
src
directory in the Lua download into this groupsrc
directory in the LuaSockets download into this group#import "luasocket.h"
to the file serial.h in the LuaSocket sourceAt this point you should be able to build and run the app without any errors. Of course, it doesn't really do anything yet...
First, we're going to modify luaL_openlibs
so that it initializes LuaSocket's C code as follows.
In the Lua source, find the file linit.c and change
static const luaL_Reg loadedlibs[] = {
{"_G", luaopen_base},
{LUA_LOADLIBNAME, luaopen_package},
{LUA_COLIBNAME, luaopen_coroutine},
{LUA_TABLIBNAME, luaopen_table},
{LUA_IOLIBNAME, luaopen_io},
{LUA_OSLIBNAME, luaopen_os},
{LUA_STRLIBNAME, luaopen_string},
{LUA_BITLIBNAME, luaopen_bit32},
{LUA_MATHLIBNAME, luaopen_math},
{LUA_DBLIBNAME, luaopen_debug},
{NULL, NULL}
};
to
{"_G", luaopen_base},
{LUA_LOADLIBNAME, luaopen_package},
{LUA_COLIBNAME, luaopen_coroutine},
{LUA_TABLIBNAME, luaopen_table},
{LUA_IOLIBNAME, luaopen_io},
{LUA_OSLIBNAME, luaopen_os},
{LUA_STRLIBNAME, luaopen_string},
{LUA_BITLIBNAME, luaopen_bit32},
{LUA_MATHLIBNAME, luaopen_math},
{LUA_DBLIBNAME, luaopen_debug},
{"socket", luaopen_socket_core},
{"mime", luaopen_mime_core},
{NULL, NULL}
};
You'll need to add #include "luasocket.h"
and #include "mime.h"
at the top of linit.c.
There are a couple of other C functions that you'll want to add to this list, such as luaopen_socket_unix
, but I'll leave including them as an exercise for the reader.
Now we'll turn to the various Lua source files that are included in LuaSocket such as socket.lua and mime.lua. Rather than using require
to load these in, we're going to execute them with luaL_dofile
.
In order to be concrete, suppose we want to use LuaSocket to do some initialization for our view controller. We'll create the Lua state in viewDidLoad
, call luaL_openlibs
, to initialize the core libraries and LuaSocket's C libraries, then we will get a filepath to the Lua files we want to run using routines from NSBundle
.
We need to edit the Lua files to remove any lines that require
socket.core, mime.core, etc. because that's simpler than trying to get require
to behave correctly. Moreover, socket.core and mime.core have already been initialized by our modified luaL_openlibs
, so there is no need to require
them.
So viewDidLoad
will look something like this:
- (void)viewDidLoad
{
[super viewDidLoad];
lua_State *L = luaL_newstate();
luaL_openlibs(L);
// Load socket.lua and mime.lua
NSString *fp = [[NSBundle mainBundle] pathForResource:@"socket" ofType:@"lua"];
luaL_dofile(L, [fp cStringUsingEncoding:NSUTF8StringEncoding]);
fp = [[NSBundle mainBundle] pathForResource:@"mime" ofType:@"lua"];
luaL_dofile(L, [fp cStringUsingEncoding:NSUTF8StringEncoding]);
lua_settop(L, 0); // ignore return values from the calls to dofile
// Now do something with the Lua state and LuaSockets
NSString *script = @"res = mime.b64('LuaSocket', 'works')";
luaL_dostring(L, [script cStringUsingEncoding:NSUTF8StringEncoding]);
lua_getglobal(L, "res");
const char *s = luaL_checkstring(L, 1);
NSLog(@"res = %@", [NSString stringWithCString:s encoding:NSUTF8StringEncoding]);
}
There are still a few loose ends, but this should demonstrate the main points. You can look at an example project I've created on Github. Over the next few days, I'll get it cleaned up and demonstrate more of LuaSocket's functionality.