资料:
模块类型:
Artifact Viewer
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{},
<OProperties{},
&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
}
版权声明:本文为songtao542原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。