OSX下安装zeromq

$ brew install zeromq

OSX下安装VirtualBox与Ubuntu Server

此处省略N个字...

OSX下的LuaJIT测试

$ brew install luajit --enable-debug # 开启deubg支持

2.1 main.c

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

int main(void) {
    
    lua_State* L = luaL_newstate();   
    luaL_openlibs(L);
    luaL_dostring(L, "return 'Hello from Lua!'");  // 执行Lua语句
    const char * str = lua_tostring(L, -1);        // 获取Lua语句的返回值
    printf(str);
    lua_close(L);

    return 0;
}

2.2 编译

$ gcc-4.7 \
    -lluajit-5.1 \                      # 加入luajit-5.1的库
    -I/usr/local/include/luajit-2.0 \   # 加入头文件搜索路径,因为系统已经装有lua会有冲突
    -pagezero_size 10000 \              # 64位的OSX的一个bug
    -image_base 100000000 \             # 详细说明在 http://luajit.org/install.html
    main.c

2.3 执行

$ ./a.out # Hello from Lua!

通过 @table.foreach(ffi, print)@ 获取的元素表

table(table table-bordered). |_.元素|_.类型|_.说明| |new|function|创建C数据类型 @cpoint = ffi.new('Point', {23, 89})@| |cast|function|转换成C数据类型 @cint = ffi.cast('int', 123)@| |typeof|function|创建给定的C数据类型 @cdouble = ffi.typeof('double')@| |sizeof|function|| |alignof|function|| |istype|function|| |fill|function|| |cdef|function|绑定C函数 @ffi.cdef[[ int printf(const char*, ...); ]]@| |abi|function|| |metatype|function|| |copy|function|| |errno|function|| |load|function|| |arch|x64|当前CPU架构| |string|function|| |gc|function|| |os|OSX|当前系统|| |C|userdata|| |offsetof|function|| see more: "http://luajit.org/ext_ffi_api.html":http://luajit.org/ext_ffi_api.html

3.1 基本应用

local ffi = require 'ffi'
local x = ffi.new('int')          -- 创建一个int
local c = ffi.new('char*')        -- 创建一个char*

ffi.cdef[[
    int printf(const char*, ...); -- 绑定c的printf函数
]]

local C = ffi.C
C.printf('Hello %s!/n', 'World')  -- 调用绑定好的printf函数

3.2 绑定C自定义函数

// main.c
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

int add(int, int);

int main(void) {
    
    lua_State* L = luaL_newstate();   
    luaL_openlibs(L);
    luaL_dofile(L, "main.lua");
    lua_close(L);

    return 0;
}

int add(int x, int y) {
    return x + y;
}
// main.lua
local ffi = require 'ffi'
ffi.cdef[[
    int add(int, int);
]]

print('12 + 59 = ' .. ffi.C.add(12, 59))

3.3 绑定C数据结构

// main.c
typedef struct {
    char *name;
    int age;
} Student;

void call(Student*); // 打印这个对象

...
// main.lua

...

ffi.cdef[[
    typedef struct {
        char *name;
        int age;
    } Student;

    void call(Student*);
]]

C.call(ffi.new('Student', {ffi.cast('char*', 'tom'), 23)}) -- 注意char*需要使用cast转换

3.4 技巧,生成ffi专用的类似tolua++的pkg文件

// stub.c
#include "header.h"     // 创建stub.c,只包含要绑定的头文件
$ gcc-4.7 -E stud.c | grep -v '^#' > ffi_header.h
// main.lua

...
ffi.cdef(io.open('ffi_header.h', 'r'):read('*a'))
...

3.5 绑定C++数据结构(对象)

@Student.h@

#ifndef __STUDENT_H__
#define __STUDENT_H__

class Student {
    public:
        Student();
        ~Student();
        void toString(void);
        void setName(const char* name);
        void setAge(int age);
    private:
        char* name;
        int age;
};

#endif

@Student.cpp@

#include "Student.h"

Student::Student() {
    
}

Student::~Student() {
    
}

void Student::toString() {
    std::cout << "name: " << name << " age: " << age << std::endl;
}

void Student::setName(const char* name) {
    delete this->name;
    this->name = new char[strlen(name) + 1];
    strcpy(this->name, name);
}

void Student::setAge(int age) {
    this->age = age;
}

@bindings.h@

#ifndef __BINDINGS_H__
#define __BINDINGS_H__

// Student对象提供给Lua的接口
Student* Student_new(void);
void Student_toString(Student*);
void Student_setName(Student*, const char*);
void Student_setAge(Student*, int);
void Student__gc(Student*);

#endif

@bindings.cpp@

#include "Student.h"

extern "C" {
#include "bindings.h"
}

extern "C" {

    Student* Student_new(void) {
        return new Student();        
    }

    void Student_toString(Student* stu) {
        stu->toString();
    }
    
    void Student_setName(Student* stu, const char* name) {
        stu->setName(name);
    }

    void Student_setAge(Student* stu, int age) {
        stu->setAge(age);
    }
    
    void Student__gc(Student* stu) {
        delete stu;
    }

}

@main.lua@

local ffi = require 'ffi'
local C = ffi.C

ffi.cdef[[
    typedef struct Student Student;
]]

-- 通过gcc -E生成bindings.ffi
ffi.cdef(io.open('bindings.ffi', 'r'):read('*a'))

local Mt_Student = {} -- metatype
Mt_Student.__index = Mt_Student
Mt_Student.setName = C.Student_setName
Mt_Student.setAge = C.Student_setAge
Mt_Student.toString = C.Student_toString

ffi.metatype('Student', Mt_Student)

local stu = ffi.gc(C.Student_new(), C.Student__gc)
stu:setName("tom")
stu:setAge(23)
stu:toString()

@generate_ffi.lua@ 生成 @bindings.ffi@

-- 执行
-- $ luajit generate_ffi.lua

local stub = io.open("stub.c", "w")
stub:write([[#include "bindings.h"]])
stub:close()

os.execute([[gcc -I . -E -P stub.c > bindings.ffi]])
os.execute([[rm stub.c]])
print 'done'

build

$ g++ \
    -lluajit-5.1 \
    -I/usr/local/include/luajit-2.0 \
    -pagezero_size 10000 \
    -image_base 100000000 \
    -o maincpp \
    main.cpp Student.cpp bindings.cpp
$ ./maincpp

@student.dylib@ 加载动态库并绑定

$ g++ -c Student.cpp bindings.cpp                           # 生成Student.o bindings.o
$ g++ -dynamiclib Student.o bindings.o -o libstudent.dylib  # 生成动态库
$ g++ \
    -lluajit-5.1 \
    -I/usr/local/include/luajit-2.0 \
    -pagezero_size 10000 \
    -image_base 100000000 \
    -o maincpp \
    main.cpp

@$ vim main.lua@

- --local C = ffi.C
+ local C = ffi.load('student')

@$ ./maincpp@

@testcallback.c@ 首先要明白函数指针


#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

typedef void (*Callback)(void);         // 定义一个无参无返回值的函数指针类型
typedef int (*Callback2)(int,int);      // 定义一个接收两个参数int返回值的函数指针类型


void callLuaFunc(Callback);
void callLuaFunc2(Callback2);

Callback callbackFunc = NULL;
Callback2 callbackFunc2 = NULL;

// 函数指针变量例子
void MyFunc(int);      // 普通函数
void (*MyFuncP)(int);  // 函数指针变量MyFuncP,注意有typedef与没有的区别

void MyFunc(int x) {
    printf("x = %d\n", x);
}

int main(void) {
   
    MyFuncP = &MyFunc;  // 把普通函数的地址赋给MyFuncP函数指针变量
    MyFuncP(12);        // 通过函数指针调用普通函数

    lua_State* L = luaL_newstate();   
    luaL_openlibs(L);
    luaL_dofile(L, "luascripts/testcallback.lua");
    lua_close(L);
    
    return 0;
}

void callLuaFunc(Callback cb) {
    callbackFunc = cb;
    callbackFunc();
}

void callLuaFunc2(Callback2 cb2) {
    callbackFunc2 = cb2;
    int count = callbackFunc2(12, 46);

    printf("count: %d\n", count);
}

@testcallback.lua@ ffi的回调机制

local log = function(...)
    print('[LuaJIT] -- ' .. string.format(...))
end

local ffi = require 'ffi'

ffi.cdef[[
    typedef void (*Callback)(void);
    typedef int (*Callback2)(int,int);

    void callLuaFunc(Callback);
    void callLuaFunc2(Callback2);
]]

local function lfunc()
    log('lfunc')
end

local function lfunc2()
    log('lfunc2')
end

local cb = ffi.cast('Callback', lfunc); -- 把lua函数转换成c函数指针
ffi.C.callLuaFunc(cb)                   -- 把转换后的c函数指针传递给c函数

cb:set(lfunc2);         -- 修改回调函数
ffi.C.callLuaFunc(cb)

cb:free()

local cb2 = ffi.cast('Callback2', function(x, y)
    log(x .. ' + ' .. y .. ' = ' .. x + y)
    return x + y
end)

ffi.C.callLuaFunc2(cb2)
cb2:free()

源码

</br>

Cocos2d-x之Lua支持std::vector容器

class vector {

    TOLUA_TEMPLATE_BIND(T, string, CCSprite*)   // 添加我们想要的容器类型

    void clear();
    int size() const;

    const T& operator[](int index) const;
    T& operator[](int index);
    void push_back(T val);

    vector();
    ~vector();
};
  ...
  #ifdef __cplusplus
  tolua_cclass(tolua_S,"vector_CCSprite__","vector<CCSprite*>","",tolua_collect_vector_CCSprite__);
  #else
  tolua_cclass(tolua_S,"vector_CCSprite__","vector<CCSprite*>","",NULL);
  #endif
  tolua_beginmodule(tolua_S,"vector_CCSprite__");
   tolua_function(tolua_S,"clear",tolua_Lottery_vector_CCSprite___clear00);
   tolua_function(tolua_S,"size",tolua_Lottery_vector_CCSprite___size00);
   tolua_function(tolua_S,".geti",tolua_Lottery_vector_CCSprite____geti00);
   tolua_function(tolua_S,".seti",tolua_Lottery_vector_CCSprite____seti00);
   tolua_function(tolua_S,".geti",tolua_Lottery_vector_CCSprite____geti01);
   tolua_function(tolua_S,"push_back",tolua_Lottery_vector_CCSprite___push_back00);
   tolua_function(tolua_S,"new",tolua_Lottery_vector_CCSprite___new00);
   tolua_function(tolua_S,"new_local",tolua_Lottery_vector_CCSprite___new00_local);
   tolua_function(tolua_S,".call",tolua_Lottery_vector_CCSprite___new00_local);
   tolua_function(tolua_S,"delete",tolua_Lottery_vector_CCSprite___delete00);
  tolua_endmodule(tolua_S);
  ...
local string_vector = vector_string_:new_local()
string_vector:push_back("hello")
string_vector:push_back("world")
cclog(string_vector[0].." "..string_vector[1])

local ccsprite_vector = vector_CCSprite__:new_local()     // 注意指针类型的是__
ccsprite_vector:push_back(CCSprite:create("image"))
ccsprite_vector:push_back(CCSprite:create("image"))

Cocos2d-x之回调Lua的函数

1.1 创建LuaHandler.h,方便其实控件增加该功能。

#ifndef __LUAHANDLER_H__
#define __LUAHANDLER_H__

#include "CCLuaEngine.h"

class LuaHandler
{
public:
    LuaHandler(): m_nLuaHandler(0){}
    virtual ~LuaHandler(){}

    // 注册Lua回调函数
    virtual void registerLuaHandler(int nHandler)
    {
        unregisterLuaHandler();
        m_nLuaHandler = nHandler;
        LUALOG("[LUA] Add lua handler: %d", m_nLuaHandler);
    }

    // 取消注册
    virtual void unregisterLuaHandler(void)
    {
        if (m_nLuaHandler != 0)
        {
            cocos2d::CCScriptEngineManager::sharedManager()
            ->getScriptEngine()
            ->removeScriptHandler(m_nLuaHandler);
            m_nLuaHandler = 0;
            LUALOG("[LUA] Remove lua handler: %d", m_nLuaHandler);
        }
    }

    // 获取在Lua中注册的Lua回调函数引用
    int getLuaHandler() { return m_nLuaHandler; };

    // 获取Lua的堆,方法调用各种函数
    cocos2d::CCLuaStack *getLuaStack(void) 
    {
        cocos2d::CCLuaEngine *pEngine = (cocos2d::CCLuaEngine*)
        (cocos2d::CCScriptEngineManager::sharedManager()->getScriptEngine());
        return pEngine->getLuaStack();
    }
protected:
    int m_nLuaHandler;
};

#endif

1.2 使用LuaHandler.h

#include "LuaHandler.h"

class MyLayer: public CCLayer, public LuaHandler
{
public:
    // ... 省略

    void callback(void)
    {
        int mHandler = getLuaHandler();
        if (mHandler != 0)
        {
            CCLuaStack *pStack = getLuaStack();
            pStack->pushInt(1234);                           // 回调函数第一个参数
            pStack->pushString("abc");                       // 回调函数第二个参数
            pStack->executeFunctionByHandler(mHandler, 2);   // 2表示回调函数有两个参数
        }
    }
};

1.3 创建MyLayer.pkg

class MyLayer: public CCLayer
{
    // ... 省略

    void registerLuaHandler(LUA_FUNCTION mHandler);
    void unregisterLuaHandler(void);
};
local function callback(f, t)
    cclog("第一个参数:" .. f .. ",第二个参数:" .. t)
end

local myLayer = MyLayer:create()
myLayer:registerLuaHandler(callback)    -- 注册回调函数
myLayer:unregisterLuaHandler()          -- 取消注册