写在前面:

前段时间下载了cocos2d-x 3.1,按照官网的教程,配置环境,编译打包,走了一遍,感觉不错,顺便发现其中用了很多python的脚本文件,比如今天要说的android-build.py.这个文件把编译,打包的功能全部整合到了一起.也就是传说中的一键打包.正好最近在看python,就顺手拿这个脚本学习一下.

小贴士:

在正式看这个脚本文件前,推荐先到cocos2d-x的官网按教程,配置环境,编译,打包,走一遍,先有个大概的了解.教程地址.http://www.cocos2d-x.org/wiki/Getting_Started_with_Cocos2d-x.

我是做coco2d-x游戏开发的,用的是windows环境.运行cocos2d-x 3.1需要安装和配置下面的软件.JDK,android-sdk,ant,python,android-ndk-r9d.系统就必须win7以上了.想进一步学习的话,也可以去看看python,我也是最近在看,大家可以相互学习进步.

正文:

android-build.py脚本文件在引擎目录下的build文件夹里.里面的代码还是有点多,这里就不全部粘贴出来了,可以在原文件上直接看源代码.

下面的一些内容会涉及到python的语法内容,如果对python比较熟悉的话可以直接跳到看重点关注.写了很多python相关的,主要是自己也在学python. :-)

  1. import sys
  2. import os, os.path
  3. import shutil
  4. from optparse import OptionParser
  5.  
  6. CPP_SAMPLES = ['cpp-empty-test', 'cpp-tests']
  7. LUA_SAMPLES = ['lua-empty-test', 'lua-tests']
  8. ALL_SAMPLES = CPP_SAMPLES + LUA_SAMPLES

这是开始的东东,前面几行的import,就和java的import一样,导入一些需要的模块.

  1. CPP_SAMPLES = ['cpp-empty-test', 'cpp-tests']

这个是python里的一种数据类型,叫做列表,和java,c++里的数组类似.里面也可以放整型,字符型啦这些数据.这里放的是字符串,python中的字符串可以用单引号,也可以用双引号括起.两个列表可以直接用 "+",合成一个新的列表.还有就是python里的数据类型都没有类型标识.所以你看python代码时变量前面一般不会看到,long,int这些啦.这三行存的是代码里要编译的demo的名字,后面要用到.

  1. def get_num_of_cpu():
  2. ''' The build process can be accelerated by running multiple concurrent job processes using the -j-option.
  3. '''
  4. try:
  5. platform = sys.platform
  6. if platform == 'win32':
  7. if 'NUMBER_OF_PROCESSORS' in os.environ:
  8. return int(os.environ['NUMBER_OF_PROCESSORS'])
  9. else:
  10. return 1
  11. else:
  12. from numpy.distutils import cpuinfo
  13. return cpuinfo.cpu._getNCPUs()
  14. except Exception:
  15. print "Can't know cpuinfo, use default 1 cpu"
  16. return 1

这个是python里的方法,看方法名字知道是用来获取系统处理器数量的.其中sys就是最开始导入的一个模块,提供了一些方法处理系统方面的一些功能.在这里

  1. platform = sys.platform

获得当前的操作系统平台

  1. os.environ['NUMBER_OF_PROCESSORS']

获得系统变量的值.在python中有种数据类型叫做字典,类似java,c++中的map,通过键找到对应的值.

  1. def check_environment_variables():

检查是否设置了ndk的环境变量'NDK_ROOT',就是在环境变量里新建一个'NDK_ROOT',再把你ndk的根目录路径设置到其中.

  1. def check_environment_variables_sdk():

检查android sdk的环境变量设置,如果没有,则需要把sdk的根目录路径设置到新建的环境变量'ANDROID_SDK_ROOT'中.

  1. def select_toolchain_version():

选择需要的toolchain.代码注释说的很明白.因为cocos2d-x 3.1用的是c++11,所以toolchain的版本需要用gcc4.7以上的版本.

重点关注:

  1. def do_build(cocos_root, ndk_root, app_android_root, ndk_build_param,sdk_root,android_platform,build_mode):
  2.  
  3. ndk_path = os.path.join(ndk_root, "ndk-build")
  4.  
  5. # windows should use ";" to seperate module paths
  6. platform = sys.platform
  7. if platform == 'win32':
  8. ndk_module_path = 'NDK_MODULE_PATH=%s;%s/external;%s/cocos' % (cocos_root, cocos_root, cocos_root)
  9. else:
  10. ndk_module_path = 'NDK_MODULE_PATH=%s:%s/external:%s/cocos' % (cocos_root, cocos_root, cocos_root)
  11.  
  12. num_of_cpu = get_num_of_cpu()
  13. if ndk_build_param == None:
  14. command = '%s -j%d -C %s %s' % (ndk_path, num_of_cpu, app_android_root, ndk_module_path)
  15. else:
  16. command = '%s -j%d -C %s %s %s' % (ndk_path, num_of_cpu, app_android_root, ndk_build_param, ndk_module_path)
  17. print command
  18. if os.system(command) != 0:
  19. raise Exception("Build dynamic library for project [ " + app_android_root + " ] fails!")
  20. elif android_platform is not None:
  21. sdk_tool_path = os.path.join(sdk_root, "tools/android")
  22. cocoslib_path = os.path.join(cocos_root, "cocos/platform/android/java")
  23. command = '%s update lib-project -t %s -p %s' % (sdk_tool_path,android_platform,cocoslib_path)
  24. if os.system(command) != 0:
  25. raise Exception("update cocos lib-project [ " + cocoslib_path + " ] fails!")
  26. command = '%s update project -t %s -p %s -s' % (sdk_tool_path,android_platform,app_android_root)
  27. if os.system(command) != 0:
  28. raise Exception("update project [ " + app_android_root + " ] fails!")
  29. buildfile_path = os.path.join(app_android_root, "build.xml")
  30. command = 'ant clean %s -f %s -Dsdk.dir=%s' % (build_mode,buildfile_path,sdk_root)
  31. os.system(command)

这个方法是这个脚本里最重要的一个.现在基本作个逐行解释吧.

  1. ndk_path = os.path.join(ndk_root, "ndk-build")

os.path.join的功能是把,ndk_root和"ndk-build"链接到一起,ndk_root你ndk的根目录路径,上面已经做了设置."ndk-build"是ndk下的编译命令,用过ndk的会知道,这个命令是用来编译c/c++代码的.具体的可以参考你ndk目录中的docs文件夹,其中包括NDK-BUILD.xml这个文档就是来介绍ndk-build命令的.因为执行"ndk-build"命令,需要在ndk目录中执行.(也可以如上面的操作,设置到环境变量里,在执行此命令时就无需在根目录执行了).上面的输出,在我的机子上是"e:\\android-ndk-r9d\\ndk-build".

  1. num_of_cpu = get_num_of_cpu()
  2. if ndk_build_param == None:
  3. command = '%s -j%d -C %s %s' % (ndk_path, num_of_cpu, app_android_root, ndk_module_path)
  4. else:
  5. command = '%s -j%d -C %s %s %s' % (ndk_path, num_of_cpu, app_android_root, ndk_build_param, ndk_module_path)

获得编译命令。代码功能类似c++中的sprintf,将%后的参数依次置换为ndk_path等等,最后command获得置换后的值。

这个command就是要执行的编译命令,其中包括一些参数。目前做ndk编译的,一般都是在cygwin中执行,针对coco2d-x 2.x的编译用的是一个.sh文件。可以参考2.x版本的sh脚本。不过从ndkr8开始,其中已经内置了cygwin,所以使用ndk编译时就无需再在cygwin命令下执行编译命令了,可以直接在ndk中使用ndk-build命令。有个好处就是可以不需要安装cygwin了。 最后一个参数

  1. ndk_module_path 用以指示查找android.mk中使用$(call import-module, XXX)函数引入外部库文件的路径。
  1. ndk_build_param 这个参数没有搞懂是干嘛用的,脚本示例用的是-p,在ndk参考文档上没有找到。
  1. if os.system(command) != 0:
  2. raise Exception("Build dynamic library for project [ " + app_android_root + " ] fails!")

os.system(XX)可以执行上面的编译命令,如果不成功会抛个异常。这个方法很好用,如果你把XX换成你电脑上的某个程序,如我电脑上os.system("F:\\Program Files\\Tencent\\Bin\\QQ.exe"),就可以打开QQ了。

command中的第一个参数是你ndk根目录加"ndk-build",-j后面跟的是处理器核心数(在ndk官方文档上没找到这个参数,不过加上这个参数后,编译速度确实有所提高:)),-C后面跟的是编译生成的.so放置的路径。

  1. ndk_module_path 指示引入外部参考库的文件路径,在android.mk中会用到。
  2. ndk_build_param 这个参数脚本示例用的是 -p,在ndk文档里没找到这个参数,不知道其作用。
  3. sdk_tool_path = os.path.join(sdk_root, "tools/android") 获取sdk目录下android命令的执行路径,用来使用"android",执行update操作.
  4. cocoslib_path = os.path.join(cocos_root, "cocos/platform/android/java") 获取引擎里的java库工程路径
  5. command = '%s update lib-project -t %s -p %s' % (sdk_tool_path,android_platform,cocoslib_path)
  6.  
  7. command = '%s update project -t %s -p %s -s' % (sdk_tool_path,android_platform,app_android_root)

上面两条命令,第一条是执行android update lib-project的命令来更新库工程。第二条是执行android update project的命令来更新应用程序工程。

更新过的android工程会生成build.xml和ant属性文件,这样就可以使用ant进行打包程序了。

因为cocos2d-x引擎是分为两个部分的(针对for android开发来说),一个是c++端的,一个是java端的。c++端是重头,引擎的大功能都是c++实现的。但是针对android来说,最基本的还是java,首先你程序的启动必须是从java这边的activity启动的,然后再调用c++端的openGL_ES进行渲染,其中一些获取硬件功能的方法,如获取重力感应,也是需要java这边android sdk提供的接口来操作的,所以cocos2d-x for android,java这边的代码是必须存在的。2.x版本前,引擎java这边的代码是放到一个包里的,你需要把这个包引入到你的android工程中就可以使用java这端的引擎,进而调用c++那端的代码了,两者交互用的是jni,不懂的童鞋可以上网学习,这里就不做介绍了。3.x版本后,将java这端的引擎代码做成了一个库工程,到时你的android工程直接引用这个库工程就可以了,相对2.x的代码集成,这样管理代码更加方便和安全。

  1. buildfile_path = os.path.join(app_android_root, "build.xml")
  2. command = 'ant clean %s -f %s -Dsdk.dir=%s' % (build_mode,buildfile_path,sdk_root)

这里就是最后的android打包命令了,执行完后会在bin下生成apk.简单介绍下,clean就是清空工程目录下的gen,bin这些东东,-f 强制覆盖 -Dsd.dir 设置android sdk的路径

如果对ant不熟悉也没关系,你只需要知道两点:1.在eclipse上的创建,打包android程序就是执行的ant命令,eclipse只是封装成可视化操作而已。2.要学会使用ant创建和打包android工程(这里不做演示了,如果要搞定build.xml,要讲的也不少,可以去百度 android ant,里面有很多介绍)。

其实说完了上面的重点关注后,脚本剩下的就和上面的一些检查方法类似了。

  1. def copy_resources(target, app_android_root): 用来拷贝资源的,包括src下的代码,resource,asset下的资源文件。在ant打包时会把拷贝的资源打到apk里,基本上都是python文件操作的内容。还包括shutil高级文件操作模块。感兴趣的童鞋就去学习python吧。:)
  2. def build_samples(target,ndk_build_param,android_platform,build_mode):当前脚本文件编译的samples。我们这个脚本就是运行这个方法来执行拷资源,编译,打包的。

可以从代码中看出,执行的顺序是先把各种环境变量检查,赋值,然后执行拷贝资源,最后编译打包。

脚本最后的代码是类似c++的main(),也就是说这个脚本最开始运行的地方是从这里开始的

  1. # -------------- main --------------
  2. if __name__ == '__main__':
  3.  
  4. #parse the params
  5. usage = """
  6. This script is mainy used for building tests built-in with cocos2d-x.
  7.  
  8. Usage: %prog [options] [cpp-empty-test|cpp-tests|lua-empty-test|lua-tests|cpp|lua|all]
  9.  
  10. If you are new to cocos2d-x, I recommend you start with cpp-empty-test, lua-empty-test.
  11.  
  12. You can combine these targets like this:
  13.  
  14. python android-build.py -p 10 cpp-empty-test lua-empty-test
  15.  
  16. Note: You should install ant to generate apk while building the andriod tests. But it is optional. You can generate apk with eclipse.
  17. """
  18.  
  19. parser = OptionParser(usage=usage)
  20. parser.add_option("-n", "--ndk", dest="ndk_build_param",
  21. help='Parameter for ndk-build')
  22. parser.add_option("-p", "--platform", dest="android_platform",
  23. help='Parameter for android-update. Without the parameter,the script just build dynamic library for the projects. Valid android-platform are:[10|11|12|13|14|15|16|17|18|19]')
  24. parser.add_option("-b", "--build", dest="build_mode",
  25. help='The build mode for java project,debug[default] or release. Get more information,please refer to http://developer.android.com/tools/building/building-cmdline.html')
  26. (opts, args) = parser.parse_args()
  27.  
  28. if len(args) == 0:
  29. parser.print_help()
  30. sys.exit(1)
  31. else:
  32. try:
  33. build_samples(args, opts.ndk_build_param,opts.android_platform,opts.build_mode)
  34. except Exception as e:
  35. print e
  36. sys.exit(1)

注释写的很详细,说明了这个脚本的执行命令参数和其作用。

  1. parser = OptionParser(usage=usage)

上面这个也是python相关的。可以参考点击打开链接这篇博客。

写在最后:

非常感谢您看完了这篇博客,看得很窝火,很想打扁博主? 想打就来吧! :)

这算是工作以来的第一篇技术博客,而且之前已经很久没有写文章了,写的过程也是断断续续的,写完后发现博客也挺难写的,对那些写了很多技术博客的人表示崇拜和感谢。

写之前觉得自己基本都懂了,但是写的过程中发现,其实还不是真懂,于是期间自己也想了很久,就像给人讲授东西一样,自己又重新学了一遍。其中会有说不好的,或者错误的,等着拍砖!!!也等着以后自己来给自己拍砖!!!!!!!

cocos2d-x 3.1 编译脚本android-build.py的更多相关文章

  1. Powershell极速教程-如何在三分钟内编写项目编译脚本

    分析及思路 来看一下项目目录结构 炒鸡正常的三板斧src+docs+tests.咦,怎么会多出一个build的文件夹呢,这就是我们今天要研究的目录.今天我会带着大家在五分钟之内编写一个极简的编译脚本. ...

  2. Android系统编译脚本理解

    android源码编译步骤: 1. repo sync 代码(下载代码) 2.start branch(用哪个分支,git相关) 3. 到根目录(android目录) $cd android/ 4. ...

  3. 通过ant脚本编译打包android工程

    通过ant脚本,编译打包android工程 1.Android程序编译.打包.签名.发布的三种方式:  方式一:命令行手动编译打包  方式二:使用ant自动编译打包  方式三:使用eclipse+AD ...

  4. Android NDK学习(二):编译脚本语法Android.mk和Application.mk

    一.Android.mk Android.mk分为一下几部分: LOCAL_PATH:= $(call my-dir), 返回当前文件在系统中的路径,Android.mk文件开始时必须定义该变量. i ...

  5. Gradle Android最新自动化编译脚本教程

    转自:http://blog.csdn.net/changemyself/article/details/39927381 一.前言 Gradle 是以 Groovy 语言为基础,面向Java应用为主 ...

  6. Gradle Android它自己的编译脚本教程的最新举措(提供demo源代码)

    一.前言 Gradle 是以 Groovy 语言为基础,面向Java应用为主.基于DSL(领域特定语言)语法的自己主动化构建工具. 上面这句话我认为写得非常官方,大家仅仅需知道Gradle能够用来an ...

  7. 【转】Android ROM研究---Android build system增加模块

    原文网址:http://hualang.iteye.com/blog/1141315 Android build system就是编译系统的意思 在我们需要向自己编译的源代码中增加模块的时候,需要一些 ...

  8. 【转】理解 Android Build 系统----不错

    $ mmm -help用法:make [选项] [目标] ...选项: -b, -m 忽略兼容性. -B, --always-make Unconditionally make all targets ...

  9. Android - Ant自动编译打包android项目 -- 1(转)

    1.  背景: Eclipse用起来虽然方便,但是编译打包android项目还是比较慢,尤其当要将应用打包发布到各个渠道时,用Eclipse手动打包各种渠道包就有点不切实际了,这时候我们用到Ant帮我 ...

  10. 理解Android Build系统【转】

    本文转载自:http://www.ibm.com/developerworks/cn/opensource/os-cn-android-build/ Android Build 系统是用来编译 And ...

随机推荐

  1. c# xml序列化和反序列化。也就是xml的解析和反解析。

    用习惯了newTownSoft.json 的json反序列化.碰到xml是真的不习惯. 每次json反序列化都是直接把json丢到bejson网站生成一个实体类,稍微修改修改一点点变量名.然后直接ne ...

  2. 008-PageBean类模板

    1 PageBean模板一 package ${enclosing_package}; import java.util.ArrayList; import java.util.List; publi ...

  3. 【Lua】LWT遍历指定目录并输出到页面中

    首先用lua遍历目录: function getDirs(path) local s = {} function attrdir(p) for file in lfs.dir(p) do if fil ...

  4. CentOS6.4 安装Redis

    按照下面步骤依次执行1.检查依赖,安装依赖 [root@ecs-3c46 ~]# whereis gcc gcc: /usr/bin/gcc /usr/lib/gcc /usr/libexec/gcc ...

  5. Program, Process and Thread

    A program is an executable file store. A process is a running program. A thread is a single sequence ...

  6. Truncated incorrect DOUBLE value: 'NO_REFUND'

    解决办法:Mysql中,如果一个字段是字符串,则一定要加单引号 问题原因: `item_refund_state` ) NOT NULL item_refund_state字段的类型是varchar但 ...

  7. cs端调用webApi

    public class Httphelper { public static string Post1(string url, string postString) { using (WebClie ...

  8. Hadoop学习笔记(4) ——搭建开发环境及编写Hello World

    Hadoop学习笔记(4) ——搭建开发环境及编写Hello World 整个Hadoop是基于Java开发的,所以要开发Hadoop相应的程序就得用JAVA.在linux下开发JAVA还数eclip ...

  9. Linux pip 安装模块时,一直黄字错误:Could not find a version that satisfies the requirement

    参考原文:https://blog.csdn.net/u012592062/article/details/51966649 这时我们用国内的镜像源来加速 pip install 包名-i http: ...

  10. java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.List com.yunweather.app.db.YunWeatherDB.loadProvinces()' on a null object reference

    NullPointerException:查看自己的什么地方是否对空指针进行了操作 Attempt to invoke virtual method 'java.util.List com.yunwe ...