本文文档在如下位置,如有需要可以下载:

https://download.csdn.net/download/fanx9339/12542402

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/目录下,我们可以通过查阅相关代码来学习!

Android.bp文件配置规则

【模块和属性】

Android.bp描述的编译对象都是以模块为组织单位的,定义一个模块从模块的类型开始,模块有不同的类型,模块包含一些属性,下面举一个例子来具体说明:

cc_binary {name: ”avbctl”,defaults: [“avb_defaults”],static_libs: [“libavb_user”,“libfs_mgr”,],shared_libs: [“libbase”],srcs: [“tools/avbctl/avbctl.cc”],
}

上面例子中的cc_binary就是模块类型,表示该模块目标为二进制可执行文件。如果要编译一个APP,那么就使用android_app模块,要编译一个动态库,那么就使用cc_library_shared.soong工具支持的模块类型在android/build/soong/androidmk/cmd/androidmk/android.go中可以查到,有以下:

●模块类型后面用大括号“{}”将模块的所有属性包裹起来。
●每个属性的名字和值用中间用冒号连接起来,属性值要用双引号””包裹起来(如果属性值是变量,变量不需要加双引号):name: ”avbctl”表示模块name属性的值为avbctl,就是类比Android.mk中的LOCAL_MODULE := avbctl。模块的name属性是必须的,内容必须是独一无二的。如果属性被定义为数组,需要用中括号“[]”将数组的各元素包裹起来,每个元素中间用逗号“,”连接,一般常用的属性有name,srcs,cflags, cppflags, shared_libs,static_libs。

●查看全部支持的模块和各个模块支持的属性定义,请查看这个网址:https://ci.android.com/builds/submitted/6504066/linux/latest/view/soong_build.html。
●cc_defaults模块比较特殊,它表示该模块的属性可以被其他模块重复引用,类似于我们的头文件被其他cpp文件引用,举例:

cc_defaults {name: "gzip_defaults",shared_libs: ["libz"],stl: "none",
}cc_binary {name: "gzip",defaults: ["gzip_defaults"],/*这里等价于shared_libs: ["libz"],stl: "none",*/srcs: ["src/test/minigzip.c"],
}

●属性可以使用列表数组的形式,也可以使用unix通配符,例如:”*.java”
●每一条完整的属性定义语句加上逗号“,”表示结束
●注释包括单行注释//和多行注释/**/

●最重要的一点:目前android编译系统同时支持mk和bp两种,但是这两种是彼此单独运行的,所以bp中依赖的目标,例如动态库静态库目标,如果库是源代码的形式存在的,那么库的编译脚本必须也是通过bp文件编译才能被找到,否则用mk文件编译库,bp会提示找不到依赖的库目标。(paxdroid代码中因为要将framework相关内容编译到android的framework中,而android已经全部转还成bp,所以这一部分paxdroid也是使用的bp来编写的,不然会提示找不到)
更多的说明可以在android/build/soong/README.md文件中查找。如果找不到想要的,可以在官网找:https://ci.android.com/builds/submitted/6504066/linux/latest/view/soong_build.html

【变量】

变量可以直接定义,使用“=”号赋值,例如:

avbctl_srcs = [“tools/avbctl/avbctl.cc”],
cc_binary {name: ”avbctl”,defaults: [“avb_defaults”],static_libs: [“libavb_user”,“libfs_mgr”,],shared_libs: [“libbase”],srcs: avbctl_srcs,
}

【条件编译】

例如我们的mk文件中包括条件判断:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := fs_mgrifeq ($(ENABLE_USER2ENG),true)
LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
LOCAL_CFLAGS += -DENABLE_USER2ENG=1
endifLOCAL_CFLAGS += -Wno-error=implicit-function-declarationifeq ($(shell if [ -d $(TOPDIR)paxdroid/external/libethtool ]; then echo "exist"; else echo "notexist"; fi;), exist)LOCAL_SHARED_LIBRARIES +=libethtool
endifinclude $(BUILD_EXECUTABLE)

我们先分析下上面两个条件的意思,如果变量ENABLE_USER2ENG的值为true,那么追加这两个编译参数,否则不追加。第二个条件是说如果存在paxdroid/external/libethtool这个目录,那么就添加libethtool这个动态库,否则不添加。

要转换为bp写法,就需要我们通过go语言写一个新文件,新建一个自定义类型的模块,来判断这些条件,比如我的修改是在system/core/fs_mgr/Android.bp,那么要在添加 system/core/fs_mgr/fs_mgr.go

//这是申明当前的包名,就是你在哪个文件夹下,就写啥package fs_mgr//导入android的soong工具目录
import ("android/soong/android""android/soong/cc""fmt"//一般情况下不需要引用os包,这里要判断文件夹是否存在需要引用"os")//初始化入口函数
func init() {// for DEBUGfmt.Println("init start")//注册模块名:fs_mgr_condition,模块名的方法入口是:fs_mgrDefaultsFactory方法android.RegisterModuleType("fs_mgr_condition", fs_mgrDefaultsFactory)
}//实现fs_mgrDefaultsFactory方法:
func fs_mgrDefaultsFactory() (android.Module) {//如果我们编译的目标是bin文件,这里就是调用cc.DefaultsFactory()//如果编译目标是so库,那么调用的是cc.LibrarySharedFactory()。这里我们举例目标是bin文件:module := cc.DefaultsFactory()//添加装载时的钩子函数fs_mgrDefaultsandroid.AddLoadHook(module, fs_mgrDefaults)return module
}//实现钩子函数
func fs_mgrDefaults(ctx android.LoadHookContext) {//这里定义我们所有需要受到条件控制的变量,比如我们这里需要根据条件来控制Cflags和依赖//的动态库两个变量,所以我们只需要定义这两个即可,按照实际需求定义:type props struct {Cflags []stringShared_libs []string}p := &props{}p.Cflags = getCflags(ctx)p.Shared_libs = getShared_libs(ctx)ctx.AppendProperties(p)
}//实现getCflags(ctx)方法
func getCflags(ctx android.BaseContext) ([]string) {var cppflags []stringfmt.Println("ENABLE_USER2ENG:",ctx.AConfig().IsEnvTrue("ENABLE_USER2ENG"))if ctx.AConfig().IsEnvTrue("ENABLE_USER2ENG"){cppflags = append(cppflags, "-DALLOW_ADBD_DISABLE_VERITY=1", "-DENABLE_USER2ENG=1")}return cppflags
}//实现getShared_libs(ctx)方法
func getShared_libs(ctx android.BaseContext) ([]string) {var shared_libs []string//判断文件是否存在,该方法返回两个参数,一个isExists,一个errorisExists,error := PathExists ("paxdroid/external/libethtool")if(isExists && error == nil){//路径存在shared_libs = append(shared_libs, “libethtool”)}return shared_libs
}//实现判断文件夹是否存在的工具方法:
func PathExists(path string) (bool, error) {_, err := os.Stat(path)if err == nil {return true, nil}if os.IsNotExist(err) {return false, nil}return false, err
}

go脚本写完了,相应的再Android.bp文件引用,如下:

// 这些个必须添加,编译刚刚写的那个go脚本需要的一些依赖
bootstrap_go_package {// 名字和包路径和刚刚写的go文件一致name: "soong-fs_mgr",pkgPath: "android/soong/fs_mgr",deps: ["blueprint","blueprint-pathtools","soong","soong-android","soong-cc","soong-genrule",],//这里的srcs就写我们刚刚写的go脚本srcs: ["fs_mgr.go",],pluginFor: ["soong_build"],
}
// fs_mgr_condition 是我们在go语言中自定义的模块类型,模块的类型是fs_mgr_condition,
// 这个模块名字叫做:fs_mgr_defaults
fs_mgr_condition {name: "fs_mgr_defaults",
}
//-----------------------------------------------------------------------
//以上所有代码是标准的添加自定义模块来实现条件控制的代码,我们可以记下来作为参考,
//下面的代码才是我们编译具体模块的:
cc_binary {name: "fs_mgr",//这里引用上面定义的模块defaults: ["fs_mgr_defaults"],cppflags: ["-Wno-error=implicit-function-declaration "],
}

【操作符】

String类型、字符串列表类型和Map类型支持操作符“+”,例如:

binder_src_files = ["lib/libsystool_client/binder.c"],
cc_library_static {srcs: ["lib/libsystool_client/systool_client_static.c","ipc/pipe_client.c",] + binder_src_files,
}

Androidmk自动转换工具

另外对于现成的Android.mk文件,也可以尝试使用androidmk工具自动将mk文件转换成bp文件,进入android/out/soong/host/linux-x86/bin/androidmk目录下,输入命令: androidmk Android.mk > Android.bp即可将当前目录下的Android.mk文件自动转换成Android.bp(部分复杂的mk文件可能会提示错误,需要手动书写)。

自己动手再写一个

编译一个可执行文件,目录结构如下:

.├── Android.bp├── testbin.go└── test.c

Android.bp文件内容如下:

bootstrap_go_package {name:"soong-testbin",pkgPath:"android/soong/testbin",deps:["blueprint","soong","soong-android","soong-cc","soong-genrule",],srcs: ["testbin.go",],pluginFor: ["soong_build"],}testbin_condition{name:"testbin_defaults",}cc_binary{name: "testbin",defaults: ["testbin_defaults",],srcs:["test.c",],}

testbin.go文件内容:

package testbinimport ("android/soong/android""android/soong/cc""fmt")func init(){fmt.Println("init start test")android.RegisterModuleType("testbin_condition", testbinDefaultFactory)}func testbinDefaultFactory()(android.Module){module := cc.DefaultsFactory()android.AddLoadHook(module, testbinDefault)return module}func testbinDefault(ctx android.LoadHookContext){type props struct {Proprietary *bool}p := &props{}var proprietary boolproprietary = getProprietary(ctx)p.Proprietary = &proprietaryctx.AppendProperties(p)}func getProprietary(ctx android.LoadHookContext)(bool){if(ctx.AConfig().Getenv("BUILD_VENDOR") == "yes"){fmt.Println("BUILD_VENDOR ============= yes")return true}else{fmt.Println("BUILD_VENDOR ============= no")return false}}

上面代码的功能是根据编译的环境变量【BUILD_VENDOR】的值,确定testbin二进制目标编译生成的位置在system/bin还是在vendor/bin目录下。以上例程需要注意的两点是:

  1. proprietary这个属性定义的时候本来是小写的,但是在go语言中,首字母大写意味着可以被别的文件引用。所以红色部分,不管啥属性本来定义的名称是什么,都应该大写字母开头。
  2. 通常情况下我们的属性是字符串数组类型[]string,如果碰到了是bool型的属性来根据条件编写的话,应该定义为指针【*bool】切记!!!

Android.bp文件详解相关推荐

  1. Android - Manifest 文件 详解

    Manifest 文件 详解 本文地址: http://blog.csdn.net/caroline_wendy/article/details/20899281 Manifest可以定义应用程序及其 ...

  2. Android.mk文件详解介绍

    Android.mk 编译文件是用来向 Android NDK描述你的 C,C++源代码文件的,   这篇文档描述了它的语法.在阅读下面的内容之前,假定你已经阅读了 docs/OVERVIEW.TXT ...

  3. Android清单文件详解(三)----应用程序的根节点application

    <application>节点是AndroidManifest.xml文件中必须持有的一个节点,它包含在<manifest>节点下.通过<application>节 ...

  4. android .so文件详解以及兼容性

    Android 设备的CPU类型通常称为ABIs 问题描述 解决方法 1解决之前的截图 2解决后的截图 3解决方法 4建议 为什么你需要重点关注so文件 App中可能出错的地方 其他地方也可能出错 使 ...

  5. Android AndroidManifest 文件详解

    目录 一.概述 二.标签和属性 1.标签 2.属性 一.概述 AndroidManifest 文件,简称为 Manifest 文件,在 AndroidManifest 文件中,它告诉系统我们 App ...

  6. Android rc 文件详解

    应用中添加使用rc 0. 在Android.mk 同目录下新建文件haha.sh (文件名任意),执行shell 操作, 以下简单举例 #!/bin/sh rm -rf /system/etc/xxx ...

  7. Android 清单文件 详解

    转载于:https://www.cnblogs.com/mohe/archive/2013/03/31/2991642.html

  8. 生成jni的android.mk,Android Studio 3.5版本JNI生成SO文件详解

    学习在于记录,把自己不懂得容易忘记得记录下,才是最好得选择. 废话不多说,想要在Android开发中嵌入c/c++代码,直接开始如下步骤 1.创建需要调用的Java类 在你某个指定的包下创建如下类pa ...

  9. android 7 apk 安装程序,Android安装apk文件并适配Android 7.0详解

    Android安装apk文件并适配Android 7.0详解 首先在AndroidManifest.xml文件,activity同级节点注册provider: android:name="a ...

最新文章

  1. 简书 java jvm_JVM介绍
  2. 【pmcaff】2014互联网公司薪资排行榜
  3. Websniff -aspx网页嗅探工具及使用说明
  4. SAP Hybris Enterprise Commerce Platform ECP和SAP CRM架构比较
  5. DSP Builder
  6. vscode配置vue环境
  7. XSS攻击(出现的原因、预防措施......)
  8. speech production model
  9. 发起ajax请求很慢,为什么我的Ajax请求比一般的浏览器请求慢得多?
  10. servlet中文乱码_Servlet入门 信息过滤
  11. ctf wav文件头损坏_【CTF入门第二篇】南邮CTF web题目总结
  12. oracle 数据库文件丢失
  13. pulseaudio数据流框图
  14. I/O设备与主机的联系方式
  15. 安装完Final Cut Pro X后出现了打不开的情况的解决方法
  16. ROS下usb_cam的安装
  17. 《我要醉在草原上》歌手孟文豪,经典歌曲《克什克腾的眼泪》上线
  18. 【数学建模】数学建模学习2---整数规划(例题+matlab代码实现)
  19. linux mint17.2 安装fcitx输入法
  20. vantUI弹出框和微信小程序的究极大坑

热门文章

  1. 智能井盖:智慧城市下的井盖管理新模式
  2. pythonwhile语句是什么意思_谈谈Python中的while循环语句
  3. CryptoKitties谜恋猫同台公有链MagnaChain,CJ发声畅谈游戏生态
  4. python keyshot_KeyShot
  5. DeepDive 简介
  6. 如何使用egret开发微信小游戏(一)Hello World
  7. arduino 勘智k210_嘉楠科技发布自研芯片勘智K210 推动AI落地应用
  8. 推荐系统研究中的九大数据集
  9. 2021-06-07 自动排产软件在航天系统工程的应用
  10. 6S管理在制药生产车间应用的必要性及实施办法