Android mk 简介

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Viiou/article/details/90612983

本文参考:https://www.cnblogs.com/wainiwann/p/3837936.html https://blog.csdn.net/wjky2014/article/details/81532917

1.mk文件简介

mk文件是Android提供的makefile文件,用来编译生成exe,so,a,jar,apk等文件。在开发中,我们最常使用Android.mk文件编译so文件。

2.mk文件小例子

我们先从最简单的Android.mk文件看起

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE :=start-jni
LOCAL_SRC_FILES :=start_jni.cpp

include $(BUILD_SHARED_LIBRARY)

然后我们对mk文件中的代码进行逐行解释。

LOCAL_PATH := $(call my-dir)

每个Android.mk文件必须以LOCAL_PATH开始,用于查找资源文件,宏my-dir由Build System提供,返回Android.mk的路径。整句话就是返回Android.mk的路径作为编译文件的根目录。

include $(CLEAR_VARS)

CLEAR_VARS变量由Build System提供。并指向一个指定的GNU Makefile,由它负责清理很多LOCAL_xxx。例如:LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES等等。但不清理LOCAL_PATH。清理动作是必须的,因为所有的编译控制文件由同一个GNU Make解析和执行,其变量是全局的。所以清理后才能避免相互影响。

LOCAL_MODULE :=start-jni

LOCAL_MODULE必须定义,表示Android.mk中的每一个模块。Build System会自动添加适当的前缀和后缀。比如这行代码就会生成libstart-jni.so库。

LOCAL_SRC_FILES :=start_jni.cpp

LOCAL_SRC_FILES变量必须包含将要打包如模块的C/C++ 源码。

include $(BUILD_SHARED_LIBRARY)

BUILD_SHARED_LIBRARY:是Build System提供的一个变量,指向一个GNU Makefile Script。
它负责收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。并决定编译为什么。BUILD_STATIC_LIBRARY:编译为静态库。 BUILD_SHARED_LIBRARY :编译为动态库。BUILD_EXECUTABLE:编译为Native C可执行程序 。

至此,一个简单的Android.mk文件我们便讲解完了,从中可以看到,有很多都是定死的东西,我们只需要做适量的增加和修改就行了。

我们在使用 JNI的过程中,也可能会调用其他的so库,你可能会想,这有什么难的,直接将要用的so库放到生成libs/armeabi文件中就行了。这样做不行,如果直接复制,如果这时候你的cpp文件要修改,要生成新的so文件,这时你会发现原来复制的so文件都被删除了,只剩下新生成的so文件。所以我们要使用Android.mk的复制功能,让Android.mk给我们复制,这样就不会被删除了。

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := swscale
LOCAL_SRC_FILES := libswscale-4.so
include $(PREBUILT_SHARED_LIBRARY)

上面这行会将已经编译好的第三方库拷贝到 $PROJECT/libs/目录下,还有需要注意的是PREBUILT_SHARED_LIBRARY,它与上面的BUILD_SHARED_LIBRARY不一样,它代表预先编译好的动态库,而后面的代表构建动态库.

3.mk文件语法

在NDK中,下列作为保留变量名存在:以LOCAL_ 为开头的以PRIVATE_ ,NDK_ 或者APP_ 开头的名字,小写字母名字:如my-dir。

如果想在Android.mk中定义自己的变量名,建议添加MY_前缀。

3.1NDK提供的变量
3.1.1 CLEAR_VARS

清理变量,因为所有的编译由一个GNU Makefile提供,所以在一个模块开始前,需要清理一系列缓存变量,避免产生冲突。所以一个模块的第一行代码都是这个。

3.1.2 BUILD_SHARED_LIBRARY

收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息,编译出一个动态库。

3.1.3 BUILD_STATIC_LIBRARY

收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息,编译出一个静态库。

3.1.4 BUILD_EXECUTABLE

收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息,编译出一个可执行Native程序。

3.1.5 PREBUILT_SHARED_LIBRARY

把动态库声明为独立的模块,此时模块的LOCAL_SRC_FILES应该指定一个预先编译好的动态库。

3.1.6 PREBUILT_STATIC_LIBRARY

把静态库声明为独立的模块,此时模块的LOCAL_SRC_FILES应该指定一个预先编译好的静态库。

3.1.7 TARGET_ARCH

目标CPU架构。

3.1.8 TARGET_PLATFORM

目标平台的名字。

3.2NDK提供的功能宏

可以通过$(cakll function)的方式获得文本值。

3.2.1 my-dir

返回最近一次include的Makefile的路径。通常返回Android.mk所在的路径。它用来作为Android.mk的开头来定义LOCAL_PATH.。请注意:返回的是最近一次include的Makefile的路径。所以在include其它Makefile后,再调用$(call my-dir)会返回其它Android.mk所在路径。

LOCAL_PATH :=$(call my-dir)
include $(LOCAL_PATH)/foo/Android.mk
LOCAL_PATH :=$(call my-dir)

这时返回的LOCAL_PATH是$PATH/foo而不是$PATH

3.2.2 all-subdir-makefiles

返回一个列表,包含my-dir中所有子目录的Android.mk.
比如这样一个架构:sources/foo/Android.mk sources/foo/lib1/Android.mk sources/foo/lib2/Android.mk
如果在sources/foo/Android.mk中调用了

include $(call all-subdir-makefiles)

那么便include了sources/foo/lib1/Android.mk与sources/foo/lib2/Android.mk。

3.2.3 this-makefile

返回当前Android.mk的路径。

3.2.4 parent-makefile

返回父mk的路径,就是include了当前mk的mk

3.2.5 import-module

允许寻找并inport其它modules到本Android.mk中来。 它会从NDK_MODULE_PATH寻找指定的模块名。

3.3模块描述变量

这些是描述模块信息,在include $(CLEAR_VARS)include $(BUILD_XXXXX)之间。必须定义此类变量。

3.3.1 LOCAL_PATH

这个值用来给定当前目录。必须在Android.mk的开始位置定义。LOCAL_PATH不会被include $(CLEAR_VARS) 清理。

3.3.2 LOCAL_MODULE

在include $(BUILD_XXXXX)之前,必须定义这个变量。此变量必须唯一且不能有空格。
通常,由此变量名决定最终生成的目标文件名。

3.3.3 LOCAL_MODULE_FILENAME

可选。可以override LOCAL_MODULE. 即允许用户重新定义最终生成的目标文件名。

3.3.4 LOCAL_SRC_FILES

文件的source 文件列表。不需要列出依赖文件。 注意:文件相对于LOCAL_PATH存放,
且可以提供相对路径。

3.3.5 LOCAL_CPP_EXTENSION

可选。指出C++扩展名。

3.3.6 LOCAL_CPP_FEATURES

可选。指定C++特性。

3.3.7 LOCAL_C_INCLUDES

可选。Path列表,在编译时,会把这些目录附上。

3.3.8 LOCAL_CFLAGS

可选。在编译时添加Flags。注意:不要尝试在此处修改编译的优化选项和Debug等级。它会通过您Application.mk中的信息自动指定。

3.3.9 LOCAL_CXXFLAGS

可选。LOCAL_CPPFLAGS的别名。

3.3.10 LOCAL_CPPFLAGS

可选。C++编译时添加到的C Flags。

3.3.11 LOCAL_STATIC_LIBRARIES

可选。要链接到本模块的静态库。

3.3.12 LOCAL_SHARED_LIBRARIES

可选。要链接到本模块的动态库。

3.3.13 LOCAL_WHOLE_STATIC_LIBRARIES

可选。要链接本模块的所有静态库。

3.3.14 LOCAL_LDLIBS

可选。编译模块时要使用的附加的链接器选项以及添加系统库。

3.3.15 LOCAL_ARM_MODE

可选。缺省模式下,ARM目标代码被编译为thumb模式。每个指令16位。如果指定此变量为:arm。 则指令为32位。

3.3.16 LOCAL_ARM_NEON

可选。设置为true时,会讲浮点编译成neon指令。这会极大地加快浮点运算(前提是硬件支持) 。

3.3.17 LOCAL_EXPORT_CFLAGS

可选。定义这个变量用来记录C/C++编译器标志集合,并且会被添加到其他任何以LOCAL_STATIC_LIBRARIES和LOCAL_SHARED_LIBRARIES的模块的LOCAL_CFLAGS定义中。

4.mk文件大例子

在前面说了很多属性,常用的,不常用的都有。看着都很烦,不如实战起来,对一个Android.mk分析一下,模仿,学习,这就可以了。

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := avcodec
LOCAL_SRC_FILES := libavcodec-57.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avdevice
LOCAL_SRC_FILES := libavdevice-57.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avfilter
LOCAL_SRC_FILES := libavfilter-6.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avformat
LOCAL_SRC_FILES := libavformat-57.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avutil
LOCAL_SRC_FILES := libavutil-55.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := postproc
LOCAL_SRC_FILES := libpostproc-54.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swresample
LOCAL_SRC_FILES := libswresample-2.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swscale
LOCAL_SRC_FILES := libswscale-4.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := jni-start
LOCAL_SRC_FILES := Start.cpp
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
LOCAL_LDLIBS := -llog -lz
LOCAL_SHARED_LIBRARIES := avcodec avdevice avfilter avformat avutil postproc swresample swscale
include $(BUILD_SHARED_LIBRARY)

从代码中可以看到,代码很长,但是都不难。首先第一行,没错。LOCAL_PATH必须在mk文件的开始定义。接下来都是几个复制模块,即将动态库复制到libs文件中,模块的开头一般是include $(CLEAR_VARS),结尾是include $(PREBUILT_SHARED_LIBRARY)或者include $(BUILD_SHARED_LIBRARY)。然后再看一下复制模块中的内容,LOCAL_MODULE是模块的名称,因为是复制模块,所以LOCAL_SRC_FILES指的是动态库。然后看一下创建模块,最后一个模块,也就是根据C++生成so库文件。因为在C++文件中调用so库中的API,所以要指定LOCAL_C_INCLUDES和LOCAL_SHARED_LIBRARIES。然后是LOCAL_LDLIBS,这个是编译模块时要使用的附加的链接器选项以及添加的系统库。

可以感觉到,Android.mk的编写是不难的,只要多练,多学习别人的Android.mk写法,很快就能掌握这个技巧。

猜你喜欢

转载自blog.csdn.net/Viiou/article/details/90612983