Android.bp 添加宏控¶
Android.mk 添加宏控¶
非常简单,只需要判断是某个设备就添加 cflags ,在c代码中就可以根据 RTFSC_SUPPORT_LTPO 是否定义来执行某段代码。
Android.bp 添加宏控¶
Android.bp 只是纯粹的配置文件,不包括分支、循环等流程控制。如果想要在Android.bp 中添加宏控,也是可以做到的。
mk+bp 方案¶
Android.mk¶
在 Android.bp 中配置前需要通过 mk 的方式注册到build/make/core/main.mk。
假设我们新增一个 rtfsc_feature.mk文件,并在 build/make/core/main.mk 中 include 这个文件。
//定义namespace
SOONG_CONFIG_NAMESPACES += rtfsc
//声明使用的变量
SOONG_CONFIG_rtfsc := \
rtfsc_product \
rtfsc_water_mark
//变量赋值
SOONG_CONFIG_rtfsc_rtfsc_product := $(TARGET_PRODUCT)
//变量赋值
SOONG_CONFIG_rtfsc_rtfsc_water_mark := true
-
SOONG_CONFIG_NAMESPACES 是 bp 进行 config 配置时需要指定。
-
注册变量名
-
定义变量名的值
Android.bp¶
soong_config_module_type {
name: "rtfsc_cc_defaults",
module_type: "cc_defaults",
config_namespace: "rtfsc",
variables: [
"rtfsc_product",
],
bool_variables: [
"rtfsc_water_mark",
],
properties: [
"cflags",
"shared_libs",
],
}
soong_config_string_variable {
name: "rtfsc_product",
values: [
"device_name_1",
"device_name_2",
],
}
//核心部分,若需要在每个外部的 Android.bp 使用,这里不声明,改成在用的外部 Android.bp 中声明
rtfsc_cc_defaults {
name: "rtfsc_inputflinger_defaults",
target: {
android: {
shared_libs: [
"libpackagelistparser",
],
cflags: [
"-DRTFSC_INPUT_EXTEND",
],
},
},
soong_config_variables: {
rtfsc_water_mark: {
cflags: [
"-DRTFSC_WATER_MARK",
],
},
rtfsc_product: {
device_name_1: {
cflags: [
"-DRTFSC_SUPPORT_LTPO",
],
},
}
},
}
-
soong_config_module_type 这个是bp 配置config 的核心,可以定义不同的配置类别,在编译的时候(soong_config_modules.go 中解析)会统计所有的soong_config_module_type。
-
name 指定config 配置,例如这里的 rtfsc_cc_defaults
-
config_namespace config 配置的namespace,必须要指定。
-
variables 注册所有的变量。
-
properties 变量需要涉及的property,如:"include_dirs", "static_libs", "shared_libs", "cflags", "srcs" 等等。
-
-
soong_config_string_variable 定义 rtfsc_cc_defaults 中依赖的 string 变量,这里的变量的值在前面的 mk 中已经定义。
-
soong_config_bool_variable 定义 rtfsc_cc_defaults 中依赖的 bool 变量,这里的变量的值在前面的 mk 中已经定义。
-
rtfsc_cc_defaults 真正区分每个变量的地方,并设置对应的 cflags 等等。 这里也可以不声明 rtfsc_cc_defaults,而是在需要用到的 Android.bp 才去用。比如在 frameworks/native/services/inputflinger/Android.bp 中需要区分设备:
假设这里的 Android.bp 文件所在的目录是 device/rtfsc/common/feature/Android.bp
外部 Android.bp 使用¶
比如 device/rtfsc/common/feature/Android.bp 文件没有定义 rtfsc_cc_defaults ;那么在 frameworks/native/services/inputflinger/Android.bp 中可以这样用:
soong_config_module_type_import {
from: "device/rtfsc/common/feature/Android.bp",
module_types: ["rtfsc_cc_defaults"],
}
rtfsc_cc_defaults {
name: "rtfsc_inputflinger_defaults",
target: {
android: {
shared_libs: [
"libpackagelistparser",
],
cflags: [
"-DRTFSC_INPUT_EXTEND",
],
},
},
soong_config_variables: {
rtfsc_water_mark: {
cflags: [
"-DRTFSC_WATER_MARK",
],
},
rtfsc_product: {
device_name_1: {
cflags: [
"-DRTFSC_SUPPORT_LTPO",
],
},
}
},
}
然后在 inputflinger_defaults 中添加
cc_defaults {
name: "inputflinger_defaults",
//添加部分
defaults: [
"rtfsc_inputflinger_defaults",
],
//添加部分
...
}
小结¶
mk 方案可以配合 lunch 设备时,根据 target 找到对应设备的 配置文件自动生成 mk 文件,这样做可以做到 feature 宏的目的。
go+bp 方案¶
此方案我们用 inputflinger 来举例,在其 c 代码中获取到当前 lunch 的设备名字,也就是 $TARGET_PRODUCT。
Android.bp¶
在 frameworks/native/services/inputflinger/Android.bp 中添加:
bootstrap_go_package {
name: "soong-rtfsc_inputflinger",
pkgPath: "android/soong/rtfsc_inputflinger",
deps: [
"soong-android",
"soong-cc",
],
srcs: [
"rtfsc_inputflinger.go",
],
pluginFor: ["soong_build"],
}
rtfsc_inputflinger_cc_defaults {
name: "rtfsc_inputflinger_defaults",
}
这里主要是添加一个 bootstrap_go_package 模块, - 名字:soong-rtfsc_inputflinger - 源文件:rtfsc_inputflinger.go
再定义一个 rtfsc_inputflinger_cc_defaults 模块,名字叫做 rtfsc_inputflinger_defaults 。
go文件¶
在解析到这个模块的 Android.bp 时,会对 rtfsc_inputflinger.go 进行编译。
package rtfsc_inputflinger
import (
"android/soong/android"
"android/soong/cc"
"fmt"
)
func init() {
android.RegisterModuleType("rtfsc_inputflinger_cc_defaults", inputflingerDefaultsFactory)
}
func inputflingerDefaultsFactory() (android.Module) {
module := cc.DefaultsFactory()
android.AddLoadHook(module, inputflingerHook)
return module
}
func inputflingerHook(ctx android.LoadHookContext) {
type props struct {
Cflags []string
}
p := &props{}
//AConfig() function is at build/soong/android/config.go
device_name := ctx.AConfig().DeviceName()
fmt.Println("DeviceName = ", device_name)
p.Cflags = append(p.Cflags, "-DPLATFORM_DEVICE_NAME=" + "\"" + device_name + "\"")
ctx.AppendProperties(p)
}
-
init() 首先init函数先会被执行,在 init 里面注册了一个新的模块类型 rtfsc_inputflinger_cc_defaults, 对应的函数是 inputflingerDefaultsFactory 。
-
inputflingerDefaultsFactory 需要注意的是其中 cc.DefaultsFactory 要根据模块类型的不同而不同。
- cc_binary –> cc.DefaultsFactory
- cc_library_shared –> cc.LibrarySharedFactory()
- java_library –> java.LibraryFactory()
这个可以在 build/soong/cc/library.go 和 java.go 中查看, 如 library.go
func RegisterLibraryBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("cc_library_static", LibraryStaticFactory)
ctx.RegisterModuleType("cc_library_shared", LibrarySharedFactory)
ctx.RegisterModuleType("cc_library", LibraryFactory)
ctx.RegisterModuleType("cc_library_host_static", LibraryHostStaticFactory)
ctx.RegisterModuleType("cc_library_host_shared", LibraryHostSharedFactory)
}
这例中,rtfsc_inputflinger_defaults 是被 cc_library_shared 使用, 但 go 文件中改成cc.LibrarySharedFactory()会导致编译不通过 这是为什么?!
-
inputflingerHook 然后我们给 rtfsc_inputflinger_cc_defaults 模块类型添加了一个 hook:inputflingerHook,当有 rtfsc_inputflinger_cc_defaults 类型的模块定义时 inputflingerHook 就会被触发执行。
我们希望的条件编译就可以在这个 hook 里面进行操作了。我们可以通过 ctx 来获取各种编译信息, 比如 PlatformSdkVersion, DeviceName。
我们可以通过 ctx.AppendProperties 来添加各种配置,可以配置的东西如下:
type props struct {
// 定义Android.bp中的各个字段
Cflags []string
Srcs []string
Include_dirs []string
Shared_libs []string
Local_include_dirs []string
Static_libs []string
Export_shared_lib_headers []string
}
这个例子中我们只是添加了一个 cflags 而已, 如果需要的话,我们可以添加源码文件及头文件目录,及依赖等。
Android.bp 使用¶
c代码中使用¶
小结¶
在 Android.bp 中添加 bootstrap_go_package 模块 soong-rtfsc_inputflinger ,并添加go源码文件。 在 go 源码中配置 cflags 、srcs 等等。
个人认为这个方案比较适合某个模块做一些宏控。
还发现一个问题,在 InputDispatcher.cpp 使用时,编译报错。即使在 libinputdispatcher_defaults 加上了 rtfsc_inputflinger_defaults 也不行。 可能是因为我对 Android.bp 还不够了解,所以这里还不知道怎么用。
总结¶
mk方案 | go方案 | |
---|---|---|
优点 | 合适全局feature使用 | 适合单模块使用 |
缺点 | 当做全局feature使用时,还需要用shell或者python自动生成mk文件 | 不像mk文件那么直观 |