【cocos2d-x 3.x 学习与应用总结】4: 使用cocos compile编译apk
2016-01-24 23:27
661 查看
前言
本文总结了在windows上使用cocos compile命令编译cocos2d-x安卓apk的基本用法,以及记录一个使用NDK-r9d(gcc 4.8)编译C++11的
hash_map遇到的一个问题:
error: invalid use of incomplete type 'struct std::hash<MessageType>'。
cocos compile 基本用法, 编译debug版本的cpp-tests.
从2.x到3.x,cocos的辅助工具做的越来越完善了,2.x刚开始的时候编译apk是比较费劲的,除了最基本的安装JDK, NDK, Android SDK, Ant还要装cygwin,自己配环境变量,执行打包脚本等等。我最近使用的是cocos2d-x官方的github仓库中的默认v3分支最新代码(3.10), 以编译cpp-tests工程为android apk为例,使用最新的打包方式:cocos compile.基本的环境准备
如今的cocos,大量使用了python作为其辅助工具,因此第一步就是装好python,推荐比较经典的2.7.x版本。装好python之后就可以到引擎的根目录,执行setup.py来初始化cocos环境了,它会引导你配置好cocos命令行工具执行所需要的环境变量和工具。其中包括:
Setting up cocos2d-x... ->Check environment variable COCOS_CONSOLE_ROOT ->Search for environment variable COCOS_CONSOLE_ROOT... ->COCOS_CONSOLE_ROOT is found : D:\codes\cocos2d-x\tools\cocos2d-console\bin ->Check environment variable COCOS_X_ROOT ->Search for environment variable COCOS_X_ROOT... ->COCOS_X_ROOT is found : D:\codes ->Check environment variable COCOS_TEMPLATES_ROOT ->Search for environment variable COCOS_TEMPLATES_ROOT... ->COCOS_TEMPLATES_ROOT is found : D:\codes\cocos2d-x\templates ->Configuration for Android platform only, you can also skip and manually edit your environment variables ->Check environment variable NDK_ROOT ->Search for environment variable NDK_ROOT... ->NDK_ROOT is found : D:\Programs\android-ndk-r9d\ ->Check environment variable ANDROID_SDK_ROOT ->Search for environment variable ANDROID_SDK_ROOT... ->ANDROID_SDK_ROOT is found : D:\Programs\adt-bundle-windows-x86_64-20131030\sdk ->Check environment variable ANT_ROOT ->Search for environment variable ANT_ROOT... ->ANT_ROOT is found : D:\programs\apache-ant-1.9.4\bin\
其中几个常用SDK和NDK的下载和安装不再细说。在配置好之后,能看到像我上面这样的输出就ok了,相对于2.x中要做的工作,这样的引导是安装已经很简单了。
在命令行执行打包命令
配置好环境之后,打包就非常简单了。对于cocos自带的cpp-tests项目,打包apk有两种操作方法:方法1
在引擎根目录/build/目录下,执行
python android_build.py cpp-tests即可。建议在cmd窗口中操作,可以看到真个过程,包括异常退出等情况。关于
android_build.py的更多用法请参考其文件内容,里面有usage说明。
方法2
在引擎根目录/tests/cpp-tests/目录,执行cocos命令:
cocos compile -p android
其实,两种方法都是使用了
cocos compile这个命令行工具。关于其完整的用法请在cmd中输入
cocos compile -h即可查看帮助信息。第一种方式中的脚本
android_build.py其实是使用
-s参数来调用
cocos compile命令,-s选项指定了工程的目录地址。即可。自己打开瞧瞧它的内容就知道了。很简单。
自己创建的项目打包apk
使用cocos new命令创建的工程如何打包成apk?
也很简单,跟cpp-tests是一样的过程,也是使用
cocos compile命令。在执行命令之前,比cpp-tests多的一步操作是,添加自己写的C++源代码文件名称和包含路径到Android.mk.
假设项目名字叫”Dog”
第一步,添加文件包含路径和cpp文件名到Dog/proj.android/jni/Android.mk
例如下面的Android.mk文件是我的游戏目录下/proj.android/jni/Android.mk文件,其中那一堆cpp就是自己写的cpp源代码,要参与到二进制编译的cpp都要加进来。
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) $(call import-add-path,$(LOCAL_PATH)/../../cocos2d) $(call import-add-path,$(LOCAL_PATH)/../../cocos2d/external) $(call import-add-path,$(LOCAL_PATH)/../../cocos2d/cocos) LOCAL_MODULE := cocos2dcpp_shared LOCAL_MODULE_FILENAME := libcocos2dcpp # 从hellocpp/main.cpp这行往下,是自己添加的cpp文件 LOCAL_SRC_FILES := hellocpp/main.cpp \ ../../Classes\AppDelegate.cpp \ ../../Classes\CCDirector.cpp \ ../../Classes\customs\FlowLayout.cpp \ ../../Classes\customs\Menu.cpp \ ../../Classes\data_models\TestDataCenter.cpp \ ../../Classes\LogicDirector.cpp \ ../../Classes\message\Message.cpp \ ../../Classes\message\MessageCenter.cpp \ ../../Classes\PageManager.cpp \ ../../Classes\pages\CameraTest.cpp \ ../../Classes\pages\CCBPage.cpp \ ../../Classes\pages\CCBTestPage.cpp \ ../../Classes\pages\LittleTouchPage.cpp \ ../../Classes\pages\MainPage.cpp \ ../../Classes\pages\NodeTestPage.cpp \ ../../Classes\pages\RootPage.cpp \ ../../Classes\pages\ScrollviewTestPage.cpp \ ../../Classes\pages\SuperPage.cpp \ ../../Classes\pages\TestEntranceLayer.cpp \ ../../Classes\pages\TouchTestPage.cpp \ ../../Classes\util\CocosWindow.cpp \ ../../Classes\util\cocos_util.cpp \ ../../Classes\util\DrawNode3D.cpp \ ../../Classes\util\StringUtil.cpp \ ../../Classes\pages\ShaderTest.cpp # 文件的包含路径 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes # _COCOS_HEADER_ANDROID_BEGIN # _COCOS_HEADER_ANDROID_END LOCAL_STATIC_LIBRARIES := cocos2dx_static # _COCOS_LIB_ANDROID_BEGIN # _COCOS_LIB_ANDROID_END include $(BUILD_SHARED_LIBRARY) $(call import-module,.) # _COCOS_LIB_IMPORT_ANDROID_BEGIN # _COCOS_LIB_IMPORT_ANDROID_END
2. 在Dog/proj.android/目录下执行:cocos compile -p android
通过这两部就完成了自己创建项目的打包apk操作,可以注意到,比较复杂的就是第一步,在把自己的cpp文件加到Android.mk的时候,尤其是当你的cpp放的到处都是,像我的那样分散在多个子目录中。为了这一步的自动化,可以自己写个脚本。我这里分享一个很简单的小脚本,它可以遍历子目录,记录下所有的cpp文件。其实就是一个简单的类似unix命令tree的小脚本。
tree.py: 递归遍历子目录,统计所有.cpp文件,并写入完整路径到cpps.txt
# coding=utf-8 import os def get_dir_tree(begin_dir, coll): files = os.listdir(begin_dir) for file_name in files: full_path = os.path.join(begin_dir, file_name) if os.path.isdir(full_path): get_dir_tree(full_path, coll) else: coll.append(full_path) if "__main__" == __name__: file_tree = [] get_dir_tree(os.getcwd(), file_tree) # write .cpp file names into file with open("cpps.txt", "w") as f: for name in file_tree: if str(name).endswith(".cpp"): f.write(name + " \\\n")
把这个tree.py脚本丢到: 项目根目录/Classes/目录下,执行即可生成一个cpps.txt, 里面记录了所有的cpp文件路径,然后按列选择
/Classes/..../xxxx.cpp \, 复制粘贴到Android.mk即可。
cpps.txt
D:\codes\3.9\PlayingWithCocos3D\Classes\AppDelegate.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\CCDirector.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\cocos_src_modified\CCNodeLoader.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\customs\FlowLayout.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\customs\Menu.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\data_models\TestDataCenter.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\HelloWorldScene.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\LogicDirector.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\message\Message.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\message\MessageCenter.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\PageManager.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\pages\CameraTest.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\pages\CCBPage.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\pages\CCBTestPage.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\pages\LittleTouchPage.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\pages\MainPage.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\pages\NodeTestPage.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\pages\RootPage.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\pages\ScrollviewTestPage.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\pages\ShaderTest.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\pages\SuperPage.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\pages\TestEntranceLayer.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\pages\TouchTestPage.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\util\CocosWindow.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\util\cocos_util.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\util\DrawNode3D.cpp \ D:\codes\3.9\PlayingWithCocos3D\Classes\util\StringUtil.cpp \
C++11中的强类型枚举(scoped enum)作为hash表键值导致的编译错误
我的cocos代码中使用了一个强类型枚举作为键值的unordered_map, 如下:
enum class MessageType { kMessageTypeChangePage = 0, kMessageTypePushPage, kMessageTypePopPage, kMessageTypeChangeBackground, }; class MessageCenter : public Singleton<MessageCenter> { // ...... private: typedef std::vector<Message*> MessageQueue; MessageQueue messages_; typedef std::set<PriorityHandler*> HandlerQueue; typedef std::unordered_map<MessageType, HandlerQueue> HandlerMap; HandlerMap handlerMap_; };
其中的HandlerMap类型就是以enum class MessageType来作为键值的hash表,在windows上我使用visual studio 2013编译项目,顺利通过。
编译apk时就出问题了。在使用
cocos compile -p android命令,使用NDK对上面的代码进行编译的时候,会发现如下错误:
In file included from D:/programs/android-ndk-r9d/sources/cxx-stl/gnu-libstdc++/4.8/include/bits/hashtable.h:35:0, from D:/programs/android-ndk-r9d/sources/cxx-stl/gnu-libstdc++/4.8/include/unordered_map:47, from D:\codes\3.9\PlayingWithCocos3D\proj.android\../cocos2d/cocos/3d/../renderer/CCTexture2D.h:32, from D:\codes\3.9\PlayingWithCocos3D\proj.android\../cocos2d/cocos/3d/../base/CCProtocols.h:34, from D:\codes\3.9\PlayingWithCocos3D\proj.android\../cocos2d/cocos/3d/../2d/CCNode.h:34, from D:\codes\3.9\PlayingWithCocos3D\proj.android\../cocos2d/cocos/3d/../2d/CCScene.h:32, from D:\codes\3.9\PlayingWithCocos3D\proj.android\../cocos2d/cocos/3d/../base/CCDirector.h:37, from D:\codes\3.9\PlayingWithCocos3D\proj.android\../cocos2d/cocos/3d/../base/CCAsyncTaskPool.h:29, from D:\codes\3.9\PlayingWithCocos3D\proj.android\../cocos2d/cocos/3d/../cocos2d.h:41, from jni/../../Classes/util/cocos_util.h:3, from jni/../../Classes/cocos_include.h:4, from jni/../../Classes/message/MessageCenter.h:4, from jni/../../Classes\message\MessageCenter.cpp:1: D:/programs/android-ndk-r9d/sources/cxx-stl/gnu-libstdc++/4.8/include/bits/hashtable_policy.h:1082:53: error: invalid use of incomplete type 'struct std::hash<MessageType>' using __ebo_h1 = _Hashtable_ebo_helper<1, _H1>; ^
编译器抱怨说 : struct std::hash是不完整类型。它为什么会这样认为?这是因为hash表的定义需要一个hash函数,对于内置的数据类型,C++标准要求标准库要提供预定义的hash函数,在
<functional>头文件里可以找到内置数据类型的hash函数定义:
// std::hash // Defined in <funtional> template<> struct hash<bool>; template<> struct hash<char>; template<> struct hash<signed char>; template<> struct hash<unsigned char>; template<> struct hash<char16_t>; template<> struct hash<char32_t>; template<> struct hash<wchar_t>; template<> struct hash<short>; template<> struct hash<unsigned short>; template<> struct hash<int>; template<> struct hash<unsigned int>; template<> struct hash<long>; template<> struct hash<long long>; template<> struct hash<unsigned long>; template<> struct hash<unsigned long long>; template<> struct hash<float>; template<> struct hash<double>; template<> struct hash<long double>; template< class T > struct hash<T*>;
而对于enum class类型C++标准并没有要求必须提供。windows上VC++编译器应该是提供了enum class的hash函数,因此编译能够通过。那么对于gcc编译器,要想解决这个问题就需要自己定义hash函数,针对我的enum class MessageType。
enum class MessageType { kMessageTypeChangePage = 0, kMessageTypePushPage, kMessageTypePopPage, kMessageTypeChangeBackground, }; namespace std { template <> struct hash<MessageType> { typedef MessageType argument_type; typedef size_t return_type; return_type operator() (const argument_type &arg) const { return static_cast<return_type>(arg); } }; }
为了快点通过编译在android上看到我的游戏测试结果,我定义了一个很简单的hash函数,直接把enum的值转为size_t。
有了这个hash函数,NDK编译通过了并且打包成功。
作者水平有限,对相关知识的理解和总结难免有错误,还望给予指正,非常感谢!
在这里也能看到这篇文章:github博客, CSDN博客, 欢迎访问
相关文章推荐
- c语言实现hashmap(转载)
- 在Windows平台下使用安装GCC(图)
- Ruby中Hash的11个问题解答
- Ruby简明教程之数组和Hash介绍
- Cocos2d-x中背景音乐和音效使用实例
- Cocos2d-x学习笔记之CCScene、CCLayer、CCSprite的默认坐标和默认锚点实验
- Cocos2d-x UI开发之CCControlPotentiometer控件类使用实例
- Cocos2d-x UI开发之文本类使用实例
- Cocos2d-x保存用户游戏数据之XML文件是否存在问题判断方法
- Cocos2d-x UI开发之菜单类使用实例
- Cocos2d-x UI开发之CCControlButton控件类实例
- Cocos2d-x学习笔记之世界坐标系、本地坐标系、opengl坐标系、屏幕坐标系
- 在C#中生成与PHP一样的MD5 Hash Code的方法
- js中hash和ico的关联分析
- Javascript SHA-1:Secure Hash Algorithm
- linux使用gcc编译c语言共享库步骤
- Cocos2d-x UI开发之CCControlColourPicker控件类使用实例
- Cocos2d-x学习笔记之CCLayerColor层的使用实例
- 理解php Hash函数,增强密码安全
- Android NDK开发之:配置环境的详解