跳转至

Android.bp 添加宏控

Android.mk 添加宏控

ifeq ($(TARGET_PRODUCT), "you target product name")
LOCAL_CFLAGS += -DRTFSC_SUPPORT_LTPO
endif

非常简单,只需要判断是某个设备就添加 cflags ,在c代码中就可以根据 RTFSC_SUPPORT_LTPO 是否定义来执行某段代码。

#ifdef RTFSC_SUPPORT_LTPO  
...
#endif

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 配置时需要指定。

  • 注册变量名

    上面指定的 namespace 名称加上 **SOONG_CONFIG_** 前缀,用以注册所有的变量名;如下例子:
    
    SOONG_CONFIG_[namespace] := \
        变量名1 \
        变量名2 \
        ...     
    

  • 定义变量名的值

    在变量名前加上前缀 **SOONG_CONFIG_[namespaces]_[变量名]** 用以定义变量的值;如下例子:
    
    SOONG_CONFIG_rtfsc_rtfsc_product := $(TARGET_PRODUCT)
    

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 使用

cc_library_shared {  
    name: "libinputflinger",  
    defaults: [  
        ...
        "rtfsc_inputflinger_defaults"  
    ],

    ...

c代码中使用

ALOGI("PLATFORM_DEVICE_NAME = %s\n", PLATFORM_DEVICE_NAME);

小结

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

评论