【Android本地开发技术:编译脚本】Android.mk
2015-07-31 14:43
696 查看
作者:郭孝星
微博:郭孝星的新浪微博
邮箱:allenwells@163.com
博客:http://blog.csdn.net/allenwells
Github:https://github.com/AllenWells
一个模块可以定义一个Android.mk文件,多个模块也可以公用一个Android.mk文件
Android.mk文件必须以LOCAL_PATH变量开始,它用于在树中定位文件。宏功能“my-dir”是由编译系统提供的,用于返回当前目录路径(包括Android.mk文件本身)。
LOCAL_MODULE变量必须被定义,用来区分Android.mk中的每一个模块。文件名必须是唯一的,不能有空格。
注意:编译器会自动加上一些前缀和后缀来保证模块名的唯一性。例如:“hello-jni”会被转换为“libhellp-jni.so”,Java中加载动态库时,依然使用“hello-jni”。
LOCAL_SRC_FILES变量被需包括一个C和C++源文件的列表,这些会编译并聚合到一个模块中。
注意:这里并不需要列出头文件和被包含的文件,编译系统会自动计算相关属性,源代码中的列表会直接传递给编译器。
该语句表示加载该动态库时必须链接/system/lib/libz.so这个动态库。编译模块时需要的附加的链接器选项,表明模块在编译时依赖的系统库。
注意:它不会附加列出的模块到编译图,即任然需要在Application.mk中把他们添加到程序要求的模块中。
注意:当几个静态库之间有循环依赖关系的时候,通常是很有益的。注意,当用来编译一个动态库的时候,这将迫使你将所有的静态库中的对象文件添加到最终的二进制文件中。但生成可执行程序时,这是不确定的。
注意:
这种方式对于指定额外的宏定义或编译选项很有用。
举例
有模块“foo”
另一个模块“bar”依赖于模块“foo”
当编译bar.c的时候,标志“-DFOO=1 -DBAR=2”将被传递到编译器,输出的标志被添加到模块的LOCAL_CFLAGS上,所以你可以很容易复写它们。它们也有传递性:如果”zoo”依赖”bar”,“bar”依赖”foo”,那么”zoo”也将继承”foo”输出的所有标志。当编译模块输出标志的时候,这些标志并不会被使用。当编译foo/foo.c时,-DFOO=1将不会被传递给编译器。
举例
这里,在连接器命令最后,libbar.so将以-llog参数进行编译来表明它依赖于系统日志库,因为它依赖于foo。
LOCAL_ARM_MODE := arm
···
默认情况下,在”thumb”模式下会生成ARM目标二进制,其中每个指令都是16位宽。你可以定义这个变量为”arm”,如果你想在”arm”模式下(32位指令)强迫模块对象文件的生成。
注意:当针对”armeabi-v7a”ABI对应的ARMv7指令集时你应该定义它。并不是所有的ARMv7都是基于NEON指令集扩展的CPU,你应该执行运行时来检测在运行时中这段代码的安全。另外,你也可以指定特定的源文件,比如用支持NEON”.neon”后缀的源文件也可以被编译。
···
LOCAL_SRC_FILES :=foo.c.neon bar.c zoo.c.arm.neon
···
在这个例子中,”foo.c”将会被编译在thumb+neon模式中,”bar.c”以thumb模式编译,zoo.c以arm+neon模式编译。如果你使用两个的话,”.neon”后缀必须出现在”.arm”后缀之后。
注意:此功能不修改ABI,并且只在ARMv6及以上的CPU设备的内核上被启用。
当模块中有很多的源文件,或者依赖很多的静态或动态库。这会强制编译系统使用一个中间的列表文件,并通过@$(listfile) 语法和library archiver 或者 static linker一起使用。
注意:
这种写法在Windows上特别有用,因为它的命令行最大只接收8191个字符,这对于比较复杂的工程显然太小了。
当该值被设置为true时就开启了这项功能,其他的值都会恢复默认行为。
所有的C/C++源码首先翻译为临时汇编文件(如果不定义LOCAL_FILTER_ASM,则C/C++源码直接编译为 obj 文件)
这些汇编文件被传给 LOCAL_FILTER_ASM 所指定的shell命令处理,得到一批新的汇编文件。
则foo.c首先传给编译器(gcc),得到 foo.S.orignal,然后这个 foo.S.original 被传给你指定的过滤器(LOCAL_ASM_FILTER),得到 foo.S,然后再传给汇编器(例如as),得到 foo.o。 bar.S 直接传给过滤器得到 bar.S.new,然后再传给汇编器,得到 bar.o。即在从.S到.o的编译流程中增加了一个过滤的环节。过滤器必须是独立的shell命令,输入文件作为它的第一个命令行参数,输出文件作为第二个命令行参数,
例如:
这个功能会清理掉所有以LOCAL_开头的内容。
BUILD_SHARED_LIBRARY这个变量是由系统提供的,并且指定给GNU Makefile的脚本,它收集所有定义的”include $(CLEAR_VARS)”中以LOCAL_开头的变量,并且决定哪些要被编译,哪些应该做的更加准确。编译生成的是以”lib.so”的文件,该文件便是生成的动态库。
BUILD_SHARED_LIBRARY这个变量是由系统提供的,并且指定给GNU Makefile的脚本,它收集所有定义的”include $(CLEAR_VARS)”中以LOCAL_开头的变量,并且决定哪些要被编译,哪些应该做的更加准确。编译生成的是以”lib.a”的文件,该文件便是生成的静态库。
编译成Native C可执行程序。
如果是Java文件,用BUILD_PACKAGE来指明,会用到系统的编译脚本host_java_library.mk。
根文件系统。
(TARGETPLATFORM)−(TARGET_PLATFORM)- (TARGET_ARCH_ABI)
它们都非常有用,特别是当你想测试一下具体的系统镜像在一个真实设备环境的时候。默认地,这个是“android-3-armeabi”。
返回最后包含的makefile的路径,这通常是当前Android.mk所在目录的路径,在Android.mk开始之前定义。
返回一个Android.mk文件所在位置的列表,以及当前的my-dir的路径。
比如对于以下目录:
sources/foo/Android.mk
sources/foo/lib1/Android.mk
sources/foo/lib2/Android.mk
如果sources/foo/Android.mk包含了以下语句:
那么,它将会自动将sources/foo/lib1/Android.mk和sources/foo/lib2/ Android.mk包含进来。此功能可以用于提供深层嵌套的源代码目录build system的层次结构。请注意,默认情况下,NDK只会寻找sources/*Android.mk。
允许你通过名字找到并包含另一个模块的的Android.mk。
这将会找到通过NDK_MODULE_PATH环境变量引用的模块的目录列表,并且将其自动包含到Android.mk中。
微博:郭孝星的新浪微博
邮箱:allenwells@163.com
博客:http://blog.csdn.net/allenwells
Github:https://github.com/AllenWells
一 Android.mk文件的作用和特点
1.1 Android.mk文件作用
该文件用来描述编译系统(build system)的,即一个微型的GNU Makefile片段,会由编译系统解析一次或多次。1.2 Android.mk文件特点
该文件用来将源文件组织成模块,模块中含有静态库或动态库。只有动态库会被安装到应用包中,静态库可以用来生成动态库。一个模块可以定义一个Android.mk文件,多个模块也可以公用一个Android.mk文件
- 不需要再Android.mk中列出头文件或其他的依赖关系,编译系统会自动计算处理。
二 Android.mk文件变量
2.1 LOCAL变量
2.1.1 LOCAL_PATH
LOCAL_PATH:=$(call my-dir)Android.mk文件必须以LOCAL_PATH变量开始,它用于在树中定位文件。宏功能“my-dir”是由编译系统提供的,用于返回当前目录路径(包括Android.mk文件本身)。
2.1.2 LOCAL_MODULE
LOCAL_MODULE :=hello-jniLOCAL_MODULE变量必须被定义,用来区分Android.mk中的每一个模块。文件名必须是唯一的,不能有空格。
注意:编译器会自动加上一些前缀和后缀来保证模块名的唯一性。例如:“hello-jni”会被转换为“libhellp-jni.so”,Java中加载动态库时,依然使用“hello-jni”。
2.1.3 LOCAL_MODULE_FILENAME
该变量是可选的,并且允许重新定义生成文件的名字。默认的,模块将始终生成lib.a或者lib.so文件,这是标准的UNIX公约。2.1.4 LOCAL_SRC_FILES
LOCAL_SRC_FILES := hello-jni.cLOCAL_SRC_FILES变量被需包括一个C和C++源文件的列表,这些会编译并聚合到一个模块中。
注意:这里并不需要列出头文件和被包含的文件,编译系统会自动计算相关属性,源代码中的列表会直接传递给编译器。
2.1.5 LOCAL_C_INCLUDES
需要包含的头文件目录。2.1.6 LOCAL_LDLIBS
LOCAL_LDLIBS :=-lz该语句表示加载该动态库时必须链接/system/lib/libz.so这个动态库。编译模块时需要的附加的链接器选项,表明模块在编译时依赖的系统库。
2.1.7 LOCAL_SHARED_LIBRARIES
表明模块运行时依赖的动态库列表,在链接时是必需的,以便在生成文件时嵌入相应的信息。注意:它不会附加列出的模块到编译图,即任然需要在Application.mk中把他们添加到程序要求的模块中。
2.1.8 LOCAL_STATIC_LIBRARIES
表示编译该模块需要的静态库列表。只有当前模块是动态库时该模块才有意义。2.1.9 LOCAL_WHOLE_STATIC_LIBRARIES
该变量表示相应的库被用作整个档案到链接程序中。注意:当几个静态库之间有循环依赖关系的时候,通常是很有益的。注意,当用来编译一个动态库的时候,这将迫使你将所有的静态库中的对象文件添加到最终的二进制文件中。但生成可执行程序时,这是不确定的。
2.1.10 LOCAL_J***A_LIBRARIES
编译Java应用程序和库的时候指定包含的Java类库,目前有core和framework两种。一般定义成以下形式:LOCAL_J***A_LIBRARIES := core framework
2.1.11 LOCAL_CPP_EXTENSION
这是个可选的变量,可以被定义为文件扩展名为c++的源文件,默认是”.cpp”,但是你可以改变它,例如LOCAL_CPP_EXTENSION:=.cxx
2.1.12 LOCAL_CPPFLAGS
编译C++代码的时候传递给编译器的选项(编译C代码不会用这里的选项)。最后得到的命令行选项中,这里指定的选项在 LOCAL_CFLAGS 指定的选项的后面。2.1.13 LOCAL_CFLAGS
当编译C/C++源文件时传递一个可选的编译器标志。注意:
这种方式对于指定额外的宏定义或编译选项很有用。
- 尽量不要改变Android.mk中的优化/调试级别,这个可以通过在Application.mk中设置相应的信息来自动为你处理,并且会会让NDK生成在调试过程中使用的有用的数据文件。
2.1.14 LOCAL_EXPORT_CFLAGS
定义这个变量用来记录C/C++编译器标志集合,并且会被添加到其他任何以LOCAL_STATIC_LIBRARIES和LOCAL_SHARED_LIBRARIES的模块的LOCAL_CFLAGS定义中。举例
有模块“foo”
include $(CLEAR_VARS) LOCAL_MODULE :=foo LOCAL_SRC_FILES :=foo/foo.c LOCAL_EXPORT_CFLAGS :=-DFOO=1 include $(BUILD_STATIC_LIBRARY)
另一个模块“bar”依赖于模块“foo”
include $(CLEAR_VARS) LOCAL_MODULE :=bar LOCAL_SRC_FILES :=bar.c LOCAL_CFLAGS:=-DBAR=2 LOCAL_STATIC_LIBRARIES:=foo include $(BUILD_SHARED_LIBRARY)
当编译bar.c的时候,标志“-DFOO=1 -DBAR=2”将被传递到编译器,输出的标志被添加到模块的LOCAL_CFLAGS上,所以你可以很容易复写它们。它们也有传递性:如果”zoo”依赖”bar”,“bar”依赖”foo”,那么”zoo”也将继承”foo”输出的所有标志。当编译模块输出标志的时候,这些标志并不会被使用。当编译foo/foo.c时,-DFOO=1将不会被传递给编译器。
2.1.15 LOCAL_EXPORT_CPPFLAGS
类似LOCAL_EXPORT_CFLAGS,但适用于C++标志。2.1.16 LOCAL_EXPORT_C_INCLUDES
类似LOCAL_EXPORT_C_CFLAGS,但是只有C能包含路径,如果”bar.c”想包含一些由”foo”模块提供的头文件的时候这会很有用。2.1.17 LOCAL_EXPORT_LDLIBS
类似于LOCAL_EXPORT_CFLAGS,但是只用于链接标志。注意,引入的链接标志将会被追加到模块的LOCAL_LDLIBS,这是因为UNIX连接器的工作方式。当模块foo是一个静态库的时候并且代码依赖于系统库时会很有用的。LOCAL_EXPORT_LDLIBS可以用于输出依赖,举例
include $(CLEAR_VARS) LOCAL_MODULE := foo LOCAL_SRC_FILES := foo/foo.c LOCAL_EXPORT_LDLIBS := -llog include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := bar LOCAL_SRC_FILES := bar.c LOCAL_STATIC_LIBRARIES := foo include $(BUILD_SHARED_LIBRARY)
这里,在连接器命令最后,libbar.so将以-llog参数进行编译来表明它依赖于系统日志库,因为它依赖于foo。
2.1.18 LOCAL_PRELINK_MODULE
是否需要做prelink处理。默认需要,用来做动态库优化。2.1.19 LOCAL_PREBUILT_EXECUTABLES
预编译including (BUILDPREBUILT)或者(BUILD_PREBUILT)或者(BUILD_HOST_PREBUILT)时所用,指定需要复制的可执行文件。2.1.20 LOCAL_REQUIRED_MODULES
指定模块运行所依赖的模块(模块安装时将会同步安装它所依赖的模块)。2.1.21 LOCAL_ALLOW_UNDEFINED_SYMBOLS
默认情况下,当试图编译一个共享库的时候遇到任何未定义的引用都可能导致”未定义符号”(undefined symbol)的错误。这在你的源代码中捕获bug会很有用。如果想禁用此项检查,可将值设置为true。2.1.22 LOCAL_ARM_MODE
···LOCAL_ARM_MODE := arm
···
默认情况下,在”thumb”模式下会生成ARM目标二进制,其中每个指令都是16位宽。你可以定义这个变量为”arm”,如果你想在”arm”模式下(32位指令)强迫模块对象文件的生成。
2.1.23 LOCAL_ARM_NEON
该变量为”true”会允许在你的C或C++源文件的GCC的内部函数中使用ARM高级SIMD(又名NEON),以及在聚合文件中的NEON指令。注意:当针对”armeabi-v7a”ABI对应的ARMv7指令集时你应该定义它。并不是所有的ARMv7都是基于NEON指令集扩展的CPU,你应该执行运行时来检测在运行时中这段代码的安全。另外,你也可以指定特定的源文件,比如用支持NEON”.neon”后缀的源文件也可以被编译。
···
LOCAL_SRC_FILES :=foo.c.neon bar.c zoo.c.arm.neon
···
在这个例子中,”foo.c”将会被编译在thumb+neon模式中,”bar.c”以thumb模式编译,zoo.c以arm+neon模式编译。如果你使用两个的话,”.neon”后缀必须出现在”.arm”后缀之后。
2.1.24 LOCAL_DISABLE_NO_EXECUTE
Android NDK r4开始添加了支持”NX位”安全功能特性。它是默认启用的,如果你需要的话,可以通过设置变量为“true”来禁用它。注意:此功能不修改ABI,并且只在ARMv6及以上的CPU设备的内核上被启用。
2.1.25 LOCAL_SHORT_COMMANDS
LOCAL_SHORT_COMMANDS := true /flase
当模块中有很多的源文件,或者依赖很多的静态或动态库。这会强制编译系统使用一个中间的列表文件,并通过@$(listfile) 语法和library archiver 或者 static linker一起使用。
注意:
这种写法在Windows上特别有用,因为它的命令行最大只接收8191个字符,这对于比较复杂的工程显然太小了。
当该值被设置为true时就开启了这项功能,其他的值都会恢复默认行为。
- 默认不推荐这项功能,因为它会使编译速度变慢。
2.1.26 LOCAL_FORCE_STATIC_EXECUTABLE
如果编译的可执行程序要进行静态链接(执行时不依赖于任何动态库),则设置该值为true。2.1.27 LOCAL_FILTER_ASM
这个变量指定一个shell命令,用于过滤LOCAL_SRC_FILES 中列出的汇编文件或者LOCAL_SRC_FILES列出的文件所编译出的汇编文件。定义该变量后,将导致以下行为:所有的C/C++源码首先翻译为临时汇编文件(如果不定义LOCAL_FILTER_ASM,则C/C++源码直接编译为 obj 文件)
这些汇编文件被传给 LOCAL_FILTER_ASM 所指定的shell命令处理,得到一批新的汇编文件。
- (这些新的汇编文件再被编译成obj文件。
换句话说,如果你定义:LOCAL_SRC_FILES := foo.c bar.S LOCAL_FILTER_ASM := myasmfilter
则foo.c首先传给编译器(gcc),得到 foo.S.orignal,然后这个 foo.S.original 被传给你指定的过滤器(LOCAL_ASM_FILTER),得到 foo.S,然后再传给汇编器(例如as),得到 foo.o。 bar.S 直接传给过滤器得到 bar.S.new,然后再传给汇编器,得到 bar.o。即在从.S到.o的编译流程中增加了一个过滤的环节。过滤器必须是独立的shell命令,输入文件作为它的第一个命令行参数,输出文件作为第二个命令行参数,
例如:
myasmfilter $OBJS_DIR/foo.S.original $OBJS_DIR/foo.S myasmfilter bar.S $OBJS_DIR/bar.S
2.2 CLEAR变量
2.2.1 CLEAR_VARS
CLEAR_VARS变量是由编译系统提供的,并且指明了一个GNU Makefile文件,其在/build/core/config.mk 文件定义为:CLEAR_VARS:=$(BUILD_SYSTEM)/clear_vars.mk)
这个功能会清理掉所有以LOCAL_开头的内容。
2.3 BUILD变量
2.3.1 BUILD_SHARED_LIBRARY
include $(BUILD_SHARED_LIBRARY)BUILD_SHARED_LIBRARY这个变量是由系统提供的,并且指定给GNU Makefile的脚本,它收集所有定义的”include $(CLEAR_VARS)”中以LOCAL_开头的变量,并且决定哪些要被编译,哪些应该做的更加准确。编译生成的是以”lib.so”的文件,该文件便是生成的动态库。
2.3.2 BUILD_STATIC_LIBRARY
include $(BUILD_ STATIC _LIBRARY)BUILD_SHARED_LIBRARY这个变量是由系统提供的,并且指定给GNU Makefile的脚本,它收集所有定义的”include $(CLEAR_VARS)”中以LOCAL_开头的变量,并且决定哪些要被编译,哪些应该做的更加准确。编译生成的是以”lib.a”的文件,该文件便是生成的静态库。
2.3.3 BUILD_EXECUTABLE
include $( BUILD_EXECUTABLE)编译成Native C可执行程序。
2.3.4 BUILD_J***A_LIBRARY.
2.3.5 BUILD_STATIC_J***A_LIBRARY
编译静态J***A库。2.3.6 BUILD_HOST_J***A_LIBRARY
编译本机用的J***A库。2.3.7 BUILD_PACKAGE
include $( BUILD_PACKAGE)如果是Java文件,用BUILD_PACKAGE来指明,会用到系统的编译脚本host_java_library.mk。
2.4 TARGET变量
2.4.1 TARGET_ROOT_OUT
LOCAL_MODULE_PATH :=$(TARGET_ROOT_OUT)根文件系统。
2.4.2 TARGET_OUT
system文件系统。2.4.3 TARGET_OUT_DATA
data文件系统2.4.4 TARGET_ARCH
目标CPU架构名,如果为“arm”则声称ARM兼容指令,与CPU架构版本无关。2.4.5 TARGET_ABI
目标平台和ABI的链接,这里要定义(TARGETPLATFORM)−(TARGET_PLATFORM)- (TARGET_ARCH_ABI)
它们都非常有用,特别是当你想测试一下具体的系统镜像在一个真实设备环境的时候。默认地,这个是“android-3-armeabi”。
2.4.6 TARGET_PLATFORM
目标平台的名字。2.4.7 TARGET_ARCH_ABI
CPU和ABI的名字。三 Android.mk文件宏
3.1 my-dir
include $(call my-dir)返回最后包含的makefile的路径,这通常是当前Android.mk所在目录的路径,在Android.mk开始之前定义。
3.2 all-subdir-makefiles
include $(call all-subdir-makefiles)返回一个Android.mk文件所在位置的列表,以及当前的my-dir的路径。
比如对于以下目录:
sources/foo/Android.mk
sources/foo/lib1/Android.mk
sources/foo/lib2/Android.mk
如果sources/foo/Android.mk包含了以下语句:
include $(call all-subdir-makefiles)
那么,它将会自动将sources/foo/lib1/Android.mk和sources/foo/lib2/ Android.mk包含进来。此功能可以用于提供深层嵌套的源代码目录build system的层次结构。请注意,默认情况下,NDK只会寻找sources/*Android.mk。
3.3 this-makefile
返回当前makefile的路径。3.4 parent-makefile
返回makefile的包含树,也就是包含Makefile当前的文件。3.5 grand-parent-makefile
返回调用树中父Makefile的父Makefile的路径。3.6 import-module
$(call import-module,)允许你通过名字找到并包含另一个模块的的Android.mk。
这将会找到通过NDK_MODULE_PATH环境变量引用的模块的目录列表,并且将其自动包含到Android.mk中。
相关文章推荐
- 简单乘法运算功能的实现
- (一)Android开发之高效加载Bitmap
- 将Android项目打包成APK文件
- 我的Android进阶之旅------>FastJson的简介
- Android 基础控件之AutoCompleteTextView
- android帧布局——霓虹灯
- android.support.design.widget.TabLayout
- Android程序开始的等待动画或LOGO
- android_Activity的四种启动模式和onNewIntent()
- android sqlite操作(1)
- androidstudio使用笔记
- Android动画效果translate、scale、alpha、rotate详解
- 从Android L默认ART虚拟机看国内手机圈
- Android activity onNewIntent触发时机
- Android Camera出现无法连接相机问题
- Android自定义文字闪烁渐变色的跑马灯
- Android 基础控件汇总之AlertDialog
- 【Android应用开发技术:应用组件】Intent使用方法
- 【Android应用开发技术:应用组件】Intent基本原理
- Android Studio中添加重载函数的方法