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文件那么直观 |