显示标签为“cocos2d-x”的博文。显示所有博文
显示标签为“cocos2d-x”的博文。显示所有博文

Lua接口学习

今天在程序里面使用lua_call,导致程序没有任何错误提示直接退出,找了好久原因,才知道lua_call不是一个受保护的方法,如果其中发生错误,会导致宿主程序直接退出

直到看到这篇文章才恍然大悟:最后查看官方文档,更换使用了lua_pcall。没有错误的问题真心可怕啊。。。

为何使用lua_atpanic
当调用无保护的lua_call后,如果调用栈发生错误(lua_error),那么默认行为是直接退出宿主程序。(可以参考这篇文章)
要避免这样的情况,一种方法是定义自己的panic函数,并作为参数调用lua_atpanic;此外为了避免退出宿主程序,自定义的panic函数应该永不返回(通常是做一个长跳转,令其跳转至lua_call调用点,不过这种做法几乎与lua_pcall无异)
lua_atpanic 1. lua_atpanic设置新panic函数并返回旧的panic函数。
2. 当在无保护环境下发生错误,lua调用当前的panic函数并呼叫exit(EXIT_FAILURE)退出宿主程序。
3. 我们可以提供自己的panic函数以避免退出宿主程序。(一种方法是做一个长跳转(long jump))
4. panic函数可以访问位于栈顶的错误讯息。
示例

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <stdio.h>
#include <setjmp.h> static jmp_buf jbuf; int
    panichandler(lua_State *L)    
    printf("%s\n", lua_tostring(L, 1));
    lua_pop(L, 1);
    longjmp(&jbuf, 1);  
}
int main(int argc, char *argv[])
lua_State *L;
int ret = 0;
if ((L = lua_open()) == NULL) {
    printf("lua_open() failed!\n");
    return 1;
} luaL_openlibs(L);
lua_atpanic(L, panichandler);
if (luaL_loadfile(L, "main.lua") == 0) {  
      if (setjmp(&jbuf) == 0)   /* first jmp */
          lua_call(L, 0, 0);    
      else                      /* second jmp, error */
          ret = 1;      else
      ret = 1; lua_close(L);
    return ret;
}



luaL_checkxxx和luaL_argcheck内部调用luaL_error,luaL_error内部调用lua_error,在调用lua_error前会格式化错误信息压入栈顶,最后调用lua_error,lua_error不会返回,而是做一个长跳转。所以在C函数中使用return luaL_error也不会返回,而是跳转到调用lua_pcall点 即lua_pcall返回。

C库函数的例子
int dir(lua_State *L)
{
    HANDLE              h;
    WIN32_FIND_DATAA    fd;
    const char         *dirpath;
    dirpath = luaL_checkstring(L, 1); /* 一旦出错立刻压入错误,并从lua_pcall返回,luaL_error也一样 */
    if ((h = FindFirstFileA(dirpath, &fd)) == INVALID_HANDLE_VALUE)
        return luaL_error(L, "failed to find '%s', win32 error code %d", dirpath, GetLastError());
    return 0;
}

lua_error在内部调用luaD_throw函数:
void luaD_throw (lua_State *L, int errcode) {
if (L->errorJmp) {
    L->errorJmp->status = errcode;
    LUAI_THROW(L, L->errorJmp);
}
else {
    L->status = cast_byte(errcode);
    if (G(L)->panic) {
      resetstack(L, errcode);
      lua_unlock(L);
      G(L)->panic(L);
    }
    exit(EXIT_FAILURE);
}
}
1. 当一个跳转点存在时,lua_error将做一个长跳转
2. 否则调用一个panic函数(如果存在),并退出宿主程序。

现在的问题是跳转点何时会存在,位于何处?
答案:LUA库函数中运行于保护模式的函数会设置跳转点,这包括lua_pcall, lua_cpcall, 以及由此函数衍生的一系列宏(如lua_dofile, luaL_dostring等)
观察lua_pcall的源码,该函数调用luaD_rawrunprotected
int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
struct lua_longjmp lj;
lj.status = 0;
lj.previous = L->errorJmp; /* chain new error handler */
L->errorJmp = &lj;
LUAI_TRY(L, &lj,
    (*f)(L, ud);
);
L->errorJmp = lj.previous; /* restore old error handler */
return lj.status;
}
这段代码显示了设置跳转点的过程。相比之下无保护的lua_call就没有类似的代码。
1.调用lua_pcall后,如果调用栈上发生任何错误(即lua_error被调用),lua_error将直接跳转至lua_pcall的调用点,并从lua_pcall返回。
2.调用lua_call后发生错误,lua_error将直接调用panic函数并退出宿主程序;除非通过设置自定义panic函数永不返回(通常是做长跳转以避免退出)。

当使用lua_call时,用lua_atpanic为其设置panic函数

为何使用lua_atpanic
当调用无保护的lua_call后,如果调用栈发生错误(lua_error),那么默认行为是直接退出宿主程序。要避免这样的情况,一种方法是定义自己的panic函数,并作为参数调用lua_atpanic;此外为了避免退出宿主程序,自定义的panic函数应该永不返回(通常是做一个长跳转,令其跳转至lua_call调用点,不过这种做法几乎与lua_pcall无异)
1. lua_atpanic设置新panic函数并返回旧的panic函数。
2. 当在无保护环境下发生错误,lua调用当前的panic函数并呼叫exit(EXIT_FAILURE)退出宿主程序。
3. 我们可以提供自己的panic函数以避免退出宿主程序。(一种方法是做一个长跳转(long jump))
4. panic函数可以访问位于栈顶的错误讯息。


示例

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <stdio.h>
#include <setjmp.h>

static jmp_buf jbuf;

int
panichandler(lua_State *L)
{  
    printf("%s\n", lua_tostring(L, 1));
    lua_pop(L, 1);
    longjmp(&jbuf, 1);  
}

int main(int argc, char *argv[])
{
  lua_State *L;
  int ret = 0;

  if ((L = lua_open()) == NULL)
  {
     printf("lua_open() failed!\n");
     return 1;
   }

   luaL_openlibs(L);
   lua_atpanic(L, panichandler);

  if (luaL_loadfile(L, "main.lua") == 0)
   {  
      if (setjmp(&jbuf) == 0)   /* first jmp */
          lua_call(L, 0, 0);    
      else                      /* second jmp, error */
          ret = 1;    
   }
   else
      ret = 1;

  lua_close(L);
  return ret;
}

Cocos2d-x-environment-set-up

Cocos2d-x专题之一:开发环境搭建

Windows 7+Visual Studio 2012+cocos2d-x-2.1.5配置cocos2d-x win32环境

下载cocos2d-x

官网:http://cocos2d-x.org/download
(注意: 由于 2.1.2版本之后不需要使用 VC模板向导创建项目,所以2.1.2之后的版本需要 使用project-creator.py这个python脚本进行工程项目的创建和配置,不适用向导的方式创建。当然,网上也能找到很多 不通过python脚本创建的方法.)

下载python

官网:http://www.python.org/download/
建议使用2.7.x的版本,因为使用Python3以上版本可能会出现莫名其妙的问题.默认安装,路径D:\Python27
将Python加入Path环境变量
打开 [计算机]-[属性] 窗口,最左侧找到 [高级系统设置],然后会弹出 [系统属性] 页面.选择[高级] 选项卡,下边的位置有一个 [环境变量],
点击按钮,便打开[环境变量]的窗口 在[系统变量]中 [变量] 这一列中找到[Path],选择[编辑]按钮,在[变量值] 的最后位置,添加上"D:\Python27",这里要根据自己安装Python 的实际目录 填写,每个值用";" 分号分割.
加入环境变量之后,运行"cmd",输入python会出现一系列东西,配置成功

创建工程

在解压后的cocos2d-x-2.1.5文件目录"~\cocos2d-x-2.1.5\tools\project-creator"下有createproject.py脚本,运行"cmd"进入"~\cocos2d-x-2.1.5\tools\project-creator"目录(createproject.py脚本所在目录),运行以下命令生成HelloWorld cpp项目:


python create_project.py -project HelloWorld -package com.einverne.helloworld -language cpp

-project 工程名
-package Android工程包名
-language 可选{cpp|lua|javascript}分别创建C++工程,lua绑定工程,javascript绑定工程 参考官网wiki

创建成功之后在"cocos2d-x-2.1.5/projects/"目录下就可以找到HelloWorld工程,找到proj.win32工程下的sln文件用vs打开.
参考:1

Android SDK+Android NDK+Eclipse+cocos2d-x-2.1.5配置cocos2d-x Android开发环境

下载和配置Android SDK和NDK

1.Android SDK:http://developer.android.com/sdk/index.html
2.Android NDK:http://developer.android.com/tools/sdk/ndk/index.html
下载完之后解压,在SDK里有Eclipse并且各种ADT,CDT插件均已经安装好(默认JDK已经安装好了)
将NDK添加到系统环境变量(仿照Python添加系统环境变量),新建系统变量,变量名"NDK_ROOT",变量值"D:\Android\android-ndk-r9\"(根据你自己解压目录来),并在Path中添加%NDK_ROOT%,以分号隔开

配置工程

1.打开Eclipse并将"~/cocos2d-x-2.1.5/projects/HelloWorld/proj.android/"工程导入 (通过上面create_project.py方法新建工程默认已经创建Android工程)
2.导入之后有错误不要怕,一步一步来,首先,Eclipse找不到cocos2d-x Java classes,解决方案:选中Project,右击"Properties",在左边栏中找到Java Build Path,在Source Tab中找到Link Source Browse找到

$COCOS2DX-HOME/cocos2dx/platform/android/java/src/

在Folder name中写"cocos2dx src",Finish->OK.
3.项目属性->C/C++ Build->"Builder Settings"->"Build command"->改为"${NDKROOT}\ndk-build.cmd"
4.项目属性->C/C++ Build->"Environment"->添加名为"NDKMODULEPATH",值为"~\cocos2d-x-2.1.5;~\cocos2d-x-2.1.5\cocos2dx\platform\thirdparty\android\prebuilt\"的变量,根据自己的实际所在地址填写.
5.将Resources中资源文件拷贝到assets文件夹中,并且适当修改Android.mk文件
还有其他错误,我也说不上来了.安装环境的时候忘了记录,如有问题可以提出来.
参考:1

Add lua support to cpp cocos2d-x project

I am asking a question on stackoverflow
Now I find a solution.
1.右击解决方案,添加项目,将"$(cocos2d-x-home)/scripting/lua/proj.win32/liblua.vcxproj"添加到解决方案
2.右击自己工程->属性->通用属性->添加新引用,勾选liblua,即可

Quote Of The Day