赞
踩
来源:https://www.jianshu.com/p/9aab51f4cd6f
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指令就是用来编译指定目录(单独模块的编译)。
如引用系统动态库:LOCAL_SHARED_LIBRARIES += liblog
如引用第三方动态库:LOCAL_LDFLAGS := -L$(LOCAL_PATH)/lib/ -ltest3
如引用第三方静态库:LOCAL_LDFLAGS := $(LOCAL_PATH)/lib/libtest2.a
如:LOCAL_C_INCLUDES = $(INCLUDES)
如引入共享(动态)jar包:LOCAL_STATIC_JAVA_LIBRARIES := libarity android-support-v4 guava
问题:一个工程下有多个源码文件,怎么统一管理进行编译?
工程目录结构.png
解答:将工程下的多个源码文件添加到Android.mk的变量LOCAL_SRC_FILES中
(1)方法一: 使用连接符“\”将每个源文件添加到Android.mk中 (2) 方法一: 使用系统提供的函数处理
编译多个源码文件的方法.png
编译生成目标文件.png
问题:如何在一个Android.mk 文件编译生成多个目标文件?如同时生成多个 bin 文件(二进制可执行文件)、.so 文件(动态库文件)和 .a 文件(静态库文件)。
解答:LOCAL_PATH变量不变,其他变量复制并重新进行配置
一个Android.mk 文件编译生成多个目标文件的方法.png
一个Android.mk 文件编译生成多个目标文件.png
- 如何编译生成二进制可执行文件exe->修改编译类型为:
BULID_EXECUTABLE
- 如何编译生成动态库文件so->修改编译类型为:
BULID_SHARED_LIBRARY
- 如何编译生成静态库文件a->修改编译类型为:
BULID_STATIC_LIBRARY
(1) 指定编译生成的文件类型
指定编译生成的文件类型.png
(2) 编译生成各类目标文件
编译生成各类目标文件.png
(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)
(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)
注
:若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)
-
- 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)
-
工程如何引入系统库
:将源文件中使用的系统库添加到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
说明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
语法:
- ifeq($(VALUE), x)
- do_yes
- else
- do_no
- endif
或
- ifneq($(VALUE), x)
- do_yes
- else
- do_no
- endif
如:
静态库与动态库的区别
首先来看什么是库,库(Library)说白了就是一段编译好的二进制代码,加上头文件就可以供别人使用。
什么时候我们会用到库呢?一种情况是某些代码需要给别人使用,但是我们不希望别人看到源码,就需要以库的形式进行封装,只暴露出头文件。另外一种情况是,对于某些不会进行大的改动的代码,我们想减少编译的时间,就可以把它打包成库,因为库是已经编译好的二进制了,编译的时候只需要 Link 一下,不会浪费编译时间。
上面提到库在使用的时候需要 Link,Link 的方式有两种,静态和动态,于是便产生了静态库和动态库。
静态库
静态库即静态链接库(Windows 下的 .lib,Linux 和 Mac 下的 .a)。之所以叫做静态,是因为静态库在编译的时候会被直接拷贝一份,复制到目标程序里,这段代码在目标程序里就不会再改变了。
静态库的好处很明显,编译完成之后,库文件实际上就没有作用了。目标程序没有外部依赖,直接就可以运行。当然其缺点也很明显,就是会使用目标程序的体积增大。
动态库
动态库即动态链接库(Windows 下的 .dll,Linux 下的 .so,Mac 下的 .dylib)。与静态库相反,动态库在编译时并不会被拷贝到目标程序中,目标程序中只会存储指向动态库的引用。等到程序运行时,动态库才会被真正加载进来。
动态库的优点是,不需要拷贝到目标程序中,不会影响目标程序的体积,而且同一份库可以被多个程序使用(因为这个原因,动态库也被称作共享库)。同时,编译时才载入的特性,也可以让我们随时对库进行替换,而不需要重新编译代码。动态库带来的问题主要是,动态载入会带来一部分性能损失,使用动态库也会使得程序依赖于外部环境。如果环境缺少动态库或者库的版本不正确,就会导致程序无法运行(Linux 下喜闻乐见的 lib not found 错误)。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。