5. Android.mk 的基本语法

1. Android.mk 介绍

Android.mk.png

Android.mk 是Android 提供的一种makefile 文件,注意用来编译生成 exe(二进制可执行文件)、so(动态库文件)、a(静态库文件)、jar(jar包) 和 apk 等文件。Android.mk和一个或多个.c的源文件放在同一目录下做为一个模块,通过mm或者mmm命令来编译该模块,生成自己所需的文件,如:二进制的可执行文件、动态库、静态库、jar包和apk。可参考原生的Android.mk文件进行修改来编写适合自己的Android.mk文件,故需要掌握Android.mk的基本语法。

通过make命令可以编译整个android源码;mm指令编译当前目录(单独模块的编译);mmm指令就是用来编译指定目录(单独模块的编译)。

2. Android.mk 基本语法

2.1 Android.mk 基本语法格式示例:

  • 配置环境变量:定义当前模块的相对路径
    LOCAL_PATH := $(call my-dir)
  • 清空当前环境变量:除 LOCAL_PATH 外的所有环境变量
    include $(CLEAR_VARS)
  • 编译所生成的目标文件的文件名
    LOCAL_MODULE := test
  • 编译该模块所需的源文件:使用连接符“\”连接多个源文件
    LOCAL_SRC_FILES := test.c
  • 编译所生成的目标文件的格式(类型):
    include $(BUILD_EXECUTABLE)

2.2 编译生成的目标文件类型:

  • EXECUTABLES:二进制可执行文件
  • SHARED_LIBRARIES:动态库文件
  • STATIC_LIBRARY:静态库文件
  • JAVA_LIBRARIES:jar包
  • PACKAGE:apk

2.3 Android.mk 中引用资源:

  • 引用系统静态库 —> LOCAL_STATIC_LIBRARIES += libxxx
  • 引用系统动态库 —> LOCAL_SHARED_LIBRARIES += libxxx

如引用系统动态库:LOCAL_SHARED_LIBRARIES += liblog

  • 引用第三方库文件 —> LOCAL_LDFLAGS := -L/PATH -lxxx

如引用第三方动态库:LOCAL_LDFLAGS := -L$(LOCAL_PATH)/lib/ -ltest3

如引用第三方静态库:LOCAL_LDFLAGS := $(LOCAL_PATH)/lib/libtest2.a

  • 引用第三方头文件 —> LOCAL_C_INCLUDES := path

如:LOCAL_C_INCLUDES = $(INCLUDES)

  • 引入头文件等 —> LOCAL_xxx := xxx
  • 引入jar包等 —> LOCAL_xxx := xxx

如引入共享(动态)jar包:LOCAL_STATIC_JAVA_LIBRARIES := libarity android-support-v4 guava

3 Android.mk管理源码文件(指定编译所需的源码文件)

3.1 编译多个源码文件

问题:一个工程下有多个源码文件,怎么统一管理进行编译?


工程目录结构.png

解答:将工程下的多个源码文件添加到Android.mk的变量LOCAL_SRC_FILES中
(1)方法一: 使用连接符“\”将每个源文件添加到Android.mk中 (2) 方法一: 使用系统提供的函数处理


编译多个源码文件的方法.png

编译生成目标文件.png

3.2 一个Android.mk 文件编译生成多个目标文件

问题:如何在一个Android.mk 文件编译生成多个目标文件?如同时生成多个 bin 文件(二进制可执行文件)、.so 文件(动态库文件)和 .a 文件(静态库文件)。
解答:LOCAL_PATH变量不变,其他变量复制并重新进行配置


一个Android.mk 文件编译生成多个目标文件的方法.png

一个Android.mk 文件编译生成多个目标文件.png

4 Android.mk 管理编译所生成的目标文件类型

4.1 编译生成 exe、so 或 a 文件 —> 源文件为 C/C++ 文件

  • 如何编译生成二进制可执行文件exe->修改编译类型为:BULID_EXECUTABLE
  • 如何编译生成动态库文件so->修改编译类型为:BULID_SHARED_LIBRARY
  • 如何编译生成静态库文件a->修改编译类型为:BULID_STATIC_LIBRARY

(1) 指定编译生成的文件类型


指定编译生成的文件类型.png

(2) 编译生成各类目标文件


编译生成各类目标文件.png

4.2 编译生成 jar 包或 apk文件 —> 源文件为 java 文件

(1) 编译生成 jar 包

  LOCAL_PATH := $(call my-dir)
  include $(CLEAR_VARS)
  LOCAL_SRC_FILES := $(call all-subdir-java-files)
  LOCAL_MODULE := com.test.myjar
  include $(BUILD_JAVA_LIBRARY)
  • 静态jar包:include $(BUILD_STATIC_JAVA_LIBRARY)
    使用.class文件打包而成的JAR文件,可以在任何java虚拟机运行
  • 动态jar包:include $(BUILD_JAVA_LIBRARY)
    在静态jar包基础之上使用.dex打包而成的jar文件,.dex是android系统使用的文件格式。

(2) 编译生成 apk
语法:

  LOCAL_PATH := $(call my-dir)
  include $(CLEAR_VARS)
  LOCAL_SRC_FILES := $(call all-subdir-java-files)
  LOCAL_PACKAGE_NAME := LocalPackage
  include $(BUILD_PACKAGE)
  • LOCAL_SRC_FILES := $(call all-subdir-java-files) —> 获取当前目录下所有的java文件作为源文件
  • LOCAL_PACKAGE_NAME := LocalPackage —> 编译生成的目标文件名为LocalPackage
  • include $(BUILD_PACKAGE) —> 编译生成的目标文件类型为apk

:若apk依赖于jar包,即在apk中导入jar包和库文件的语法为

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_JAVA_LIBRARIES := share-library
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := LocalPackage
include $(BUILD_PACKAGE)

  • apk中导入静态jar包 —> LOCAL_STATIC_JAVA_LIBRARIES := static-library
  • apk中导入动态(系统/共享)jar包 —> LOCAL_JAVA_LIBRARIES := share-library
    如:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_STATIC_JAVA_LIBRARIES := libarity android-support-v4 guava

LOCAL_SRC_FILES := $(call all-java-files-under, src)

LOCAL_SDK_VERSION := current

LOCAL_PACKAGE_NAME := Calculator

include $(BUILD_PACKAGE)

5. Android.mk 引入各种库和头文件

5.1 在工程引入系统库

工程如何引入系统库:将源文件中使用的系统库添加到Android.mk中,即LOCAL_SHARED_LIBRARIES += libxxx。libxxx 代表系统库名称。
(1) 如:新建源文件main.cpp中使用了系统函数 ALOGE("")

#include <stdio.h>
#define LOG_TAG "Main"
#include <utils/Log.h>
int main(void)
{
   ALOGE("test");
   return 0;
}

(2) 将源文件main.cpp添加至Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= test3
LOCAL_C_ALL_FILES := src/main.cpp
LOCAL_SRC_FILES := $(LOCAL_C_ALL_FILES)
LOCAL_MODULE_PATH := $(LOCAL_PATH)/bin
include $(BUILD_EXECUTABLE)

(3) 直接编译报错:没用将源码中使用的系统库文件引入工程


编译报错.png

(4) 修改Android.mk:将源文件main.cpp中使用的系统函数对应的库liblog加入,即添加LOCAL_SHARED_LIBRARIES += liblog


引入系统库文件.png

(5) 重新编译成功
编译成功.png

5.2 在工程引入第三方库

说明1:新建源文件test1.cpp

#include <stdio.h>
void call_test(void)
{
   printf("test1\n");
   return;
}

说明2:Android.mk文件如下

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE:= libtest3
LOCAL_C_ALL_FILES := src/test1.cpp
LOCAL_SRC_FILES := $(LOCAL_C_ALL_FILES)
LOCAL_MODULE_PATH := $(LOCAL_PATH)/lib
include $(BUILD_SHARED_LIBRARY)


include $(CLEAR_VARS)
LOCAL_MODULE:= test3
LOCAL_C_ALL_FILES := src/main.cpp
LOCAL_SHARED_LIBRARIES += liblog
LOCAL_SRC_FILES := $(LOCAL_C_ALL_FILES)
LOCAL_MODULE_PATH := $(LOCAL_PATH)/bin
include $(BUILD_EXECUTABLE)

备注:test1.cpp编译生成了动态库libtest3.so文件(相当于第三方库文件),main.cpp编译生成了二进制可执行test3文件。

5.2.1 引入第三方动态库

工程如何引入第三方动态库:将源文件中使用的第三方库添加到Android.mk中,即LOCAL_LDFLAGS := -L/Path -lxxx。Path 代表第三方库路径,xxx代表第三方库名称 or 编译生成的目标文件名
(1) 如:工程源文件main.cpp调用了test1.cpp中的函数,通过extern的方式

调用其他文件中的函数.png

(2) 直接编译则会报错:
编译报错.png

(3) 需修改Android.mk:引入第三方库libtest3.so文件,即添加:LOCAL_LDFLAGS := -L ./lib/ -ltest3 或LOCAL_LDFLAGS := -L$(LOCAL_PATH)/lib/ -ltest3
引入第三方库文件.png

(4) 重新编译成功
编译成功.png

5.2.2 引入第三方头文件

说明1:头文件test1.h 文件如下

#ifndef TEST1 H
#define TEST1 H
extern void call_test(void);
#endif

说明2:Android.mk文件如下

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE:= libtest3
LOCAL_C_ALL_FILES := src/test1.cpp
LOCAL_SRC_FILES := $(LOCAL_C_ALL_FILES)
LOCAL_MODULE_PATH := $(LOCAL_PATH)/lib
include $(BUILD_SHARED_LIBRARY)


include $(CLEAR_VARS)
LOCAL_MODULE:= test3
LOCAL_LDFLAGS := -L ./lib/ -ltest3
#LOCAL_LDFLAGS := -L$(LOCAL_PATH)/lib/ -ltest3
LOCAL_C_ALL_FILES := src/main.cpp
LOCAL_SHARED_LIBRARIES += liblog
LOCAL_SRC_FILES := $(LOCAL_C_ALL_FILES)
LOCAL_MODULE_PATH := $(LOCAL_PATH)/bin
include $(BUILD_EXECUTABLE)

工程如何引入第三方头文件:在Android.mk文件中配置头文件路径LOCAL_C_INCLUDES := Path 。Path 代表头文件的路径。
(1) 如:工程源文件main.cpp调用了test1.cpp中的函数,通过头文件的方式

main.cpp.png

(2) 当头文件的路径和main.cpp的路径相差很多时,可通过以下方式来引入头文件
main.cpp.png

配置头文件路径.png

5.2.3 引入第三方静态库

工程如何引入第三方静态库:将源文件中使用的第三方库静态库添加到Android.mk中,即LOCAL_LDFLAGS := Path。Path 代表第三方库静态库的路径。

引入第三方静态库.png

6. Android.mk 中使用判断语句

语法:

ifeq($(VALUE), x)  
  do_yes
else
  do_no
endif

ifneq($(VALUE), x)  
  do_yes
else
  do_no
endif

如:


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

推荐阅读更多精彩内容