转:http://blog.csdn.net/langresser_king/article/details/8275291

原本只是想记录一些常用的使用技巧,但是越写越得意(>_<),忍不住想要做出一份相对完善的说明文档,以供大家研究探讨。

写这篇文章的起因当然是实际工程需要,在搭建一个网游的android客户端时遇到种种恶心的问题,比如文件过多导致"Argument list too long" 的错误,又比如增加和删除文件时都需要维护好Android.mk配置,虽然可以通过写个脚本自动生成android.mk,但是终归不是很漂亮的解决方 案。通过本文所提到的几个方法,可以使Android.mk变得十分简洁,减少增加和删减工程文件时对Android.mk的修改,工程文件数目较多时会 非常实用。

我先附上修改后的cocos2d-x工程配置(在本文的最后,我还会附上原始的配置,有兴趣的同学可以对比下看看),然后在此基础上逐一说明:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) LOCAL_MODULE := cocos2dx_static
LOCAL_MODULE_FILENAME := libcocos2d # 定义查找所有cpp文件的宏
define all-cpp-files-under
$(patsubst ./%,%, $(shell find $(LOCAL_PATH) -name "platform" -prune -o -name "*.cpp" -and -not -name ".*"))
endef define all-subdir-cpp-files
$(call all-cpp-files-under,.)
endef # 定义查找所有c文件的宏,android有默认定义,此处可酌情省略
define all-c-files-under
$(patsubst ./%,%, $(shell find $(LOCAL_PATH) -name "platform" -prune -o -name "*.c" -and -not -name ".*"))
endef define all-subdir-c-files
$(call all-c-files-under,.)
endef # 通过查找获取所有工程文件列表
CPP_FILE_LIST := $(call all-subdir-cpp-files) \
$(wildcard $(LOCAL_PATH)/platform/*.cpp) \
$(wildcard $(LOCAL_PATH)/platform/android/*.cpp) \
$(wildcard $(LOCAL_PATH)/platform/android/jni/*.cpp)
C_FILE_LIST := $(call all-subdir-c-files) #4 加入工程文件,之所以不直接加是需要进行一个LOCAL_PATH的替换
LOCAL_SRC_FILES := $(CPP_FILE_LIST:$(LOCAL_PATH)/%=%)
LOCAL_SRC_FILES += $(C_FILE_LIST:$(LOCAL_PATH)/%=%) LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) \
$(LOCAL_PATH)/include \
$(LOCAL_PATH)/kazmath/include \
$(LOCAL_PATH)/platform/android LOCAL_EXPORT_LDLIBS := -llog\
-lz \
-lGLESv2 #5 加入头文件
LOCAL_C_INCLUDES := $(LOCAL_PATH) \
$(LOCAL_PATH)/include \
$(LOCAL_PATH)/kazmath/include \
$(LOCAL_PATH)/platform/android #6 需要链接的系统默认库
LOCAL_LDLIBS := -lGLESv2 \
-lEGL \
-llog \
-lz #7 加入静态库,加了LOCAL_WHOLE_STATIC_LIBRARIES代表编译器会将静态库完整链接而不会进行删减优化
LOCAL_WHOLE_STATIC_LIBRARIES := cocos_libpng_static
LOCAL_WHOLE_STATIC_LIBRARIES += cocos_jpeg_static
LOCAL_WHOLE_STATIC_LIBRARIES += cocos_libxml2_static
LOCAL_WHOLE_STATIC_LIBRARIES += cocos_libtiff_static #8 预编译宏
# define the macro to compile through support/zip_support/ioapi.c
LOCAL_CFLAGS := -DUSE_FILE32API
LOCAL_EXPORT_CFLAGS := -DUSE_FILE32API #9 声明生成静态库
include $(BUILD_STATIC_LIBRARY) #10 添加外部导入库目录
$(call import-add-path,$(LOCAL_PATH)) #11 添加导入库(基于上一行添加的导入库目录)
$(call import-module,platform/third_party/android/prebuilt/libjpeg)
$(call import-module,platform/third_party/android/prebuilt/libpng)
$(call import-module,platform/third_party/android/prebuilt/libxml2)
$(call import-module,platform/third_party/android/prebuilt/libtiff)

首先是自动遍历整个工程文件的方法,当解决这个问题,我们的目的也就实现了一大半。我先介绍makefile里面的三个常用命令:

1、wildcard : 扩展通配符,用于查找一个目录下的所有符合条件的文件
2、notdir : 去除路径,仅保留文件名
3、patsubst :替换通配符,也可以是任意文本替换

#1  #2这两处我定义了两个宏,用于遍历整个工程的cpp和c文件。

$(patsubst ./%,%, $(shell find $(LOCAL_PATH) -name "platform" -prune -o -name "*.c" -and -not -name ".*"))

如上文所 说,patsubst是文本替换,也就是把$(shell....)所返回的查找到的所有文件名去除掉开头的"./",具体替换原因我们下文会说明。 $(shell...)会执行任意的shell命令(如果是在windows下,就一定要用cygwin来执行ndk-build)。

find可以查找指定目录下的所有符合条件的文件。find后面跟查找目录,这里就是Android.mk所在目录。需要特别注意后面的 -name "platform" -prune这个参数,它可以过滤掉特定文件夹("platform"),使用时要先通过-name把文件夹名字传递过去,然后添加-prune,如果没 有需要过滤的文件夹,就不需要这个参数了。 -o可以指定输出,如果使用了-prune就一定要有这个参数,表示在过滤结果的基础上进行查找。  最后跟查找的判定式,示例中的判定式代表查找所有.c文件但是忽略以.开头的文件(通常是系统文件或隐藏文件)。  find命令是实现文件遍历的基础。

#3处我们定义了一个宏代表文件列表

CPP_FILE_LIST := $(call all-subdir-cpp-files) \
                $(wildcard $(LOCAL_PATH)/platform/*.cpp) \
                $(wildcard $(LOCAL_PATH)/platform/android/*.cpp) \
                $(wildcard $(LOCAL_PATH)/platform/android/jni/*.cpp)
C_FILE_LIST := $(call all-subdir-c-files)

调用 $(call all-subdir-cpp-files) 返回了所有cpp文件列表,但是由于我们有指定忽略platform目录的文件,所以需要在后面把这个目录下android平台相关的文件加进来。

$(wildcard $(LOCAL_PATH)/platform/*.cpp)

这个我们一开始有介绍,就是遍历某一目录下的所有特定扩展名的文件。这个命令的缺点是不支持递归目录遍历(否则也就不需要我们前面写一大堆东西了),不过如果你的工程没有太多目录的话,可以直接使用这个。

#4处正式把文件加入到android工程中

LOCAL_SRC_FILES := $(CPP_FILE_LIST:$(LOCAL_PATH)/%=%)
LOCAL_SRC_FILES += $(C_FILE_LIST:$(LOCAL_PATH)/%=%)

$(CPP_FILE_LIST:$(LOCAL_PATH)/%=%) 这个又是一个文本替换技巧。意思是,把CPP_FILE_LIST里面的所有$(LOCAL_PATH)/去掉。之所以有这样的替换是因为LOCAL_SRC_FILES已经包含了LOCAL_PATH,其文件名应该是相对于Android.mk的相对路径。如果SRC_FILES里面还包含LOCAL_PATH的路径那就出错了。同样这也是我们在#1 #2处需要将查找到的文件名中的"./"去除掉的原因。

#5~#9可以直接看注释,没有什么需要特别说明的。

我们再重点说下#10 #11,也就是导入库的使用。

LOCAL_WHOLE_STATIC_LIBRARIES += cocos_jpeg_static
#LOCAL_STATIC_LIBRARIES += cocos_jpeg_static
$(call import-module,platform/third_party/android/prebuilt/libjpeg)

加入静态 库(第一行和第二行看实际情况使用,差别不大),然后使用call import-module引入导入库。在编译我们这个Android.mk模块时编译器会自动查找并编译libjpeg模块。通过使用导入库可以更加清 晰和方便的复用现有库,或者像我一样把一个大的工程拆分成多个子模块,然后再链接到一起。这样还有一个附带的好处是,当我们修改Android.mk文件 时,本文件的代码都会重新编译,但是导入库引入的模块不会。如果我们的工程很大,那么使用导入库后就可以避免修改一下配置就重新编译整个工程的情况。

prebuilt库的使用:

目的:复用没有源代码的静态库或动态库。

方式:新建一个文件夹如libpng,将头文件放到里面的include目录,.a静态库放到里面的libs目录,新建一个Android.mk其内容如下

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := cocos_libpng_static
LOCAL_MODULE_FILENAME := png
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libpng.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_STATIC_LIBRARY)

重点有两个LOCAL_MODULE是prebuilt库的名字,外部使用时添加的就是这个名字, LOCAL_EXPORT_C_INCLUDES是导出头文件,方便外部头文件包含。

外部使用时像普通的导入库一样使用,再次强调名字一定要一致,否则prebuilt库无法正确导入,就会出现头文件找不到或者是链接错误:

LOCAL_WHOLE_STATIC_LIBRARIES := cocos_libpng_static
$(call import-module,cocos2dx/platform/third_party/android/prebuilt/libpng)

Android.mk高级写法的更多相关文章

  1. cocos2d-x 3.0 引用第三方库 及编译成apk时android mk文件写法

    cocos2d-x 3.0 中.假设你须要使用CocosStudio.Extensions扩展库 等等.都须要自己手动加入. 加入过程例如以下:(比方说如今我要加入libExtensions,libC ...

  2. android编译系统的makefile文件Android.mk写法

    Android.mk文件首先需要指定LOCAL_PATH变量,用于查找源文件.由于一般情况下Android.mk和需要编译的源文件在同一目录下,宏函数“my-dir”右编译系统提供的,用于返回当前路径 ...

  3. android编译系统的makefile文件Android.mk写法如下

    (1)Android.mk文件首先需要指定LOCAL_PATH变量,用于查找源文件.由于一般情况下Android.mk和需要编译的源文件在同一目录下,所以定义成如下形式:LOCAL_PATH:=$(c ...

  4. Android.mk编译的写法

    更多Android.mk的 用法见 :http://blog.csdn.net/fengbingchun/article/details/38705519 如何修改Android.mk 为Androi ...

  5. Android.mk走读与Cmake配置

    Android.mk认识: 在上一次[https://www.cnblogs.com/webor2006/p/9946061.html]中学会了用NDK提供的交叉编译工程编译成Android能运行的可 ...

  6. Android.mk 文件语法详解

    0. Android.mk简介: Android.mk文件用来告知NDK Build 系统关于Source的信息. Android.mk将是GNU Makefile的一部分,且将被Build Syst ...

  7. Android.mk相关知识

    Android.mk是Android提供的一种makefile文件,用来指定诸如编译生成so库名.引用的头文件目录.需要编译的.c/.cpp文件和.a静态库文件等.要掌握jni,就必须熟练掌握Andr ...

  8. Android.mk的用法和基础【转】

    一个Android.mk file用来向编译系统描述你的源代码.具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次.你可以在每一个Android.mk file中定义一个 ...

  9. Android.mk详解

    Android.mk是Android提供的一种makefile文件,用来指定诸如编译生成so库名.引用的头文件目录.需要编译的.c/.cpp文件和.a静态库文件等.要掌握jni,就必须熟练掌握Andr ...

随机推荐

  1. SQL之group by

    转自:理解group by 先来看下表1,表名为test: 表1 执行如下SQL语句: 1 2 SELECT name FROM test GROUP BY name 你应该很容易知道运行的结果,没错 ...

  2. >/dev/null 2>&1的含义

    转帖:http://www.cnblogs.com/dkblog/archive/2009/07/31/1980722.html os.system("/etc/init.d/winbind ...

  3. zabbix v3.0安装部署

    这篇文章没有写明init的部分要注意 zabbix v3.0安装部署 摘要: 本文的安装过程摘自http://www.ttlsa.com/以及http://b.lifec-inc.com ,和站长凉白 ...

  4. java 实现唯一ID生成器

      2014-11-08 内容存档在evernote,笔记名"java 实现唯一ID生成器"

  5. mac 终端添加颜色

    1.打开终端,然后找到终端偏好设置,选择自己喜欢的颜色 2.然后切换到当前用户的家目录: cd ~ 3.打开文件,开始编辑".bash_profile", 添加下面两句 expor ...

  6. ceph-RGW Jewel版新概念

    一.概述 zone: 包含多个RGW实例的一个逻辑概念.zone不能跨集群,同一个zone的数据保存在同一组pool中: zonegroup:一个zonegroup如果包含一个或多个zone,如果包含 ...

  7. PowerDesigner使用:[3]创建索引

    PowerDesigner是一款功能非常强大的建模工具软件,足以与Rose比肩,同样是当今最著名的建模软件之一.Rose是专攻UML对象模型的建模工具,之后才向数据库建模发展,而PowerDesign ...

  8. HDU 2602 Bone Collector 0/1背包

    题目链接:pid=2602">HDU 2602 Bone Collector Bone Collector Time Limit: 2000/1000 MS (Java/Others) ...

  9. tomcat服务器配置字符集为utf-8-彻底解决中文乱码问题

    <Connector port="8070" protocol="HTTP/1.1" connectionTimeout="20000" ...

  10. Groovy 学习手册(4)

    6. 领域特定语言 Groovy 有许多特性,使它非常适合写DSL(领域特定语言).这些特性包活: 具有委托机制的闭包: 点号(.)和语句末尾的分号(;)是可选的: 运算符的重载(例如,加号,减号等) ...