Android.mk
LOCAL_PATH:= $(call my-dir)
#清理缓存变量
include $(CLEAR_VARS)
#表示目标模式
LOCAL_MODULE_TAGS := samples
#表示源文件编译路径 这个应用里面只有java源文件
LOCAL_SRC_FILES := $(call all-java-files-under, src)
#表示项目包名也就是模块名,在项目中唯一
LOCAL_PACKAGE_NAME := HelloWorld
#指定编译sdk版本为当前版本
LOCAL_SDK_VERSION := current
# 使用该指令编译目标Apk.
include $(BUILD_PACKAGE)
#搜索编译该源码目录下所有的mk文件,如果没有可以不写
include $(call all-makefiles-under,$(LOCAL_PATH))
简化
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
接下来我们来一行一行的分析
LOCAL_PATH := $(call my-dir)
一般看到这种带下划线的我们就会想到配置系统环境变量,何况这里还带有明显的路径名称。没错小伙子你很上道啊,你已经有开发者的直觉了。
LOCAl_PATH这好像是在指明什么路径。
:= 做开发的同学怎么看都觉得这像是赋值语句像但是又不完全像。
$(call my-dir)好像是去的系统值并把系统环境变量中的什么位置,或者文件位置赋值给LOCAL_PATH。
答案
Android.mk 文件必须先定义 LOCAL_PATH 变量:
LOCAL_PATH := $(call my-dir)
此变量表示源文件在开发树中的位置。在这行代码中,编译系统提供的宏函数 my-dir 将返回当前目录(Android.mk 文件本身所在的目录)的路径。
下一行
include $(CLEAR_VARS)
这一行学C语言的小伙伴大惊引包,include好像是引包的意思吧,没好好学c希望学c的小伙伴看到我的错我能纠正一下我。
在继续看好像是引用了一个什么清除的包。
答案
这一行声明 CLEAR_VARS 变量,其值由编译系统提供。
CLEAR_VARS 变量指向一个特殊的 GNU Makefile,后者会清除许多 LOCAL_XXX 变量,例如 LOCAL_MODULE、LOCAL_SRC_FILES 和 LOCAL_STATIC_LIBRARIES。请注意,GNU Makefile 不会清除 LOCAL_PATH。此变量必须保留其值,因为系统在单一 GNU Make 执行环境(其中的所有变量都是全局变量)中解析所有编译控制文件。在描述每个模块之前,必须声明(重新声明)此变量。
LOCAL_MODULE := hello-jni
每个模块名称必须唯一,且不含任何空格。编译系统在生成最终共享库文件时,会对您分配给 LOCAL_MODULE 的名称自动添加正确的前缀和后缀。例如,上述示例会生成名为 libhello-jni.so的库。
注意:如果模块名称的开头已经是 lib,则编译系统不会附加额外的 lib 前缀;而是按原样采用模块名称,并添加 .so 扩展名。因此,比如原来名为 libfoo.c 的源文件仍会生成名为 libfoo.so 的共享对象文件。此行为是为了支持 Android 平台源文件根据 Android.mk 文件生成的库;所有这些库的名称都以 lib 开头。
LOCAL_SRC_FILES := hello-jni.c
LOCAL_SRC_FILES 变量必须包含要编译到模块中的 C 和/或 C++ 源文件列表。这句话的意思就是说,我这个工程的源码路径只有一个文件,这个文件就是我这个MK文件所在目录下的hello-jni.c
include $(BUILD_SHARED_LIBRARY)
当前模块在静态链接时需要的库的名称。
Android.bp
Android.bp文件是什么
Android.bp文件首先是Android系统的一种编译配置文件,是用来代替原来的Android.mk文件的。在Android7.0以前,Android都是使用make来组织各模块的编译,对应的编译配置文件就是Android.mk。在Android7.0开始,Google引入了ninja和kati来编译,为啥引入ninja?因为随着Android越来越庞大,module越来越多,编译时间也越来越久,而使用ninja在编译的并发处理上较make有很大的提升。Ninja的配置文件就是Android.bp,Android系统使用Blueprint和Soong工具来解析Android.bp转换生成ninja文件。为了兼容老的mk配置文件,Android当初也开发了Kati 工具来转换mk文件生成ninja,目前Android Q里边,还是支持Android.mk方式的。相信在将来的版本中,会彻底让mk文件废弃,同时Kati也就淘汰了,只保留bp配置方式,所以我们要提前学习bp。Blueprint和Soong工具的源码在Android/build/目录下,我们可以通过查阅相关代码来学习!
上面是我引用的别人的说法.
image.png
语法初探
cc_library_shared { //编译成动态库,类似于Android.mk中的BUILD_SHARED_LIBRARY
name: "libbluetooth_jni", //编译出的模块的名称,类似于Android.mk中的LOCAL_MODULE
srcs: [ //源文件,类似于Android.mk中的LOCAL_SRC_FILES
"com_android_bluetooth_btservice_AdapterService.cpp",
"com_android_bluetooth_hfp.cpp",
"com_android_bluetooth_hfpclient.cpp",
"com_android_bluetooth_a2dp.cpp",
"com_android_bluetooth_a2dp_sink.cpp",
"com_android_bluetooth_avrcp.cpp",
"com_android_bluetooth_avrcp_controller.cpp",
"com_android_bluetooth_hid.cpp",
"com_android_bluetooth_hidd.cpp",
"com_android_bluetooth_hdp.cpp",
"com_android_bluetooth_pan.cpp",
"com_android_bluetooth_gatt.cpp",
"com_android_bluetooth_sdp.cpp",
],
include_dirs: [ //用户指定的头文件查找路径,类似于Android.mk中的LOCAL_C_INCLUDES
"libnativehelper/include/nativehelper",
"system/bt/types",
],
shared_libs: [ //编译所依赖的动态库,类似于Android.mk中的LOCAL_SHARED_LIBRARIES
"libandroid_runtime",
"libchrome",
"libnativehelper",
"libcutils",
"libutils",
"liblog",
"libhardware",
],
static_libs: [ //编译所依赖的静态库,类似于Android.mk中的LOCAL_STATIC_LIBRARIES
"libbluetooth-types",
],
cflags: [ ///编译flag,类似于Android.mk中的LOCAL_CFLAGS
"-Wall",
"-Wextra",
"-Wno-unused-parameter",
],
}
模块与示例
Android.bp 文件中的模块以模块类型开头,然后是一组格式属性:name: value,在一点上Android.bp的语法结构与JSON的语法结构相似,都是以键值对的形式编写。下面是一个简单示例:
android_app {
name: "Provision",
srcs: ["**/*.java"],
platform_apis: true,
product_specific: true,
certificate: "platform",
}
那么接下来逐行分析这段代码
android_app {
}
表示该模块用于构建一个apk
name: "Provision",
如果指定了 android_app 模块类型(在代码块的开头),就需要设定该模块的name 。此设置会为模块命名,生成的 APK 将与模块名称相同,不过带有 .apk 后缀。例如,在本例中,生成的 APK 将命名为 Provision.apk
srcs: ["**/*.java"],
srcs用于指定当前的模块编译的源码位置,*表示通配符
platform_apis: true,
设置该标记后会使用sdk的hide的api來编译。编译的APK中使用了系统级API,必须设定该值。和Android.mk中的LOCAL_PRIVATE_PLATFORM_APIS的作用相同
certificate: "platform",
Android中共有四中签名方式:
1.testkey:普通APK,默认使用该签名。
2.platform:该APK完成一些系统的核心功能。经过对系统中存在的文件夹的访问测试,这种方式编译出来的APK所在进程的UID为system。
3.shared:该APK需要和home/contacts进程共享数据。
4.media:该APK是media/download系统中的一环。
常见的模块类型
android_app
1.用于构建Android 应用程序安装包,是Android系统应用开发中常用的模块类型,与Android.mk中的BUILD_PACKAGE作用相同。
java_library
2.java_library用于将源代码构建并链接到设备的.jar文件中。默认情况下,java_library只有一个变量,它生成一个包含根据设备引导类路径编译的.class文件的.jar包。生成的jar不适合直接安装在设备上,通过会用作另一个模块的static_libs依赖项。
如果指定“installable:true”将生成一个包含“classes.dex”文件的“.jar”文件,适合在设备上安装。指定'host_supported:true'将产生两个变量,一个根据device的bootclasspath编译,另一个根据host的bootclasspath编译。
java_library_static
3.java_library_static作用等同于java_library,但是java_library_static已经过时,不推荐使用
android_library
4.android_library将源代码与android资源文件一起构建并链接到设备的“.jar”文件中。android_library有一个单独的变体,它生成一个包含根据device的bootclasspath编译的.class文件的.jar文件,以及一个包含使用aapt2编译的android资源的.package-res.apk文件。生成的apk文件不能直接安装在设备上,但可以用作android_app模块的static_libs依赖项。
cc_library
5.cc_library为device或host创建静态库或共享库。默认情况下,cc_library具有针对设备的单一变体。指定'host_supported:true'还会创建一个以主机为目标的库。与cc_library相关的模块类型还有cc_library_shared、cc_library_headers、cc_library_static等。
设置变量
在bp中可以通过=号来设定一个全局变量
src_path = ["**/*.java"]
android_app {
name: "Provision",
srcs: src_path,
platform_apis: true,
product_specific: true,
certificate: "platform",
}
默认模块
soong提供了一系列xx_defaults模块类型,例如:cc_defaults, java_defaults, doc_defaults, stubs_defaults等等。
xx_defaults的模块提供了一组可由其它模块继承的属性。其它模块可以通过defaults:["<:default_module_name>"]来继承xx_defaults类型模块中定义的属性。xxx_defaults类型的模块可以被多个模块继承,减少我们在bp中书写重复的属性。
cc_defaults {
name: "gzip_defaults",
shared_libs: ["libz"],
stl: "none",
}
cc_binary {
name: "gzip",
defaults: ["gzip_defaults"],
srcs: ["src/test/minigzip.c"],
}
数据类型
Android.bp中变量和属性是强类型,变量根据第一项赋值动态变化,属性由模块类型静态设置。支持的类型为:
1.布尔值(true或 false)
2.整数 (int)
3.字符串("string")
4.字符串列表 (["string1", "string2"])
5.映射 ({key1: "value1", key2: ["value2"]})
映射可以包含任何类型的值,包括嵌套映射