Androip.bp条件编译

资料:
模块类型:   Artifact Viewer
Makefile中为了实现选择性编译,往往在 BoardConfig.mk 中定义变量,例如:MARCO。之后在 Android.mk 中根据 MARCO 来控制编译。
ifeq ($(MARCO),true) 
    #do something
endif
Android.bp 中实现选择性编译需借助 go 脚本
// 文件: logservice.go
package logservice

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

func init() {
    android.RegisterModuleType("logservice_defaults", logServiceDefaultsFactory)
    android.RegisterModuleType("task_library_shared", logServiceLibraryFactory)
}

func logServiceDefaultsFactory() android.Module { // android.Module 见 build/soong/android/module.go
    module := cc.DefaultsFactory() // DefaultsFactory() 函数实现见 build/soong/cc/cc.go
    android.AddLoadHook(module, logServiceDefaults) // AddLoadHook 函数实现见 build/soong/cc/cc.go
    return module
}

// LoadHookContext 见 build/soong/android/hooks.go
func logServiceDefaults(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, "libeventutils")
        p.Shared_libs = sharedlib
        relative_install_path := "logservice"
        p.Relative_install_path = &relative_install_path
        ctx.AppendProperties(p)
    }   
}

func logServiceLibraryFactory() (android.Module) {
    module := cc.LibrarySharedFactory()  // LibrarySharedFactory() 函数实现见 build/soong/cc/library.go
    android.AddLoadHook(module, logServiceLibrary)
    return module
}

func logServiceLibrary(ctx android.LoadHookContext) {
    sdkVersion := ctx.AConfig().PlatformSdkVersionInt()
    fmt.Println("sdkVersion: ", sdkVersion)
    if sdkVersion >= 28 { //after P
        type props struct {
            Shared_libs []string
        }
        p := &props{}
        var sharedlib []string
        sharedlib = append(sharedlib, "libeventutils")
        p.Shared_libs = sharedlib
        ctx.AppendProperties(p)
    }   
}

// 文件: Android.bpp
bootstrap_go_package {
    name: "soong-logservice",
    pkgPath: "android/soong/logservice",
    deps: [
        "soong-android",
        "soong-cc",
    ],
    srcs: [
        "logservice.go",
    ],
    pluginFor: ["soong_build"],
}

// logservice.go 中通过 RegisterModuleType 函数注册了 task_library_shared, 而且该 module 是通过 cc.LibrarySharedFactory() 方法创建的
// 如果 module 通过 cc.DefaultsFactory() 方法创建,则此处可以写成 cc_library_shared , 并在内部通过 defaults 属性引用 task_library_shared
task_library_shared { 
    name: "libtasks",

    srcs: [
        "Tasks.cpp",
    ],

    shared_libs: [
        "libbinder",
        "libcutils",
        "liblog",
        "libutils",
    ],

    cflags: [
        "-Wall",
        "-Wextra",
    ],

    export_include_dirs: ["include"],
}

logservice_defaults {
    name: "logservice_defaults", // 此处的 name 必须通过上面的 logservice.go 中 RegisterModuleType 函数注册
}

cc_binary {
    defaults: ["logservice_defaults"],

    name: "logservice",

    srcs: ["util.cpp"],

    shared_libs: [
        "libtasks",
        "libbinder",
        "libcutils",
        "liblog",
        "libutils",
    ],

    cflags: [
        "-Wall",
        "-Wextra",
    ],
}

soong源码导读:
// 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{},
        &StlProperties{},
        &SanitizeProperties{},
        &StripProperties{},
        &InstallerProperties{},
        &TidyProperties{},
        &CoverageProperties{},
        &SAbiProperties{},
        &VndkProperties{},
        &LTOProperties{},
        &PgoProperties{},
        &XomProperties{},
        &android.ProtoProperties{},
    )

    android.InitDefaultsModule(module)
    android.InitApexModule(module)

    return module
}

// build/soong/android/hooks.go
func AddLoadHook(m blueprint.Module, hook func(LoadHookContext)) {
    h := &m.(Module).base().hooks // android.Module 见 build/soong/android/module.go
    h.load = append(h.load, hook)
}

// build/soong/android/module.go
type Module interface {
    blueprint.Module // 继承 blueprint.Module

    // GenerateAndroidBuildActions is analogous to Blueprints' GenerateBuildActions,
    // but GenerateAndroidBuildActions also has access to Android-specific information.
    // For more information, see Module.GenerateBuildActions within Blueprint's module_ctx.go
    GenerateAndroidBuildActions(ModuleContext)

    DepsMutator(BottomUpMutatorContext)

    base() *ModuleBase
    Enabled() bool
    Target() Target
    InstallInData() bool
    InstallInSanitizerDir() bool
    InstallInRecovery() bool
    SkipInstall()
    ExportedToMake() bool
    NoticeFile() OptionalPath

    AddProperties(props ...interface{})
    GetProperties() []interface{}

    BuildParamsForTests() []BuildParams
    RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams
    VariablesForTests() map[string]string
}

// build/soong/android/module.go
type ModuleBase struct {
    // Putting the curiously recurring thing pointing to the thing that contains
    // the thing pattern to good use.
    // TODO: remove this
    module Module

    nameProperties          nameProperties
    commonProperties        commonProperties
    variableProperties      variableProperties
    hostAndDeviceProperties hostAndDeviceProperties
    generalProperties       []interface{}
    archProperties          [][]interface{}
    customizableProperties  []interface{}

    noAddressSanitizer bool
    installFiles       Paths
    checkbuildFiles    Paths
    noticeFile         OptionalPath

    // Used by buildTargetSingleton to create checkbuild and per-directory build targets
    // Only set on the final variant of each module
    installTarget    WritablePath
    checkbuildTarget WritablePath
    blueprintDir     string

    hooks hooks

    registerProps []interface{}

    // For tests
    buildParams []BuildParams
    ruleParams  map[blueprint.Rule]blueprint.RuleParams
    variables   map[string]string

    prefer32 func(ctx BaseModuleContext, base *ModuleBase, class OsClass) bool
}

// build/soong/android/hooks.go
type hooks struct {
    load    []func(LoadHookContext)
    arch    []func(ArchHookContext)
    install []func(InstallHookContext)
}

// build/soong/android/hooks.go
// Load hooks are run after the module's properties have been filled from the blueprint file, but
// before the module has been split into architecture variants, and before defaults modules have
// been applied.
type LoadHookContext interface {
    // TODO: a new context that includes Config() but not Target(), etc.?
    BaseContext
    AppendProperties(...interface{})
    PrependProperties(...interface{})
    CreateModule(blueprint.ModuleFactory, ...interface{})
}

// build/soong/android/hooks.go
func (x *hooks) runLoadHooks(ctx LoadHookContext, m *ModuleBase) { 
    if len(x.load) > 0 {
        for _, x := range x.load {
            x(ctx)  // 执行 func(LoadHookContext) 函数,LoadHookContext 是一个 interface,那实际传入的参数类型到底是啥呢??
            if ctx.Failed() {
                return
            }
        }
    }
}

// build/soong/android/hooks.go
func LoadHookMutator(ctx TopDownMutatorContext) {
    if m, ok := ctx.Module().(Module); ok {
        // Cast through *androidTopDownMutatorContext because AppendProperties is implemented
        // on *androidTopDownMutatorContext but not exposed through TopDownMutatorContext
        var loadHookCtx LoadHookContext = ctx.(*androidTopDownMutatorContext) // 强制类型转换成 *androidTopDownMutatorContext
        m.base().hooks.runLoadHooks(loadHookCtx, m.base())
    }
}

//  build/soong/android/mutator.go
type androidTopDownMutatorContext struct {
    blueprint.TopDownMutatorContext  // 继承 blueprint.TopDownMutatorContext
    androidBaseContextImpl  // 继承 androidBaseContextImpl
    walkPath []Module
}

//   先看一下 AppendProperties 函数的实现
// build/soong/android/mutator.go
func (a *androidTopDownMutatorContext) AppendProperties(props ...interface{}) {
    for _, p := range props {
        // customizableProperties 见 build/soong/android/module.go 中 ModuleBase
        err := proptools.AppendMatchingProperties(a.Module().base().customizableProperties, p, nil)
        if err != nil {
            if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
                a.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
            } else {
                panic(err)
            }
        }
    }
}

//  build/blueprint/proptools/extend.go
func AppendMatchingProperties(dst []interface{}, src interface{},
    filter ExtendPropertyFilterFunc) error {
    return extendMatchingProperties(dst, src, filter, orderAppend)
}

// build/blueprint/proptools/extend.go
func extendMatchingProperties(dst []interface{}, src interface{}, filter ExtendPropertyFilterFunc, order ExtendPropertyOrderFunc) error {

    srcValue, err := getStruct(src)
    if err != nil {
        if _, ok := err.(getStructEmptyError); ok {
            return nil
        }
        return err
    }

    dstValues := make([]reflect.Value, len(dst))
    for i := range dst {
        var err error
        dstValues[i], err = getOrCreateStruct(dst[i])
        if err != nil {
            return err
        }
    }
    // extendPropertiesRecursive 函数比较长,见 // build/blueprint/proptools/extend.go
    return extendPropertiesRecursive(dstValues, srcValue, "", filter, false, order)
}


// build/soong/android/module.go
type androidBaseContextImpl struct { // androidBaseContextImpl 实现了 androidBaseContext interface
    target        Target
    multiTargets  []Target
    targetPrimary bool
    debug         bool
    kind          moduleKind
    config        Config
}

// build/soong/android/module.go
type androidBaseContext interface {
    Target() Target
    TargetPrimary() bool
    MultiTargets() []Target
    Arch() Arch
    Os() OsType
    Host() bool
    Device() bool
    Darwin() bool
    Fuchsia() bool
    Windows() bool
    Debug() bool
    PrimaryArch() bool
    Platform() bool
    DeviceSpecific() bool
    SocSpecific() bool
    ProductSpecific() bool
    ProductServicesSpecific() bool
    AConfig() Config
    DeviceConfig() DeviceConfig
}

// build/soong/android/module.go
func (a *androidBaseContextImpl) AConfig() Config {
    return a.config
}

// build/soong/android/config.go
// A Config object represents the entire build configuration for Android.
type Config struct {
    *config
}

// build/soong/android/config.go
type config struct {
    FileConfigurableOptions
    productVariables productVariables

    // Only available on configs created by TestConfig
    TestProductVariables *productVariables

    PrimaryBuilder           string
    ConfigFileName           string
    ProductVariablesFileName string

    Targets              map[OsType][]Target
    BuildOsVariant       string
    BuildOsCommonVariant string

    deviceConfig *deviceConfig

    srcDir   string // the path of the root source directory
    buildDir string // the path of the build output directory

    env       map[string]string
    envLock   sync.Mutex
    envDeps   map[string]string
    envFrozen bool

    inMake bool

    captureBuild      bool // true for tests, saves build parameters for each module
    ignoreEnvironment bool // true for tests, returns empty from all Getenv calls

    targetOpenJDK9 bool // Target 1.9

    stopBefore bootstrap.StopBefore

    OncePer
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

songtao542

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值