Cocos创建Lua项目使用自定义runtime脚本没有调试输出的解决方法

使用Cocos集成开发环境配合Cocos Code IDE 1.2.0可以很方便的创建cocos2d-x lua binding项目并支持脚本语言的智能感知及调试。同时在添加native代码支持后还可以在一定程度上方便的进行原生代码功能扩展,如植入一些第三方库,扩展lua脚本功能等。但是在使用Cocos创建项目时,发现一个非常奇怪的问题,就是如果不使用自带的PrebuiltRuntime:C:\Program Files (x86)\Cocos\cocos-simulator-bin\win32\Simulator.exe 来作为主执行程序调试(Windows平台,其他平台未测试),所有lua脚本中的printprintf等调试输出代码都不会在控制台内输出任何内容!这样就丧失了添加native代码后自定义runtime执行程序的能力。

而让人恼火的是,如果直接使用cocos2d-x.org上下载的framework zip的话(http://www.cocos2d-x.org/filedown/cocos2d-x-3.5.zip),又没法顺利作为Code IDE的可用frameworks!会提示如下所示的信息:Lua: 不能找到…/PrebuiltRuntimeLua.apk,请确保引擎是完整的并重试一次。
QQ截图20150407155754
貌似是在说下载的cocos2d-x中找不到预编译的运行时程序,手动查找了一遍文件夹cocos2d-x-3.5\templates中,也确实是只有两个模板项目的源代码,并不包含任何预编译程序。
虽然使用自定义运行时Code IDE还是可以正常进行断点调试的,但是看不见log始终是不方便,于是开始查找、解决问题。
最开始考虑的是使用默认Simulator时的一些环境参数,如启动命令行、项目config.json配置信息等有所不同,导致只能看到如下的一些基本信息(PS:已经定义了cocos2d debug和ide support的预编译宏):

SCREEN DPI = 96, SCREEN SCALE = 1.00
WORKAREA WIDTH 1904.00, HEIGHT 982.00
FRAME SCALE = 1.00
Ready for GLSL
Ready for OpenGL 2.0
Project Config:
project dir: D:\Projects\cocos\tsc\
writable path: $(PROJDIR)\
script file: $(PROJDIR)\src\main.lua
frame size: 1136 x 640
frame scale: 1.00
show console: NO
write debug log: NO ()
listen:
debugger: Cocos Code IDE
add searching path:

还用专门的进程分析器,比较了下两个runtime启动时的参数,发现都是一致的:
“C:\Program Files (x86)\Cocos\cocos-simulator-bin\win32\Simulator.exe” D:/Projects/cocos/tsc -workdir D:/Projects/cocos/tsc -debugger codeide -console enable
由此判断应该不是启动参数或项目配置信息不同所致。
由于使用Cocos所带framework创建出的项目编译时是基于prebuilt的cocos2d-x lib dll进行的,所以也不方便进行引擎底层lua代码追踪看到底是什么地方出了问题。于是又开始从自行下载的cocos2d-x 3.5入手,通过cocos.bat new创建了lua项目,编译后运行,所有log print printf均正常输出,但是这样有个问题就是无法进行IDE调试,全源码版的libsimulator中并不带有任何对Code IDE调试支持的部分(可以看到protobuf lite中全是空的),且运行时代码启动部分也和Cocos的prebuilt版框架生成的项目有所不同,搜索了下github等,发现这部分IDE支持的libsimulator代码貌似是闭源的(⊙﹏⊙)b,又开始尝试剥离掉源码版的libsimulator直接link prebuilt版的,结果没想象的那么简单,一些常量定义可能由于编译器导致的不同使最终的link彻底失败!当然,也可能是没剥离彻底所致,没工夫沿这方向推敲了……
最后无奈之下开始搜索全源码中的lua print实现,很轻松的找到了CCLuaStack.cpp中的这段:

    // Register our version of the global "print" function
    const luaL_reg global_functions [] = {
        {"print", lua_print},
        {"release_print",lua_release_print},
        {nullptr, nullptr}
    };
    luaL_register(_state, "_G", global_functions);

很明显是print函数的原生实现代码,并且下面还有个叫release_print的,看了下两个print的实现基本是一样的,于是用自定义runtime运行,并且将其中一些print、printf改为了release_print,发现果然有了输出!这样基本可以得出问题起因的结论了:无论是否定义了debug宏,还是进行了调试模式生成,都是按照release环境处理的,所以print都被忽略掉了!(还特意试了下Cocos商店下过的3.4版本,也是一样)
既然找到问题的根源就好办了,显然,都改用release_print虽然可以输出调试信息,但是所有cocos2d-x lua api中的print、printf还是看不到,而且以后真正到了release版的时候,再去掉调试信息也很不方便,所以这种做法不可取。
我目前解决的方法是照抄CCLuaStack中的register全局函数注册方法,在Runtime项目的AppDelegate.cpp中重新注册一次print:

int lua_print(lua_State * luastate)
{
	int nargs = lua_gettop(luastate);

	std::string t;
	for (int i = 1; i <= nargs; i++)
	{
		if (lua_istable(luastate, i))
			t += "table";
		else if (lua_isnone(luastate, i))
			t += "none";
		else if (lua_isnil(luastate, i))
			t += "nil";
		else if (lua_isboolean(luastate, i))
		{
			if (lua_toboolean(luastate, i) != 0)
				t += "true";
			else
				t += "false";
		}
		else if (lua_isfunction(luastate, i))
			t += "function";
		else if (lua_islightuserdata(luastate, i))
			t += "lightuserdata";
		else if (lua_isthread(luastate, i))
			t += "thread";
		else
		{
			const char * str = lua_tostring(luastate, i);
			if (str)
				t += lua_tostring(luastate, i);
			else
				t += lua_typename(luastate, lua_type(luastate, i));
		}
		if (i != nargs)
			t += "\t";
	}
	CCLOG("[LUA-print] %s", t.c_str());

	return 0;
}

bool AppDelegate::applicationDidFinishLaunching()
{
        ...
	const luaL_reg global_functions[] = {
		{ "print", lua_print },
		{ nullptr, nullptr }
	};
	luaL_register(lState, "_G", global_functions);

#if (COCOS2D_DEBUG > 0) && (CC_CODE_IDE_DEBUG_SUPPORT > 0)
    // NOTE:Please don't remove this call if you want to debug with Cocos Code IDE
    RuntimeEngine::getInstance()->addRuntime(RuntimeLuaImpl::create(), kRuntimeEngineLua);
    RuntimeEngine::getInstance()->start();
    cocos2d::log("iShow!");
#else
        ...
}

这样,再次执行runtime就可以正常看到lua中的print输出了,并且以后release版的时候可以加上条件编译宏,去掉这次注册的print全局函数。

博主友情提示:

如在您的评论中需要提及如QQ号、微信号、电子邮件地址或其他隐私敏感信息,欢迎通过>>博主专用加密工具v2<<加密后发布,原文只有博主可以看到。