go语言控制android.bp选择性编译

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012188065/article/details/86226934

为了降低工作量以及考虑到产品的可维护性,大部分手机厂商采用了同一套android代码对应多个产品,编译时根据配置参数选择性编译不同模块的代码。

1、 Android.mk时代选择性编译

最初android的编译脚本为 Android.mk,采用了Makefile的语言
为了控制编译,我们可以在不同产品的BoardConfig.mk中定义 MARCO
之后在Android.mk中,根据是否使用MARCO来确定编译选项以及编译代码块

ifeq ($(MARCO),true)
    xxxx
endif

2、Android.bp时代选择性编译

随着android逐渐将编译脚本从Android.mk转换成Android.bp,这种方法不再有效,
我们需要采用一种新的方式来选择性编译,此时使用到了go语言。
假如在vendor/privateParser/ 目录下有我们自己的解析器代码,多个版本多个平台均会使用。
在 android 9.0( SDK: 28) 及之后的平台,加载解析器的方式发生了改变,
MediaExtractorFactory会从 手机的 system/lib(64)/extractor/目录下加载.so,
需要将此.so编译到 system/lib/extractors/目录下
之前的平台编译到system/lib/ 目录下

参考google的MPEG4Extractor的代码,需要在 Android.bp中增加如下语句:

	relative_install_path: "extractors",

才能保证编译出的.so 位于system/lib(64)/extractor/目录下

由于我们的代码是共线的,需要保证9.0的平台有此编译选项,之前的平台没有此编译选项
由于不能通过android.bp来区分平台,我们需要增加 go 脚本,来保证此编译选项

2.1、增加go脚本

vendor/privateParser/ 目录下增加go脚本 privateparser.go, 如下:

package privateparser

import (
    "android/soong/android"
    "android/soong/cc"
    "fmt"
)

func privateParserDefaults(ctx android.LoadHookContext) {
    sdkVersion := ctx.AConfig().PlatformSdkVersionInt()
    fmt.Println("sdkVersion:", sdkVersion)
    if sdkVersion >=28 { //after P
        type props struct {
            Shared_libs []string
            Relative_install_path *string
        }
        p := &props{}

        var sharedlib []string
        sharedlib = append(sharedlib, "libmediaextractor")
        p.Shared_libs = sharedlib

        relative_install_path := "extractors"
        p.Relative_install_path = &relative_install_path

        ctx.AppendProperties(p)
    }   
}

func init() {
    android.RegisterModuleType("privateparser_defaults",    privateParserDefaultsFactory)
}

func privateParserDefaultsFactory() android.Module {
    module := cc.DefaultsFactory()
    android.AddLoadHook(module, privateParserDefaults)

    return module
}

2.2、android.bp使用此脚本

android.bp开头位置增加如下语句

privateparser_defaults {
    name: "privateparser_defaults",
}

bootstrap_go_package {
    name: "soong-privateparser",
    pkgPath: "android/soong/external/privateParser",
    deps: [
        "blueprint",
        "blueprint-pathtools",
        "soong",
        "soong-android",
        "soong-cc",
        "soong-genrule",
    ],  
    srcs: [
        "privateparser.go",
    ],  
    pluginFor: ["soong_build"],
}

以上语句可以保证运行android.bp时,先编译对应的 privateparser.go
运行go脚本时,会首先运行init函数,将 privateParserDefaultsFactory 函数注册到module中
之后调用privateParserDefaultsFactory函数时,会将回调函数 privateParserDefaults 注册进去
之后调用 privateParserDefaults 时,我们可以从 ctx.AConfig() 中获取好多属性
(参考 build/soong/android/config.go 中对 build/soong/android/module.go中的 androidBaseContext interface的各种函数实现),其中有一项是获取 sdk版本号,根据版本号,来控制编译选项
之后在 share_libs 中增加 “libmediaextractor”, relative_install_path 中增加 “extractors”
对应 go脚本中的变量名为 Share_libs 和 Relative_install_path

注1: go语言中的变量名,可以在 build/soong/androidmk/cmd/androidmk/android.go 的init函数中查看map表
注2: 必须在确定sdk版本号后才能确定 type props struct,因为不同的版本号会有不同的变量明
如 Relative_install_path 在sdk 27上的类型为 string, 在 sdk 28上的类型为 * string 类型
至此,运行android.bp时,会先去运行go脚本,将一些某些特定的编译选项加载到此so的整体编译选择中
之后运行到 bp 之后的语句,才会去加载其他编译选择,实现了go脚本选择性编译的结果。

3、 深入解析go脚本

3.1 解析 init 函数

运行go语言时,先运行init函数,此函数为

func init() {
    android.RegisterModuleType("privateparser_defaults",    privateParserDefaultsFactory)
}
3.1.1 解析RegisterModuleType函数

脚本开头import了两个包 “android/soong/android” 和 “android/soong/cc”
从 build/soong/ 目录下搜索 “func RegisterModuleType” 来获取RegisterModuleType函数的定义位置
RegisterModuleType函数位于build/soong/android/register.go中,如下:

func RegisterModuleType(name string, factory ModuleFactory) {
        moduleTypes = append(moduleTypes, moduleType{name, ModuleFactoryAdaptor(factory)})
}

可以看出将 name 和 ModuleFactoryAdaptor(factory) append到 var moduleTypes []moduleType 中
moduleType类型如下:

type moduleType struct {
        name    string
        factory blueprint.ModuleFactory
}
3.1.2 查找ModuleFactory类型

register.go 开头 import “github.com/google/blueprint
我们从github上下载 github.com/google/blueprint/ 仓后,搜索 “type ModuleFactory” 来获取 ModuleFactory 定义位置,
位于 github.com/buleprint/context.go中,

// A ModuleFactory function creates a new Module object.  See the
// Context.RegisterModuleType method for details about how a registered
// ModuleFactory is used by a Context.
type ModuleFactory func() (m Module, propertyStructs []interface{})

可以看出ModuleFactory为一函数指针,形参为null,返回类型为 Module, []interface{},

注1: 此处我们详细的讲解了如何搜索变量名和函数名的位置,即关键字 “type xxx"和"func xxx”,之后不再给出详细步骤

3.1.3 解析ModuleFactoryAdaptor函数

搜索如下:

// ModuleFactoryAdapter Wraps a ModuleFactory into a blueprint.ModuleFactory by converting an Module
// into a blueprint.Module and a list of property structs
func ModuleFactoryAdaptor(factory ModuleFactory) blueprint.ModuleFactory {
        return func() (blueprint.Module, []interface{}) {
                module := factory()
                return module, module.GetProperties()
        }
}

将register.go中的 type ModuleFactory func() Module 函数指针,转换成 blueprint.ModuleFactory 类型的函数指针

3.2 解析回调函数 privateParserDefaultsFactory

从上文可以得知,privateParserDefaultsFactory类型为 type ModuleFactory func() Module
我们实现了这个函数为

func privateParserDefaultsFactory() android.Module {
    module := cc.DefaultsFactory()
    android.AddLoadHook(module, privateParserDefaults)

    return module
}
3.2.1 解析 DefaultsFactory()函数

函数实现见 build/soong/cc/cc.go,如下:

func DefaultsFactory(props ...interface{}) android.Module {
        module := &Defaults{}

        module.AddProperties(props...)
        module.AddProperties(
                &BaseProperties{},
                &VendorProperties{},
                &BaseCompilerProperties{},
                &BaseLinkerProperties{},
                &LibraryProperties{},
                &FlagExporterProperties{},
                &BinaryLinkerProperties{},
                &TestProperties{},
                &TestBinaryProperties{},
                &UnusedProperties{},
                &StlProperties{},
                &SanitizeProperties{},
                &StripProperties{},
                &InstallerProperties{},
                &TidyProperties{},
                &CoverageProperties{},
                &SAbiProperties{},
                &VndkProperties{},
                &LTOProperties{},
                &PgoProperties{},
                &android.ProtoProperties{},
        )

        android.InitDefaultsModule(module)

        return module
}

未完待续……

猜你喜欢

转载自blog.csdn.net/u012188065/article/details/86226934
今日推荐