写在前面:

前段时间下载了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. :-)

import sys
import os, os.path
import shutil
from optparse import OptionParser CPP_SAMPLES = ['cpp-empty-test', 'cpp-tests']
LUA_SAMPLES = ['lua-empty-test', 'lua-tests']
ALL_SAMPLES = CPP_SAMPLES + LUA_SAMPLES

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

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

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

def get_num_of_cpu():
''' The build process can be accelerated by running multiple concurrent job processes using the -j-option.
'''
try:
platform = sys.platform
if platform == 'win32':
if 'NUMBER_OF_PROCESSORS' in os.environ:
return int(os.environ['NUMBER_OF_PROCESSORS'])
else:
return 1
else:
from numpy.distutils import cpuinfo
return cpuinfo.cpu._getNCPUs()
except Exception:
print "Can't know cpuinfo, use default 1 cpu"
return 1

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

 platform = sys.platform

获得当前的操作系统平台

os.environ['NUMBER_OF_PROCESSORS']

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

def check_environment_variables():

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

def check_environment_variables_sdk():

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

def select_toolchain_version():

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

重点关注:

def do_build(cocos_root, ndk_root, app_android_root, ndk_build_param,sdk_root,android_platform,build_mode):

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

    # windows should use ";" to seperate module paths
platform = sys.platform
if platform == 'win32':
ndk_module_path = 'NDK_MODULE_PATH=%s;%s/external;%s/cocos' % (cocos_root, cocos_root, cocos_root)
else:
ndk_module_path = 'NDK_MODULE_PATH=%s:%s/external:%s/cocos' % (cocos_root, cocos_root, cocos_root) num_of_cpu = get_num_of_cpu()
if ndk_build_param == None:
command = '%s -j%d -C %s %s' % (ndk_path, num_of_cpu, app_android_root, ndk_module_path)
else:
command = '%s -j%d -C %s %s %s' % (ndk_path, num_of_cpu, app_android_root, ndk_build_param, ndk_module_path)
print command
if os.system(command) != 0:
raise Exception("Build dynamic library for project [ " + app_android_root + " ] fails!")
elif android_platform is not None:
sdk_tool_path = os.path.join(sdk_root, "tools/android")
cocoslib_path = os.path.join(cocos_root, "cocos/platform/android/java")
command = '%s update lib-project -t %s -p %s' % (sdk_tool_path,android_platform,cocoslib_path)
if os.system(command) != 0:
raise Exception("update cocos lib-project [ " + cocoslib_path + " ] fails!")
command = '%s update project -t %s -p %s -s' % (sdk_tool_path,android_platform,app_android_root)
if os.system(command) != 0:
raise Exception("update project [ " + app_android_root + " ] fails!")
buildfile_path = os.path.join(app_android_root, "build.xml")
command = 'ant clean %s -f %s -Dsdk.dir=%s' % (build_mode,buildfile_path,sdk_root)
os.system(command)

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

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".

    num_of_cpu = get_num_of_cpu()
if ndk_build_param == None:
command = '%s -j%d -C %s %s' % (ndk_path, num_of_cpu, app_android_root, ndk_module_path)
else:
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了。 最后一个参数

ndk_module_path 用以指示查找android.mk中使用$(call import-module, XXX)函数引入外部库文件的路径。
ndk_build_param 这个参数没有搞懂是干嘛用的,脚本示例用的是-p,在ndk参考文档上没有找到。
if os.system(command) != 0:
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放置的路径。

ndk_module_path 指示引入外部参考库的文件路径,在android.mk中会用到。
ndk_build_param 这个参数脚本示例用的是 -p,在ndk文档里没找到这个参数,不知道其作用。
sdk_tool_path = os.path.join(sdk_root, "tools/android") 获取sdk目录下android命令的执行路径,用来使用"android",执行update操作.
cocoslib_path = os.path.join(cocos_root, "cocos/platform/android/java") 获取引擎里的java库工程路径
command = '%s update lib-project -t %s -p %s' % (sdk_tool_path,android_platform,cocoslib_path) 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的代码集成,这样管理代码更加方便和安全。

buildfile_path = os.path.join(app_android_root, "build.xml")
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,里面有很多介绍)。

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

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

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

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

# -------------- main --------------
if __name__ == '__main__': #parse the params
usage = """
This script is mainy used for building tests built-in with cocos2d-x. Usage: %prog [options] [cpp-empty-test|cpp-tests|lua-empty-test|lua-tests|cpp|lua|all] If you are new to cocos2d-x, I recommend you start with cpp-empty-test, lua-empty-test. You can combine these targets like this: python android-build.py -p 10 cpp-empty-test lua-empty-test Note: You should install ant to generate apk while building the andriod tests. But it is optional. You can generate apk with eclipse.
""" parser = OptionParser(usage=usage)
parser.add_option("-n", "--ndk", dest="ndk_build_param",
help='Parameter for ndk-build')
parser.add_option("-p", "--platform", dest="android_platform",
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]')
parser.add_option("-b", "--build", dest="build_mode",
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')
(opts, args) = parser.parse_args() if len(args) == 0:
parser.print_help()
sys.exit(1)
else:
try:
build_samples(args, opts.ndk_build_param,opts.android_platform,opts.build_mode)
except Exception as e:
print e
sys.exit(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. HttpClient登陆后获取并携带cookies发起请求

    最近项目中,用到了登陆后获取并携带cookies发起请求的业务场景,现总结写出来备忘一下. 1.定义存取cookies信息的全局变量 public class HttpUtil { /** * 用来存 ...

  2. Unity QualitySettings.vSyncCount 垂直同步数

    QualitySettings.vSyncCount 垂直同步数 Description 描述 The VSync Count. 垂直同步数. The number of VSyncs that sh ...

  3. java中Map转化为bean

    Map 集合类用于存储元素对(称作“键”和“值”),其中每个键映射到一个值,在java编程中会经常用到.但是当我们进行业务逻辑的处理或着操作数据库时,往往应用的是我们自己定义的的Bean或VO来传递和 ...

  4. 自定义ajax,添加loading效果

    自定义ajax /** * @desc 自定义ajax请求,添加等待gif */ var n=0; $.defineAjax=function(obj){ n++; if(!$('#loadingDi ...

  5. D3介绍

    D3介绍 D3是用来做web页面可视化的组件,其官方网址为http://d3js.org 安装 D3类库的文件只有一个d3.js.下载后直接在html的<script>标签中引用此js就可 ...

  6. Python基础(3) - 数据类型:4元组类型

    Python Tuple 是不可变 list. 一旦创建了一个 tuple 就不能以任何方式改变它.Tuple是用()包括起来的. Tuple与List都是按照定义的顺序进行排序的,索引从0开始,与 ...

  7. Bash实践:抽样检测数据迁移至Redis集群后的数据一致性

    熟悉了一段时间的Bash编程,因此借此任务操作一把bash编程,主要涉及到Redis单节点与Redis集群的操作 1. 任务背景 近日有个任务需要将历史的Redis(主从节点)中的数据迁移至Redis ...

  8. Array中对象的排序

    1.子母排序 NSArray *kArrSort = [_dic allKeys]; //这里是字母数组:,g,a,b.y,m…… NSArray *resultkArrSort = [kArrSor ...

  9. Java - 网络IO的阻塞

    最近学习时碰到事件驱动和非阻塞的相关知识,随之想到了Java中的Reactor.io与nio的一些东西:在前辈的博客上翻了翻.复习复习,在此记录一番. 实在找不到比较大点的东西,于是随便弄了个压缩包, ...

  10. golang学习之win7下go web之revel安装

    接着上回记录的win7下go环境搭建,go的开发,现在除了sublime外,LiteIDE比较推荐,下载链接 下载安装后直接打开,需要配置下go环境(本机使用的是window 386版本),如下: 打 ...