Android.mk解析

一 简介

Android NDK的构建系统是基于GUN Makefile的,Android.mk其实就是一个用于向Android NDK构建系统描述NDK项目的GUN Makefile片段。
在编写涉及JNI的项目时,往往需要自己配置Android.mk:主要通过makefile语法,使用变量或语句对用到的工具链、要编译生成的库名称、生成库所依赖的源文件、生成动态库或静态库等信息进行描述...
下面从变量开始认识Android.mk

二 Android.mk中的常用变量

1、LOCAL_PATH
LOCAL_PATH :=$(call my-dir)
Android构建系统利用LOCAL_PATH来定位源文件,Android构建系统要求,Android.mk文档必须以该变量的定义开头。
my-dir是宏功能,这里将该变量设置为my-dir的返回值,即设置为当前目录
my-dir就是该Android.mk所在目录,一般就是我们的jni目录

2、Include &(CLEAR_VARS)
Android构建系统在单次执行中解析多个构建文件,
LOCAL_<name>是全局变量,这条语句在每个模块开头使用,可以帮助清除 除了LOCAL_PATH以外的其他LOCAL_<name>变量,避免模块间变量冲突,
例如可以清除如下文件:LOCAL_MODULELOCAL_SRC_FILES

3、LOCAL_MODULE
LOCAL_MODULE变量,简单理解就是给生成的so库文件设置的名称,如:
LOCAL_MODULE : = hello-jni,表示生成名为hello-jni的模块,
因为模块名称也被用于给构建过程生成的文件命名,
因此,构建系统加上适当的前缀,最终生成libhello-jni.so

4、LOCAL_SRC_FILES
该变量定义了生成库文件的源文件列表:
LOCAL_SRC_FILES := hello-jni.cpp
这里hello-jni只由一个源文件生成,包含多个源文件,注意用空格分开:
LOCAL_SRC_FILES := hello-jni.cpp hello-ndk.cpp

5、LOCAL_C_INCLUDES:
表示头文件的搜索路径,用来指定在编译时即将使用的头文件的位置,
一般在使用预编译库构建so时使用,用于包含第三方源文件对应的头文件
例:

LOCAL_C_INCLUDES := $(LOCAL_PATH) \
            $(ClientCommon_Path)/basecore/a2/framecore/include \
            $(ClientCommon_Path)/include/android/client \
            $(ClientCommon_Path)/basecore/a2/appshare/include/ \
            $(ClientCommon_Path)/basecore/a2/avcore/include/avcore \
            $(ClientCommon_Path)/include/android/meetingcore \
            $(ClientCommon_Path)/include/android/uithreadhandler \
            $(ClientCommon_Path)/include/android/MultiWhiteBoard \
            $(ClientCommon_Path)/include/android/terminalonlinemanager \
            $(ClientCommon_Path)/protocol 

6、LOCAL_LDLIBS:
用于告诉链接器,生成的模块要在加载时链接到的库,表示编译模块时要使用的附加的链接器选项。
使用‘-l’前缀传递指定库的名字
例:
LOCAL_LDLIBS := -lz表示告诉链接器生成的模块要在加载时链接到
/system/lib/libz.so/system/lib/libz.a(可链接到动态库或静态库)

例:
要与NDK日志库链接:
LOCAL_LDLIBS:= -llog

连接到多个静态库或动态库(用空格隔开):
LOCAL_LDLIBS:= -ltinyxml32 -luithreadhandler -lxmlprotocolparser32

7、 自定义新的变量
MyLibrary_Path := $(LOCAL_PATH)/../../library
( ../ 表示上一级目录)
注意:以LOCAL和NDK前缀开头的名称预留给Android NDK构建系统使用,自定义变量应避免使用这两个前缀

三 构建动态库(xxx.so)

为了建立可供主应用程序使用的模块,必须将该模块变成动态库,只有动态库才能被安装/复制到APK包中。
构建动态库,在Android.mk中相应模块下添加如下描述语句即可:

include &(BUILD_SHARED_LIBRARY)

比如在一个工程中定义两个动态库:

LOCAL_PATH := &(call my-dir)

//模块1:
include &(CLEAR_VARS)

LOCAL_MODULE := module1
LOCAL_SRC_FILES := moudel1.cpp
include &(BUILD_SHARED_LIBRARY)
----------------------------------------------------
//模块2:
include &(CLEAR_VARS)

LOCAL_MODULE := module2
LOCAL_SRC_FILES := moudel2.cpp
include &(BUILD_SHARED_LIBRARY)

定义完成后,NDK构建系统将会产生两个动态库:moudel1.somoudel2.so

四 构建静态库(xxx.a)

构建静态库,在Android.mk相应模块添加描述语句:
include $(BUILD_STATIC_LIBRARY) (生成静态库)

Android应用程序不直接使用静态库,且apk中也不包含静态库,但静态库可以用来构建动态库
例如:
开放某个核心库的功能给他人使用时,无须将核心源代码提供给客户,而是将这些代码编译成静态库,用户只需并入他们的动态库就可使用了

//编译.a静态库
LOCAL_PATH := &(call my-dir)
include &(CLEAR_VARS)

LOCAL_MODULE := avilib
LOCAL_SRC_FILES := avilib.cpp  platform.cpp
include &(BUILD_STATIC_LIBRARY)   //编译生成静态库

第三方使用这个静态库构建自己的动态库在应用程序中使用:
用库名称为变量LOCAL_STATIC_LIBRARY赋值,即可引用静态库:
LOCAL_STATIC_LIBRARY:静态库名称

//原生模块
LOCAL_PATH := &(call my-dir)
include &(CLEAR_VARS)

LOCAL_MODULE := module2
LOCAL_SRC_FILES := module2.cpp
LOCAL_STATIC_LIBRARIES := avilib   //引用编译好的.a静态库
include &(BUILD_SHARED_LIBRARY)
五 用动态库构建通用模块

承接上一个静态库的示例代码,多个动态库与同一个静态库相连时,会产生重复连接,增加了apk大小
所以,当有多个动态库都使用某个库时,一般将该模块建立为动态库,避免重复连接。

LOCAL_PATH := &(call my-dir)

//编译动态库
include &(CLEAR_VARS)

LOCAL_MODULE := avilib
LOCAL_SRC_FILES := avilib.cpp  platform.cpp
include &(BUILD_SHARED_LIBRARY)     //多个moduel使用,构建成动态库

多个模块引用同一个动态库:
使用变量LOCAL_SHARED_LIBRARIES引用动态库:
LOCAL_SHARED_LIBRARIES :动态库名称

//原生模块1
include &(CLEAR_VARS)

LOCAL_MODULE := module1
LOCAL_SRC_FILES := module1.cpp
LOCAL_SHARED_LIBRARIES := avilib    //引用1
include &(BUILD_SHARED_LIBRARY)
----------------------------------------------------
//原生模块2
include &(CLEAR_VARS)

LOCAL_MODULE := module2
LOCAL_SRC_FILES := module2.cpp
LOCAL_SHARED_LIBRARIES := avilib    //引用2
include &(BUILD_SHARED_LIBRARY)
六 使用Rebuild库完成预构建

Prebuid:预构建
NDK R5以后包含Rebuid库,在Rebuild库的支持下,可以依赖编译好的so生成动态库

1、声明预编译库的模块
Android.mk可以写成如下形式:

LOCAL_PATH := &(call my-dir)
COMMON_LIBS_PATH := ../../ClientCommon

// 预构建库
include &(CLEAR_VARS)
LOCAL_MODULE := avnet       //生成的预编译库名称(名称可不与依赖库相同)
LOCAL_SRC_FILES := $(COMMON_LIBS_PATH)/basecore/libavnet.so
include &(PREBUILT_SHARED_LIBRARY)

说明:
1)LOCAL_SRC_FILES变量不再指向源文件,而是直接指向so库文件
2)预构建库的声明语句:
include &(PREBUILT_SHARED_LIBRARY)生成预构建动态库
include &(PREBUILT_STATIC_LIBRARY)生成预构建静态库

2、在其他模块引用这个预编译库:
与引用普通动态库的方式相同
预编译静态库的名字赋值给变量LOCAL_STATIC_LIBRARIES
预编译动态库的名字赋值给变量LOCAL_SHARED_LIBRARIES

3、将预编译库的头文件导出:LOCAL_C_INCLUDES
得到预编译库后,一般需要提供它对应的头文件,
因为依赖库生成预编译库时,需要将它的头文件提供给NDK构建系统
例:
依赖libavnet.so生成预编译库时,有对应的avnet.h头文件在include子目录,
那么在Android.mk中需要使用LOCAL_C_INCLUDES变量指定该头文件或直接指定该目录:
LOCAL_C_INCLUDES := $(LOCAL_PATH) /include

4、优点
利用Prebuild预编译,依赖so库生成最终的so库
1)可不发布源代码,只将so库发布给第三方开发人员
2)直接指向so库文件,称之为预构建,可以加速构建过程

七 条件操作

针对不同的平台,可能使用不同的代码,使用条件操作可进行区分处理
例:

ifeq (&(TARGET_ARCH),arm)
LOCAL_SRC_FILES += armonly.c
else
LOCAL_SRC_FILES += generic.c
endif
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,275评论 25 707
  • Android游戏开发实践(1)之NDK与JNI开发02 承接上篇Android游戏开发实践(1)之NDK与JNI...
    AlphaGL阅读 3,734评论 0 24
  • 最近,喜欢上了余华,文字简单,意蕴不简单,读了一遍不够,第二遍时发现遗落许多精彩情节,这个情节,每每读起,让...
    春妮宝贝阅读 296评论 0 0
  • 重新阅读团长的《只因目中无人》,读的过程有了更深的感受。首先自己语言表达能力比较弱,通过读一定程度上对自己有所帮助...
    墨韵阅读 237评论 0 0
  • 你试过酒醉后写东西吗 嗯 就是这样。
    留子尧阅读 202评论 0 2