1. Android.mk 介绍
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 编译多个源码文件
问题:一个工程下有多个源码文件,怎么统一管理进行编译?
解答:将工程下的多个源码文件添加到Android.mk的变量LOCAL_SRC_FILES中
(1)方法一: 使用连接符“\”将每个源文件添加到Android.mk中 (2) 方法一: 使用系统提供的函数处理
3.2 一个Android.mk 文件编译生成多个目标文件
问题:如何在一个Android.mk 文件编译生成多个目标文件?如同时生成多个 bin 文件(二进制可执行文件)、.so 文件(动态库文件)和 .a 文件(静态库文件)。
解答:LOCAL_PATH变量不变,其他变量复制并重新进行配置
4 Android.mk 管理编译所生成的目标文件类型
4.1 编译生成 exe、so 或 a 文件 —> 源文件为 C/C++ 文件
- 如何编译生成二进制可执行文件exe->修改编译类型为:
BULID_EXECUTABLE
- 如何编译生成动态库文件so->修改编译类型为:
BULID_SHARED_LIBRARY
- 如何编译生成静态库文件a->修改编译类型为:
BULID_STATIC_LIBRARY
(1) 指定编译生成的文件类型
(2) 编译生成各类目标文件
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) 直接编译报错:没用将源码中使用的系统库文件引入工程
(4) 修改Android.mk:将源文件main.cpp中使用的系统函数对应的库liblog加入,即添加LOCAL_SHARED_LIBRARIES += liblog
(5) 重新编译成功
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的方式
(2) 直接编译则会报错:
(3) 需修改Android.mk:引入第三方库libtest3.so文件,即添加:LOCAL_LDFLAGS := -L ./lib/ -ltest3 或LOCAL_LDFLAGS := -L$(LOCAL_PATH)/lib/ -ltest3
(4) 重新编译成功
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中的函数,通过头文件的方式
(2) 当头文件的路径和main.cpp的路径相差很多时,可通过以下方式来引入头文件
5.2.3 引入第三方静态库
工程如何引入第三方静态库
:将源文件中使用的第三方库静态库添加到Android.mk中,即LOCAL_LDFLAGS := Path
。Path 代表第三方库静态库的路径。
6. Android.mk 中使用判断语句
语法:
ifeq($(VALUE), x)
do_yes
else
do_no
endif
或
ifneq($(VALUE), x)
do_yes
else
do_no
endif
如: