Split *ModuleContext out of module.go
Move EarlyModuleContext, BaseModuleContext and ModuleContext out of module.go and into early_module_context, base_module_context and module_context.go respectively. Test: builds Change-Id: I52e6eb1589d1478233c1c55d770b395a16eaa1a3
This commit is contained in:
@@ -37,6 +37,7 @@ bootstrap_go_package {
|
||||
"api_levels.go",
|
||||
"arch.go",
|
||||
"arch_list.go",
|
||||
"base_module_context.go",
|
||||
"bazel.go",
|
||||
"bazel_handler.go",
|
||||
"bazel_paths.go",
|
||||
@@ -51,6 +52,7 @@ bootstrap_go_package {
|
||||
"defs.go",
|
||||
"depset_generic.go",
|
||||
"deptag.go",
|
||||
"early_module_context.go",
|
||||
"expand.go",
|
||||
"filegroup.go",
|
||||
"fixture.go",
|
||||
@@ -65,6 +67,7 @@ bootstrap_go_package {
|
||||
"makevars.go",
|
||||
"metrics.go",
|
||||
"module.go",
|
||||
"module_context.go",
|
||||
"mutator.go",
|
||||
"namespace.go",
|
||||
"neverallow.go",
|
||||
|
656
android/base_module_context.go
Normal file
656
android/base_module_context.go
Normal file
@@ -0,0 +1,656 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package android
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/google/blueprint"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns
|
||||
// a Config instead of an interface{}, and some methods have been wrapped to use an android.Module
|
||||
// instead of a blueprint.Module, plus some extra methods that return Android-specific information
|
||||
// about the current module.
|
||||
type BaseModuleContext interface {
|
||||
EarlyModuleContext
|
||||
|
||||
blueprintBaseModuleContext() blueprint.BaseModuleContext
|
||||
|
||||
// OtherModuleName returns the name of another Module. See BaseModuleContext.ModuleName for more information.
|
||||
// It is intended for use inside the visit functions of Visit* and WalkDeps.
|
||||
OtherModuleName(m blueprint.Module) string
|
||||
|
||||
// OtherModuleDir returns the directory of another Module. See BaseModuleContext.ModuleDir for more information.
|
||||
// It is intended for use inside the visit functions of Visit* and WalkDeps.
|
||||
OtherModuleDir(m blueprint.Module) string
|
||||
|
||||
// OtherModuleErrorf reports an error on another Module. See BaseModuleContext.ModuleErrorf for more information.
|
||||
// It is intended for use inside the visit functions of Visit* and WalkDeps.
|
||||
OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
|
||||
|
||||
// OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency
|
||||
// on the module. When called inside a Visit* method with current module being visited, and there are multiple
|
||||
// dependencies on the module being visited, it returns the dependency tag used for the current dependency.
|
||||
OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
|
||||
|
||||
// OtherModuleExists returns true if a module with the specified name exists, as determined by the NameInterface
|
||||
// passed to Context.SetNameInterface, or SimpleNameInterface if it was not called.
|
||||
OtherModuleExists(name string) bool
|
||||
|
||||
// OtherModuleDependencyVariantExists returns true if a module with the
|
||||
// specified name and variant exists. The variant must match the given
|
||||
// variations. It must also match all the non-local variations of the current
|
||||
// module. In other words, it checks for the module that AddVariationDependencies
|
||||
// would add a dependency on with the same arguments.
|
||||
OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool
|
||||
|
||||
// OtherModuleFarDependencyVariantExists returns true if a module with the
|
||||
// specified name and variant exists. The variant must match the given
|
||||
// variations, but not the non-local variations of the current module. In
|
||||
// other words, it checks for the module that AddFarVariationDependencies
|
||||
// would add a dependency on with the same arguments.
|
||||
OtherModuleFarDependencyVariantExists(variations []blueprint.Variation, name string) bool
|
||||
|
||||
// OtherModuleReverseDependencyVariantExists returns true if a module with the
|
||||
// specified name exists with the same variations as the current module. In
|
||||
// other words, it checks for the module that AddReverseDependency would add a
|
||||
// dependency on with the same argument.
|
||||
OtherModuleReverseDependencyVariantExists(name string) bool
|
||||
|
||||
// OtherModuleType returns the type of another Module. See BaseModuleContext.ModuleType for more information.
|
||||
// It is intended for use inside the visit functions of Visit* and WalkDeps.
|
||||
OtherModuleType(m blueprint.Module) string
|
||||
|
||||
// OtherModuleProvider returns the value for a provider for the given module. If the value is
|
||||
// not set it returns the zero value of the type of the provider, so the return value can always
|
||||
// be type asserted to the type of the provider. The value returned may be a deep copy of the
|
||||
// value originally passed to SetProvider.
|
||||
OtherModuleProvider(m blueprint.Module, provider blueprint.ProviderKey) interface{}
|
||||
|
||||
// OtherModuleHasProvider returns true if the provider for the given module has been set.
|
||||
OtherModuleHasProvider(m blueprint.Module, provider blueprint.ProviderKey) bool
|
||||
|
||||
// Provider returns the value for a provider for the current module. If the value is
|
||||
// not set it returns the zero value of the type of the provider, so the return value can always
|
||||
// be type asserted to the type of the provider. It panics if called before the appropriate
|
||||
// mutator or GenerateBuildActions pass for the provider. The value returned may be a deep
|
||||
// copy of the value originally passed to SetProvider.
|
||||
Provider(provider blueprint.ProviderKey) interface{}
|
||||
|
||||
// HasProvider returns true if the provider for the current module has been set.
|
||||
HasProvider(provider blueprint.ProviderKey) bool
|
||||
|
||||
// SetProvider sets the value for a provider for the current module. It panics if not called
|
||||
// during the appropriate mutator or GenerateBuildActions pass for the provider, if the value
|
||||
// is not of the appropriate type, or if the value has already been set. The value should not
|
||||
// be modified after being passed to SetProvider.
|
||||
SetProvider(provider blueprint.ProviderKey, value interface{})
|
||||
|
||||
GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module
|
||||
|
||||
// GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if
|
||||
// none exists. It panics if the dependency does not have the specified tag. It skips any
|
||||
// dependencies that are not an android.Module.
|
||||
GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module
|
||||
|
||||
// GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified
|
||||
// name, or nil if none exists. If there are multiple dependencies on the same module it returns
|
||||
// the first DependencyTag.
|
||||
GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
|
||||
|
||||
ModuleFromName(name string) (blueprint.Module, bool)
|
||||
|
||||
// VisitDirectDepsBlueprint calls visit for each direct dependency. If there are multiple
|
||||
// direct dependencies on the same module visit will be called multiple times on that module
|
||||
// and OtherModuleDependencyTag will return a different tag for each.
|
||||
//
|
||||
// The Module passed to the visit function should not be retained outside of the visit
|
||||
// function, it may be invalidated by future mutators.
|
||||
VisitDirectDepsBlueprint(visit func(blueprint.Module))
|
||||
|
||||
// VisitDirectDeps calls visit for each direct dependency. If there are multiple
|
||||
// direct dependencies on the same module visit will be called multiple times on that module
|
||||
// and OtherModuleDependencyTag will return a different tag for each. It raises an error if any of the
|
||||
// dependencies are not an android.Module.
|
||||
//
|
||||
// The Module passed to the visit function should not be retained outside of the visit
|
||||
// function, it may be invalidated by future mutators.
|
||||
VisitDirectDeps(visit func(Module))
|
||||
|
||||
VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module))
|
||||
|
||||
// VisitDirectDepsIf calls pred for each direct dependency, and if pred returns true calls visit. If there are
|
||||
// multiple direct dependencies on the same module pred and visit will be called multiple times on that module and
|
||||
// OtherModuleDependencyTag will return a different tag for each. It skips any
|
||||
// dependencies that are not an android.Module.
|
||||
//
|
||||
// The Module passed to the visit function should not be retained outside of the visit function, it may be
|
||||
// invalidated by future mutators.
|
||||
VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
|
||||
// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
|
||||
VisitDepsDepthFirst(visit func(Module))
|
||||
// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
|
||||
VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
|
||||
|
||||
// WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order. visit may
|
||||
// be called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the
|
||||
// child and parent with different tags. OtherModuleDependencyTag will return the tag for the currently visited
|
||||
// (child, parent) pair. If visit returns false WalkDeps will not continue recursing down to child. It skips
|
||||
// any dependencies that are not an android.Module.
|
||||
//
|
||||
// The Modules passed to the visit function should not be retained outside of the visit function, they may be
|
||||
// invalidated by future mutators.
|
||||
WalkDeps(visit func(child, parent Module) bool)
|
||||
|
||||
// WalkDepsBlueprint calls visit for each transitive dependency, traversing the dependency
|
||||
// tree in top down order. visit may be called multiple times for the same (child, parent)
|
||||
// pair if there are multiple direct dependencies between the child and parent with different
|
||||
// tags. OtherModuleDependencyTag will return the tag for the currently visited
|
||||
// (child, parent) pair. If visit returns false WalkDeps will not continue recursing down
|
||||
// to child.
|
||||
//
|
||||
// The Modules passed to the visit function should not be retained outside of the visit function, they may be
|
||||
// invalidated by future mutators.
|
||||
WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool)
|
||||
|
||||
// GetWalkPath is supposed to be called in visit function passed in WalkDeps()
|
||||
// and returns a top-down dependency path from a start module to current child module.
|
||||
GetWalkPath() []Module
|
||||
|
||||
// PrimaryModule returns the first variant of the current module. Variants of a module are always visited in
|
||||
// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the
|
||||
// Module returned by PrimaryModule without data races. This can be used to perform singleton actions that are
|
||||
// only done once for all variants of a module.
|
||||
PrimaryModule() Module
|
||||
|
||||
// FinalModule returns the last variant of the current module. Variants of a module are always visited in
|
||||
// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all
|
||||
// variants using VisitAllModuleVariants if the current module == FinalModule(). This can be used to perform
|
||||
// singleton actions that are only done once for all variants of a module.
|
||||
FinalModule() Module
|
||||
|
||||
// VisitAllModuleVariants calls visit for each variant of the current module. Variants of a module are always
|
||||
// visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read
|
||||
// from all variants if the current module == FinalModule(). Otherwise, care must be taken to not access any
|
||||
// data modified by the current mutator.
|
||||
VisitAllModuleVariants(visit func(Module))
|
||||
|
||||
// GetTagPath is supposed to be called in visit function passed in WalkDeps()
|
||||
// and returns a top-down dependency tags path from a start module to current child module.
|
||||
// It has one less entry than GetWalkPath() as it contains the dependency tags that
|
||||
// exist between each adjacent pair of modules in the GetWalkPath().
|
||||
// GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1]
|
||||
GetTagPath() []blueprint.DependencyTag
|
||||
|
||||
// GetPathString is supposed to be called in visit function passed in WalkDeps()
|
||||
// and returns a multi-line string showing the modules and dependency tags
|
||||
// among them along the top-down dependency path from a start module to current child module.
|
||||
// skipFirst when set to true, the output doesn't include the start module,
|
||||
// which is already printed when this function is used along with ModuleErrorf().
|
||||
GetPathString(skipFirst bool) string
|
||||
|
||||
AddMissingDependencies(missingDeps []string)
|
||||
|
||||
// getMissingDependencies returns the list of missing dependencies.
|
||||
// Calling this function prevents adding new dependencies.
|
||||
getMissingDependencies() []string
|
||||
|
||||
// AddUnconvertedBp2buildDep stores module name of a direct dependency that was not converted via bp2build
|
||||
AddUnconvertedBp2buildDep(dep string)
|
||||
|
||||
// AddMissingBp2buildDep stores the module name of a direct dependency that was not found.
|
||||
AddMissingBp2buildDep(dep string)
|
||||
|
||||
Target() Target
|
||||
TargetPrimary() bool
|
||||
|
||||
// The additional arch specific targets (e.g. 32/64 bit) that this module variant is
|
||||
// responsible for creating.
|
||||
MultiTargets() []Target
|
||||
Arch() Arch
|
||||
Os() OsType
|
||||
Host() bool
|
||||
Device() bool
|
||||
Darwin() bool
|
||||
Windows() bool
|
||||
PrimaryArch() bool
|
||||
}
|
||||
|
||||
type baseModuleContext struct {
|
||||
bp blueprint.BaseModuleContext
|
||||
earlyModuleContext
|
||||
os OsType
|
||||
target Target
|
||||
multiTargets []Target
|
||||
targetPrimary bool
|
||||
|
||||
walkPath []Module
|
||||
tagPath []blueprint.DependencyTag
|
||||
|
||||
strictVisitDeps bool // If true, enforce that all dependencies are enabled
|
||||
|
||||
bazelConversionMode bool
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) isBazelConversionMode() bool {
|
||||
return b.bazelConversionMode
|
||||
}
|
||||
func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string {
|
||||
return b.bp.OtherModuleName(m)
|
||||
}
|
||||
func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string { return b.bp.OtherModuleDir(m) }
|
||||
func (b *baseModuleContext) OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) {
|
||||
b.bp.OtherModuleErrorf(m, fmt, args...)
|
||||
}
|
||||
func (b *baseModuleContext) OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag {
|
||||
return b.bp.OtherModuleDependencyTag(m)
|
||||
}
|
||||
func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) }
|
||||
func (b *baseModuleContext) OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool {
|
||||
return b.bp.OtherModuleDependencyVariantExists(variations, name)
|
||||
}
|
||||
func (b *baseModuleContext) OtherModuleFarDependencyVariantExists(variations []blueprint.Variation, name string) bool {
|
||||
return b.bp.OtherModuleFarDependencyVariantExists(variations, name)
|
||||
}
|
||||
func (b *baseModuleContext) OtherModuleReverseDependencyVariantExists(name string) bool {
|
||||
return b.bp.OtherModuleReverseDependencyVariantExists(name)
|
||||
}
|
||||
func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string {
|
||||
return b.bp.OtherModuleType(m)
|
||||
}
|
||||
func (b *baseModuleContext) OtherModuleProvider(m blueprint.Module, provider blueprint.ProviderKey) interface{} {
|
||||
return b.bp.OtherModuleProvider(m, provider)
|
||||
}
|
||||
func (b *baseModuleContext) OtherModuleHasProvider(m blueprint.Module, provider blueprint.ProviderKey) bool {
|
||||
return b.bp.OtherModuleHasProvider(m, provider)
|
||||
}
|
||||
func (b *baseModuleContext) Provider(provider blueprint.ProviderKey) interface{} {
|
||||
return b.bp.Provider(provider)
|
||||
}
|
||||
func (b *baseModuleContext) HasProvider(provider blueprint.ProviderKey) bool {
|
||||
return b.bp.HasProvider(provider)
|
||||
}
|
||||
func (b *baseModuleContext) SetProvider(provider blueprint.ProviderKey, value interface{}) {
|
||||
b.bp.SetProvider(provider, value)
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
|
||||
return b.bp.GetDirectDepWithTag(name, tag)
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) blueprintBaseModuleContext() blueprint.BaseModuleContext {
|
||||
return b.bp
|
||||
}
|
||||
|
||||
// AddUnconvertedBp2buildDep stores module name of a dependency that was not converted to Bazel.
|
||||
func (b *baseModuleContext) AddUnconvertedBp2buildDep(dep string) {
|
||||
unconvertedDeps := &b.Module().base().commonProperties.BazelConversionStatus.UnconvertedDeps
|
||||
*unconvertedDeps = append(*unconvertedDeps, dep)
|
||||
}
|
||||
|
||||
// AddMissingBp2buildDep stores module name of a dependency that was not found in a Android.bp file.
|
||||
func (b *baseModuleContext) AddMissingBp2buildDep(dep string) {
|
||||
missingDeps := &b.Module().base().commonProperties.BazelConversionStatus.MissingDeps
|
||||
*missingDeps = append(*missingDeps, dep)
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) AddMissingDependencies(deps []string) {
|
||||
if deps != nil {
|
||||
missingDeps := &b.Module().base().commonProperties.MissingDeps
|
||||
*missingDeps = append(*missingDeps, deps...)
|
||||
*missingDeps = FirstUniqueStrings(*missingDeps)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) checkedMissingDeps() bool {
|
||||
return b.Module().base().commonProperties.CheckedMissingDeps
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) getMissingDependencies() []string {
|
||||
checked := &b.Module().base().commonProperties.CheckedMissingDeps
|
||||
*checked = true
|
||||
var missingDeps []string
|
||||
missingDeps = append(missingDeps, b.Module().base().commonProperties.MissingDeps...)
|
||||
missingDeps = append(missingDeps, b.bp.EarlyGetMissingDependencies()...)
|
||||
missingDeps = FirstUniqueStrings(missingDeps)
|
||||
return missingDeps
|
||||
}
|
||||
|
||||
type AllowDisabledModuleDependency interface {
|
||||
blueprint.DependencyTag
|
||||
AllowDisabledModuleDependency(target Module) bool
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool) Module {
|
||||
aModule, _ := module.(Module)
|
||||
|
||||
if !strict {
|
||||
return aModule
|
||||
}
|
||||
|
||||
if aModule == nil {
|
||||
b.ModuleErrorf("module %q (%#v) not an android module", b.OtherModuleName(module), tag)
|
||||
return nil
|
||||
}
|
||||
|
||||
if !aModule.Enabled() {
|
||||
if t, ok := tag.(AllowDisabledModuleDependency); !ok || !t.AllowDisabledModuleDependency(aModule) {
|
||||
if b.Config().AllowMissingDependencies() {
|
||||
b.AddMissingDependencies([]string{b.OtherModuleName(aModule)})
|
||||
} else {
|
||||
b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return aModule
|
||||
}
|
||||
|
||||
type dep struct {
|
||||
mod blueprint.Module
|
||||
tag blueprint.DependencyTag
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) getDirectDepsInternal(name string, tag blueprint.DependencyTag) []dep {
|
||||
var deps []dep
|
||||
b.VisitDirectDepsBlueprint(func(module blueprint.Module) {
|
||||
if aModule, _ := module.(Module); aModule != nil {
|
||||
if aModule.base().BaseModuleName() == name {
|
||||
returnedTag := b.bp.OtherModuleDependencyTag(aModule)
|
||||
if tag == nil || returnedTag == tag {
|
||||
deps = append(deps, dep{aModule, returnedTag})
|
||||
}
|
||||
}
|
||||
} else if b.bp.OtherModuleName(module) == name {
|
||||
returnedTag := b.bp.OtherModuleDependencyTag(module)
|
||||
if tag == nil || returnedTag == tag {
|
||||
deps = append(deps, dep{module, returnedTag})
|
||||
}
|
||||
}
|
||||
})
|
||||
return deps
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) getDirectDepInternal(name string, tag blueprint.DependencyTag) (blueprint.Module, blueprint.DependencyTag) {
|
||||
deps := b.getDirectDepsInternal(name, tag)
|
||||
if len(deps) == 1 {
|
||||
return deps[0].mod, deps[0].tag
|
||||
} else if len(deps) >= 2 {
|
||||
panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
|
||||
name, b.ModuleName()))
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) getDirectDepFirstTag(name string) (blueprint.Module, blueprint.DependencyTag) {
|
||||
foundDeps := b.getDirectDepsInternal(name, nil)
|
||||
deps := map[blueprint.Module]bool{}
|
||||
for _, dep := range foundDeps {
|
||||
deps[dep.mod] = true
|
||||
}
|
||||
if len(deps) == 1 {
|
||||
return foundDeps[0].mod, foundDeps[0].tag
|
||||
} else if len(deps) >= 2 {
|
||||
// this could happen if two dependencies have the same name in different namespaces
|
||||
// TODO(b/186554727): this should not occur if namespaces are handled within
|
||||
// getDirectDepsInternal.
|
||||
panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
|
||||
name, b.ModuleName()))
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module {
|
||||
var deps []Module
|
||||
b.VisitDirectDepsBlueprint(func(module blueprint.Module) {
|
||||
if aModule, _ := module.(Module); aModule != nil {
|
||||
if b.bp.OtherModuleDependencyTag(aModule) == tag {
|
||||
deps = append(deps, aModule)
|
||||
}
|
||||
}
|
||||
})
|
||||
return deps
|
||||
}
|
||||
|
||||
// GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified
|
||||
// name, or nil if none exists. If there are multiple dependencies on the same module it returns the
|
||||
// first DependencyTag.
|
||||
func (b *baseModuleContext) GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) {
|
||||
return b.getDirectDepFirstTag(name)
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) ModuleFromName(name string) (blueprint.Module, bool) {
|
||||
if !b.isBazelConversionMode() {
|
||||
panic("cannot call ModuleFromName if not in bazel conversion mode")
|
||||
}
|
||||
var m blueprint.Module
|
||||
var ok bool
|
||||
if moduleName, _ := SrcIsModuleWithTag(name); moduleName != "" {
|
||||
m, ok = b.bp.ModuleFromName(moduleName)
|
||||
} else {
|
||||
m, ok = b.bp.ModuleFromName(name)
|
||||
}
|
||||
if !ok {
|
||||
return m, ok
|
||||
}
|
||||
// If this module is not preferred, tried to get the prebuilt version instead
|
||||
if a, aOk := m.(Module); aOk && !IsModulePrebuilt(a) && !IsModulePreferred(a) {
|
||||
return b.ModuleFromName("prebuilt_" + name)
|
||||
}
|
||||
return m, ok
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module)) {
|
||||
b.bp.VisitDirectDeps(visit)
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) {
|
||||
b.bp.VisitDirectDeps(func(module blueprint.Module) {
|
||||
if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
|
||||
visit(aModule)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) {
|
||||
b.bp.VisitDirectDeps(func(module blueprint.Module) {
|
||||
if b.bp.OtherModuleDependencyTag(module) == tag {
|
||||
if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
|
||||
visit(aModule)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
|
||||
b.bp.VisitDirectDepsIf(
|
||||
// pred
|
||||
func(module blueprint.Module) bool {
|
||||
if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
|
||||
return pred(aModule)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
// visit
|
||||
func(module blueprint.Module) {
|
||||
visit(module.(Module))
|
||||
})
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
|
||||
b.bp.VisitDepsDepthFirst(func(module blueprint.Module) {
|
||||
if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
|
||||
visit(aModule)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) {
|
||||
b.bp.VisitDepsDepthFirstIf(
|
||||
// pred
|
||||
func(module blueprint.Module) bool {
|
||||
if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
|
||||
return pred(aModule)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
// visit
|
||||
func(module blueprint.Module) {
|
||||
visit(module.(Module))
|
||||
})
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) {
|
||||
b.bp.WalkDeps(visit)
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) {
|
||||
b.walkPath = []Module{b.Module()}
|
||||
b.tagPath = []blueprint.DependencyTag{}
|
||||
b.bp.WalkDeps(func(child, parent blueprint.Module) bool {
|
||||
childAndroidModule, _ := child.(Module)
|
||||
parentAndroidModule, _ := parent.(Module)
|
||||
if childAndroidModule != nil && parentAndroidModule != nil {
|
||||
// record walkPath before visit
|
||||
for b.walkPath[len(b.walkPath)-1] != parentAndroidModule {
|
||||
b.walkPath = b.walkPath[0 : len(b.walkPath)-1]
|
||||
b.tagPath = b.tagPath[0 : len(b.tagPath)-1]
|
||||
}
|
||||
b.walkPath = append(b.walkPath, childAndroidModule)
|
||||
b.tagPath = append(b.tagPath, b.OtherModuleDependencyTag(childAndroidModule))
|
||||
return visit(childAndroidModule, parentAndroidModule)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) GetWalkPath() []Module {
|
||||
return b.walkPath
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag {
|
||||
return b.tagPath
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) VisitAllModuleVariants(visit func(Module)) {
|
||||
b.bp.VisitAllModuleVariants(func(module blueprint.Module) {
|
||||
visit(module.(Module))
|
||||
})
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) PrimaryModule() Module {
|
||||
return b.bp.PrimaryModule().(Module)
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) FinalModule() Module {
|
||||
return b.bp.FinalModule().(Module)
|
||||
}
|
||||
|
||||
// IsMetaDependencyTag returns true for cross-cutting metadata dependencies.
|
||||
func IsMetaDependencyTag(tag blueprint.DependencyTag) bool {
|
||||
if tag == licenseKindTag {
|
||||
return true
|
||||
} else if tag == licensesTag {
|
||||
return true
|
||||
} else if tag == acDepTag {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// A regexp for removing boilerplate from BaseDependencyTag from the string representation of
|
||||
// a dependency tag.
|
||||
var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:{}\E(, )?`)
|
||||
|
||||
// PrettyPrintTag returns string representation of the tag, but prefers
|
||||
// custom String() method if available.
|
||||
func PrettyPrintTag(tag blueprint.DependencyTag) string {
|
||||
// Use tag's custom String() method if available.
|
||||
if stringer, ok := tag.(fmt.Stringer); ok {
|
||||
return stringer.String()
|
||||
}
|
||||
|
||||
// Otherwise, get a default string representation of the tag's struct.
|
||||
tagString := fmt.Sprintf("%T: %+v", tag, tag)
|
||||
|
||||
// Remove the boilerplate from BaseDependencyTag as it adds no value.
|
||||
tagString = tagCleaner.ReplaceAllString(tagString, "")
|
||||
return tagString
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) GetPathString(skipFirst bool) string {
|
||||
sb := strings.Builder{}
|
||||
tagPath := b.GetTagPath()
|
||||
walkPath := b.GetWalkPath()
|
||||
if !skipFirst {
|
||||
sb.WriteString(walkPath[0].String())
|
||||
}
|
||||
for i, m := range walkPath[1:] {
|
||||
sb.WriteString("\n")
|
||||
sb.WriteString(fmt.Sprintf(" via tag %s\n", PrettyPrintTag(tagPath[i])))
|
||||
sb.WriteString(fmt.Sprintf(" -> %s", m.String()))
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) Target() Target {
|
||||
return b.target
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) TargetPrimary() bool {
|
||||
return b.targetPrimary
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) MultiTargets() []Target {
|
||||
return b.multiTargets
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) Arch() Arch {
|
||||
return b.target.Arch
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) Os() OsType {
|
||||
return b.os
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) Host() bool {
|
||||
return b.os.Class == Host
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) Device() bool {
|
||||
return b.os.Class == Device
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) Darwin() bool {
|
||||
return b.os == Darwin
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) Windows() bool {
|
||||
return b.os == Windows
|
||||
}
|
||||
|
||||
func (b *baseModuleContext) PrimaryArch() bool {
|
||||
if len(b.config.Targets[b.target.Os]) <= 1 {
|
||||
return true
|
||||
}
|
||||
return b.target.Arch.ArchType == b.config.Targets[b.target.Os][0].Arch.ArchType
|
||||
}
|
169
android/early_module_context.go
Normal file
169
android/early_module_context.go
Normal file
@@ -0,0 +1,169 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package android
|
||||
|
||||
import (
|
||||
"github.com/google/blueprint"
|
||||
"os"
|
||||
"text/scanner"
|
||||
)
|
||||
|
||||
// EarlyModuleContext provides methods that can be called early, as soon as the properties have
|
||||
// been parsed into the module and before any mutators have run.
|
||||
type EarlyModuleContext interface {
|
||||
// Module returns the current module as a Module. It should rarely be necessary, as the module already has a
|
||||
// reference to itself.
|
||||
Module() Module
|
||||
|
||||
// ModuleName returns the name of the module. This is generally the value that was returned by Module.Name() when
|
||||
// the module was created, but may have been modified by calls to BaseMutatorContext.Rename.
|
||||
ModuleName() string
|
||||
|
||||
// ModuleDir returns the path to the directory that contains the definition of the module.
|
||||
ModuleDir() string
|
||||
|
||||
// ModuleType returns the name of the module type that was used to create the module, as specified in
|
||||
// RegisterModuleType.
|
||||
ModuleType() string
|
||||
|
||||
// BlueprintFile returns the name of the blueprint file that contains the definition of this
|
||||
// module.
|
||||
BlueprintsFile() string
|
||||
|
||||
// ContainsProperty returns true if the specified property name was set in the module definition.
|
||||
ContainsProperty(name string) bool
|
||||
|
||||
// Errorf reports an error at the specified position of the module definition file.
|
||||
Errorf(pos scanner.Position, fmt string, args ...interface{})
|
||||
|
||||
// ModuleErrorf reports an error at the line number of the module type in the module definition.
|
||||
ModuleErrorf(fmt string, args ...interface{})
|
||||
|
||||
// PropertyErrorf reports an error at the line number of a property in the module definition.
|
||||
PropertyErrorf(property, fmt string, args ...interface{})
|
||||
|
||||
// Failed returns true if any errors have been reported. In most cases the module can continue with generating
|
||||
// build rules after an error, allowing it to report additional errors in a single run, but in cases where the error
|
||||
// has prevented the module from creating necessary data it can return early when Failed returns true.
|
||||
Failed() bool
|
||||
|
||||
// AddNinjaFileDeps adds dependencies on the specified files to the rule that creates the ninja manifest. The
|
||||
// primary builder will be rerun whenever the specified files are modified.
|
||||
AddNinjaFileDeps(deps ...string)
|
||||
|
||||
DeviceSpecific() bool
|
||||
SocSpecific() bool
|
||||
ProductSpecific() bool
|
||||
SystemExtSpecific() bool
|
||||
Platform() bool
|
||||
|
||||
Config() Config
|
||||
DeviceConfig() DeviceConfig
|
||||
|
||||
// Deprecated: use Config()
|
||||
AConfig() Config
|
||||
|
||||
// GlobWithDeps returns a list of files that match the specified pattern but do not match any
|
||||
// of the patterns in excludes. It also adds efficient dependencies to rerun the primary
|
||||
// builder whenever a file matching the pattern as added or removed, without rerunning if a
|
||||
// file that does not match the pattern is added to a searched directory.
|
||||
GlobWithDeps(pattern string, excludes []string) ([]string, error)
|
||||
|
||||
Glob(globPattern string, excludes []string) Paths
|
||||
GlobFiles(globPattern string, excludes []string) Paths
|
||||
IsSymlink(path Path) bool
|
||||
Readlink(path Path) string
|
||||
|
||||
// Namespace returns the Namespace object provided by the NameInterface set by Context.SetNameInterface, or the
|
||||
// default SimpleNameInterface if Context.SetNameInterface was not called.
|
||||
Namespace() *Namespace
|
||||
}
|
||||
|
||||
// Deprecated: use EarlyModuleContext instead
|
||||
type BaseContext interface {
|
||||
EarlyModuleContext
|
||||
}
|
||||
|
||||
type earlyModuleContext struct {
|
||||
blueprint.EarlyModuleContext
|
||||
|
||||
kind moduleKind
|
||||
config Config
|
||||
}
|
||||
|
||||
func (e *earlyModuleContext) Glob(globPattern string, excludes []string) Paths {
|
||||
return Glob(e, globPattern, excludes)
|
||||
}
|
||||
|
||||
func (e *earlyModuleContext) GlobFiles(globPattern string, excludes []string) Paths {
|
||||
return GlobFiles(e, globPattern, excludes)
|
||||
}
|
||||
|
||||
func (e *earlyModuleContext) IsSymlink(path Path) bool {
|
||||
fileInfo, err := e.config.fs.Lstat(path.String())
|
||||
if err != nil {
|
||||
e.ModuleErrorf("os.Lstat(%q) failed: %s", path.String(), err)
|
||||
}
|
||||
return fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink
|
||||
}
|
||||
|
||||
func (e *earlyModuleContext) Readlink(path Path) string {
|
||||
dest, err := e.config.fs.Readlink(path.String())
|
||||
if err != nil {
|
||||
e.ModuleErrorf("os.Readlink(%q) failed: %s", path.String(), err)
|
||||
}
|
||||
return dest
|
||||
}
|
||||
|
||||
func (e *earlyModuleContext) Module() Module {
|
||||
module, _ := e.EarlyModuleContext.Module().(Module)
|
||||
return module
|
||||
}
|
||||
|
||||
func (e *earlyModuleContext) Config() Config {
|
||||
return e.EarlyModuleContext.Config().(Config)
|
||||
}
|
||||
|
||||
func (e *earlyModuleContext) AConfig() Config {
|
||||
return e.config
|
||||
}
|
||||
|
||||
func (e *earlyModuleContext) DeviceConfig() DeviceConfig {
|
||||
return DeviceConfig{e.config.deviceConfig}
|
||||
}
|
||||
|
||||
func (e *earlyModuleContext) Platform() bool {
|
||||
return e.kind == platformModule
|
||||
}
|
||||
|
||||
func (e *earlyModuleContext) DeviceSpecific() bool {
|
||||
return e.kind == deviceSpecificModule
|
||||
}
|
||||
|
||||
func (e *earlyModuleContext) SocSpecific() bool {
|
||||
return e.kind == socSpecificModule
|
||||
}
|
||||
|
||||
func (e *earlyModuleContext) ProductSpecific() bool {
|
||||
return e.kind == productSpecificModule
|
||||
}
|
||||
|
||||
func (e *earlyModuleContext) SystemExtSpecific() bool {
|
||||
return e.kind == systemExtSpecificModule
|
||||
}
|
||||
|
||||
func (e *earlyModuleContext) Namespace() *Namespace {
|
||||
return e.EarlyModuleContext.Namespace().(*Namespace)
|
||||
}
|
1465
android/module.go
1465
android/module.go
File diff suppressed because it is too large
Load Diff
698
android/module_context.go
Normal file
698
android/module_context.go
Normal file
@@ -0,0 +1,698 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package android
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/google/blueprint"
|
||||
"github.com/google/blueprint/proptools"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// BuildParameters describes the set of potential parameters to build a Ninja rule.
|
||||
// In general, these correspond to a Ninja concept.
|
||||
type BuildParams struct {
|
||||
// A Ninja Rule that will be written to the Ninja file. This allows factoring out common code
|
||||
// among multiple modules to reduce repetition in the Ninja file of action requirements. A rule
|
||||
// can contain variables that should be provided in Args.
|
||||
Rule blueprint.Rule
|
||||
// Deps represents the depfile format. When using RuleBuilder, this defaults to GCC when depfiles
|
||||
// are used.
|
||||
Deps blueprint.Deps
|
||||
// Depfile is a writeable path that allows correct incremental builds when the inputs have not
|
||||
// been fully specified by the Ninja rule. Ninja supports a subset of the Makefile depfile syntax.
|
||||
Depfile WritablePath
|
||||
// A description of the build action.
|
||||
Description string
|
||||
// Output is an output file of the action. When using this field, references to $out in the Ninja
|
||||
// command will refer to this file.
|
||||
Output WritablePath
|
||||
// Outputs is a slice of output file of the action. When using this field, references to $out in
|
||||
// the Ninja command will refer to these files.
|
||||
Outputs WritablePaths
|
||||
// SymlinkOutput is an output file specifically that is a symlink.
|
||||
SymlinkOutput WritablePath
|
||||
// SymlinkOutputs is a slice of output files specifically that is a symlink.
|
||||
SymlinkOutputs WritablePaths
|
||||
// ImplicitOutput is an output file generated by the action. Note: references to `$out` in the
|
||||
// Ninja command will NOT include references to this file.
|
||||
ImplicitOutput WritablePath
|
||||
// ImplicitOutputs is a slice of output files generated by the action. Note: references to `$out`
|
||||
// in the Ninja command will NOT include references to these files.
|
||||
ImplicitOutputs WritablePaths
|
||||
// Input is an input file to the Ninja action. When using this field, references to $in in the
|
||||
// Ninja command will refer to this file.
|
||||
Input Path
|
||||
// Inputs is a slice of input files to the Ninja action. When using this field, references to $in
|
||||
// in the Ninja command will refer to these files.
|
||||
Inputs Paths
|
||||
// Implicit is an input file to the Ninja action. Note: references to `$in` in the Ninja command
|
||||
// will NOT include references to this file.
|
||||
Implicit Path
|
||||
// Implicits is a slice of input files to the Ninja action. Note: references to `$in` in the Ninja
|
||||
// command will NOT include references to these files.
|
||||
Implicits Paths
|
||||
// OrderOnly are Ninja order-only inputs to the action. When these are out of date, the output is
|
||||
// not rebuilt until they are built, but changes in order-only dependencies alone do not cause the
|
||||
// output to be rebuilt.
|
||||
OrderOnly Paths
|
||||
// Validation is an output path for a validation action. Validation outputs imply lower
|
||||
// non-blocking priority to building non-validation outputs.
|
||||
Validation Path
|
||||
// Validations is a slice of output path for a validation action. Validation outputs imply lower
|
||||
// non-blocking priority to building non-validation outputs.
|
||||
Validations Paths
|
||||
// Whether to skip outputting a default target statement which will be built by Ninja when no
|
||||
// targets are specified on Ninja's command line.
|
||||
Default bool
|
||||
// Args is a key value mapping for replacements of variables within the Rule
|
||||
Args map[string]string
|
||||
}
|
||||
|
||||
type ModuleBuildParams BuildParams
|
||||
|
||||
type ModuleContext interface {
|
||||
BaseModuleContext
|
||||
|
||||
blueprintModuleContext() blueprint.ModuleContext
|
||||
|
||||
// Deprecated: use ModuleContext.Build instead.
|
||||
ModuleBuild(pctx PackageContext, params ModuleBuildParams)
|
||||
|
||||
// Returns a list of paths expanded from globs and modules referenced using ":module" syntax. The property must
|
||||
// be tagged with `android:"path" to support automatic source module dependency resolution.
|
||||
//
|
||||
// Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead.
|
||||
ExpandSources(srcFiles, excludes []string) Paths
|
||||
|
||||
// Returns a single path expanded from globs and modules referenced using ":module" syntax. The property must
|
||||
// be tagged with `android:"path" to support automatic source module dependency resolution.
|
||||
//
|
||||
// Deprecated: use PathForModuleSrc instead.
|
||||
ExpandSource(srcFile, prop string) Path
|
||||
|
||||
ExpandOptionalSource(srcFile *string, prop string) OptionalPath
|
||||
|
||||
// InstallExecutable creates a rule to copy srcPath to name in the installPath directory,
|
||||
// with the given additional dependencies. The file is marked executable after copying.
|
||||
//
|
||||
// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
|
||||
// installed file will be returned by PackagingSpecs() on this module or by
|
||||
// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
|
||||
// for which IsInstallDepNeeded returns true.
|
||||
InstallExecutable(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath
|
||||
|
||||
// InstallFile creates a rule to copy srcPath to name in the installPath directory,
|
||||
// with the given additional dependencies.
|
||||
//
|
||||
// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
|
||||
// installed file will be returned by PackagingSpecs() on this module or by
|
||||
// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
|
||||
// for which IsInstallDepNeeded returns true.
|
||||
InstallFile(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath
|
||||
|
||||
// InstallFileWithExtraFilesZip creates a rule to copy srcPath to name in the installPath
|
||||
// directory, and also unzip a zip file containing extra files to install into the same
|
||||
// directory.
|
||||
//
|
||||
// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
|
||||
// installed file will be returned by PackagingSpecs() on this module or by
|
||||
// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
|
||||
// for which IsInstallDepNeeded returns true.
|
||||
InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, extraZip Path, deps ...Path) InstallPath
|
||||
|
||||
// InstallSymlink creates a rule to create a symlink from src srcPath to name in the installPath
|
||||
// directory.
|
||||
//
|
||||
// The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
|
||||
// installed file will be returned by PackagingSpecs() on this module or by
|
||||
// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
|
||||
// for which IsInstallDepNeeded returns true.
|
||||
InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath
|
||||
|
||||
// InstallAbsoluteSymlink creates a rule to create an absolute symlink from src srcPath to name
|
||||
// in the installPath directory.
|
||||
//
|
||||
// The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
|
||||
// installed file will be returned by PackagingSpecs() on this module or by
|
||||
// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
|
||||
// for which IsInstallDepNeeded returns true.
|
||||
InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath
|
||||
|
||||
// PackageFile creates a PackagingSpec as if InstallFile was called, but without creating
|
||||
// the rule to copy the file. This is useful to define how a module would be packaged
|
||||
// without installing it into the global installation directories.
|
||||
//
|
||||
// The created PackagingSpec for the will be returned by PackagingSpecs() on this module or by
|
||||
// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
|
||||
// for which IsInstallDepNeeded returns true.
|
||||
PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec
|
||||
|
||||
CheckbuildFile(srcPath Path)
|
||||
|
||||
InstallInData() bool
|
||||
InstallInTestcases() bool
|
||||
InstallInSanitizerDir() bool
|
||||
InstallInRamdisk() bool
|
||||
InstallInVendorRamdisk() bool
|
||||
InstallInDebugRamdisk() bool
|
||||
InstallInRecovery() bool
|
||||
InstallInRoot() bool
|
||||
InstallInVendor() bool
|
||||
InstallForceOS() (*OsType, *ArchType)
|
||||
|
||||
RequiredModuleNames() []string
|
||||
HostRequiredModuleNames() []string
|
||||
TargetRequiredModuleNames() []string
|
||||
|
||||
ModuleSubDir() string
|
||||
SoongConfigTraceHash() string
|
||||
|
||||
Variable(pctx PackageContext, name, value string)
|
||||
Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
|
||||
// Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string,
|
||||
// and performs more verification.
|
||||
Build(pctx PackageContext, params BuildParams)
|
||||
// Phony creates a Make-style phony rule, a rule with no commands that can depend on other
|
||||
// phony rules or real files. Phony can be called on the same name multiple times to add
|
||||
// additional dependencies.
|
||||
Phony(phony string, deps ...Path)
|
||||
|
||||
// GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods,
|
||||
// but do not exist.
|
||||
GetMissingDependencies() []string
|
||||
|
||||
// LicenseMetadataFile returns the path where the license metadata for this module will be
|
||||
// generated.
|
||||
LicenseMetadataFile() Path
|
||||
}
|
||||
|
||||
type moduleContext struct {
|
||||
bp blueprint.ModuleContext
|
||||
baseModuleContext
|
||||
packagingSpecs []PackagingSpec
|
||||
installFiles InstallPaths
|
||||
checkbuildFiles Paths
|
||||
module Module
|
||||
phonies map[string]Paths
|
||||
|
||||
katiInstalls []katiInstall
|
||||
katiSymlinks []katiInstall
|
||||
|
||||
// For tests
|
||||
buildParams []BuildParams
|
||||
ruleParams map[blueprint.Rule]blueprint.RuleParams
|
||||
variables map[string]string
|
||||
}
|
||||
|
||||
func (m *moduleContext) ninjaError(params BuildParams, err error) (PackageContext, BuildParams) {
|
||||
return pctx, BuildParams{
|
||||
Rule: ErrorRule,
|
||||
Description: params.Description,
|
||||
Output: params.Output,
|
||||
Outputs: params.Outputs,
|
||||
ImplicitOutput: params.ImplicitOutput,
|
||||
ImplicitOutputs: params.ImplicitOutputs,
|
||||
Args: map[string]string{
|
||||
"error": err.Error(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *moduleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) {
|
||||
m.Build(pctx, BuildParams(params))
|
||||
}
|
||||
|
||||
func validateBuildParams(params blueprint.BuildParams) error {
|
||||
// Validate that the symlink outputs are declared outputs or implicit outputs
|
||||
allOutputs := map[string]bool{}
|
||||
for _, output := range params.Outputs {
|
||||
allOutputs[output] = true
|
||||
}
|
||||
for _, output := range params.ImplicitOutputs {
|
||||
allOutputs[output] = true
|
||||
}
|
||||
for _, symlinkOutput := range params.SymlinkOutputs {
|
||||
if !allOutputs[symlinkOutput] {
|
||||
return fmt.Errorf(
|
||||
"Symlink output %s is not a declared output or implicit output",
|
||||
symlinkOutput)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert build parameters from their concrete Android types into their string representations,
|
||||
// and combine the singular and plural fields of the same type (e.g. Output and Outputs).
|
||||
func convertBuildParams(params BuildParams) blueprint.BuildParams {
|
||||
bparams := blueprint.BuildParams{
|
||||
Rule: params.Rule,
|
||||
Description: params.Description,
|
||||
Deps: params.Deps,
|
||||
Outputs: params.Outputs.Strings(),
|
||||
ImplicitOutputs: params.ImplicitOutputs.Strings(),
|
||||
SymlinkOutputs: params.SymlinkOutputs.Strings(),
|
||||
Inputs: params.Inputs.Strings(),
|
||||
Implicits: params.Implicits.Strings(),
|
||||
OrderOnly: params.OrderOnly.Strings(),
|
||||
Validations: params.Validations.Strings(),
|
||||
Args: params.Args,
|
||||
Optional: !params.Default,
|
||||
}
|
||||
|
||||
if params.Depfile != nil {
|
||||
bparams.Depfile = params.Depfile.String()
|
||||
}
|
||||
if params.Output != nil {
|
||||
bparams.Outputs = append(bparams.Outputs, params.Output.String())
|
||||
}
|
||||
if params.SymlinkOutput != nil {
|
||||
bparams.SymlinkOutputs = append(bparams.SymlinkOutputs, params.SymlinkOutput.String())
|
||||
}
|
||||
if params.ImplicitOutput != nil {
|
||||
bparams.ImplicitOutputs = append(bparams.ImplicitOutputs, params.ImplicitOutput.String())
|
||||
}
|
||||
if params.Input != nil {
|
||||
bparams.Inputs = append(bparams.Inputs, params.Input.String())
|
||||
}
|
||||
if params.Implicit != nil {
|
||||
bparams.Implicits = append(bparams.Implicits, params.Implicit.String())
|
||||
}
|
||||
if params.Validation != nil {
|
||||
bparams.Validations = append(bparams.Validations, params.Validation.String())
|
||||
}
|
||||
|
||||
bparams.Outputs = proptools.NinjaEscapeList(bparams.Outputs)
|
||||
bparams.ImplicitOutputs = proptools.NinjaEscapeList(bparams.ImplicitOutputs)
|
||||
bparams.SymlinkOutputs = proptools.NinjaEscapeList(bparams.SymlinkOutputs)
|
||||
bparams.Inputs = proptools.NinjaEscapeList(bparams.Inputs)
|
||||
bparams.Implicits = proptools.NinjaEscapeList(bparams.Implicits)
|
||||
bparams.OrderOnly = proptools.NinjaEscapeList(bparams.OrderOnly)
|
||||
bparams.Validations = proptools.NinjaEscapeList(bparams.Validations)
|
||||
bparams.Depfile = proptools.NinjaEscape(bparams.Depfile)
|
||||
|
||||
return bparams
|
||||
}
|
||||
|
||||
func (m *moduleContext) Variable(pctx PackageContext, name, value string) {
|
||||
if m.config.captureBuild {
|
||||
m.variables[name] = value
|
||||
}
|
||||
|
||||
m.bp.Variable(pctx.PackageContext, name, value)
|
||||
}
|
||||
|
||||
func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
|
||||
argNames ...string) blueprint.Rule {
|
||||
|
||||
if m.config.UseRemoteBuild() {
|
||||
if params.Pool == nil {
|
||||
// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
|
||||
// jobs to the local parallelism value
|
||||
params.Pool = localPool
|
||||
} else if params.Pool == remotePool {
|
||||
// remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's
|
||||
// pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS
|
||||
// parallelism.
|
||||
params.Pool = nil
|
||||
}
|
||||
}
|
||||
|
||||
rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...)
|
||||
|
||||
if m.config.captureBuild {
|
||||
m.ruleParams[rule] = params
|
||||
}
|
||||
|
||||
return rule
|
||||
}
|
||||
|
||||
func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {
|
||||
if params.Description != "" {
|
||||
params.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}"
|
||||
}
|
||||
|
||||
if missingDeps := m.GetMissingDependencies(); len(missingDeps) > 0 {
|
||||
pctx, params = m.ninjaError(params, fmt.Errorf("module %s missing dependencies: %s\n",
|
||||
m.ModuleName(), strings.Join(missingDeps, ", ")))
|
||||
}
|
||||
|
||||
if m.config.captureBuild {
|
||||
m.buildParams = append(m.buildParams, params)
|
||||
}
|
||||
|
||||
bparams := convertBuildParams(params)
|
||||
err := validateBuildParams(bparams)
|
||||
if err != nil {
|
||||
m.ModuleErrorf(
|
||||
"%s: build parameter validation failed: %s",
|
||||
m.ModuleName(),
|
||||
err.Error())
|
||||
}
|
||||
m.bp.Build(pctx.PackageContext, bparams)
|
||||
}
|
||||
|
||||
func (m *moduleContext) Phony(name string, deps ...Path) {
|
||||
addPhony(m.config, name, deps...)
|
||||
}
|
||||
|
||||
func (m *moduleContext) GetMissingDependencies() []string {
|
||||
var missingDeps []string
|
||||
missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...)
|
||||
missingDeps = append(missingDeps, m.bp.GetMissingDependencies()...)
|
||||
missingDeps = FirstUniqueStrings(missingDeps)
|
||||
return missingDeps
|
||||
}
|
||||
|
||||
func (m *moduleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
|
||||
module, _ := m.getDirectDepInternal(name, tag)
|
||||
return module
|
||||
}
|
||||
|
||||
func (m *moduleContext) ModuleSubDir() string {
|
||||
return m.bp.ModuleSubDir()
|
||||
}
|
||||
|
||||
func (m *moduleContext) SoongConfigTraceHash() string {
|
||||
return m.module.base().commonProperties.SoongConfigTraceHash
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallInData() bool {
|
||||
return m.module.InstallInData()
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallInTestcases() bool {
|
||||
return m.module.InstallInTestcases()
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallInSanitizerDir() bool {
|
||||
return m.module.InstallInSanitizerDir()
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallInRamdisk() bool {
|
||||
return m.module.InstallInRamdisk()
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallInVendorRamdisk() bool {
|
||||
return m.module.InstallInVendorRamdisk()
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallInDebugRamdisk() bool {
|
||||
return m.module.InstallInDebugRamdisk()
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallInRecovery() bool {
|
||||
return m.module.InstallInRecovery()
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallInRoot() bool {
|
||||
return m.module.InstallInRoot()
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallForceOS() (*OsType, *ArchType) {
|
||||
return m.module.InstallForceOS()
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallInVendor() bool {
|
||||
return m.module.InstallInVendor()
|
||||
}
|
||||
|
||||
func (m *moduleContext) skipInstall() bool {
|
||||
if m.module.base().commonProperties.SkipInstall {
|
||||
return true
|
||||
}
|
||||
|
||||
if m.module.base().commonProperties.HideFromMake {
|
||||
return true
|
||||
}
|
||||
|
||||
// We'll need a solution for choosing which of modules with the same name in different
|
||||
// namespaces to install. For now, reuse the list of namespaces exported to Make as the
|
||||
// list of namespaces to install in a Soong-only build.
|
||||
if !m.module.base().commonProperties.NamespaceExportedToMake {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path,
|
||||
deps ...Path) InstallPath {
|
||||
return m.installFile(installPath, name, srcPath, deps, false, nil)
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path,
|
||||
deps ...Path) InstallPath {
|
||||
return m.installFile(installPath, name, srcPath, deps, true, nil)
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path,
|
||||
extraZip Path, deps ...Path) InstallPath {
|
||||
return m.installFile(installPath, name, srcPath, deps, false, &extraFilesZip{
|
||||
zip: extraZip,
|
||||
dir: installPath,
|
||||
})
|
||||
}
|
||||
|
||||
func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec {
|
||||
fullInstallPath := installPath.Join(m, name)
|
||||
return m.packageFile(fullInstallPath, srcPath, false)
|
||||
}
|
||||
|
||||
func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool) PackagingSpec {
|
||||
licenseFiles := m.Module().EffectiveLicenseFiles()
|
||||
spec := PackagingSpec{
|
||||
relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
|
||||
srcPath: srcPath,
|
||||
symlinkTarget: "",
|
||||
executable: executable,
|
||||
effectiveLicenseFiles: &licenseFiles,
|
||||
partition: fullInstallPath.partition,
|
||||
}
|
||||
m.packagingSpecs = append(m.packagingSpecs, spec)
|
||||
return spec
|
||||
}
|
||||
|
||||
func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []Path,
|
||||
executable bool, extraZip *extraFilesZip) InstallPath {
|
||||
|
||||
fullInstallPath := installPath.Join(m, name)
|
||||
m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false)
|
||||
|
||||
if !m.skipInstall() {
|
||||
deps = append(deps, InstallPaths(m.module.base().installFilesDepSet.ToList()).Paths()...)
|
||||
|
||||
var implicitDeps, orderOnlyDeps Paths
|
||||
|
||||
if m.Host() {
|
||||
// Installed host modules might be used during the build, depend directly on their
|
||||
// dependencies so their timestamp is updated whenever their dependency is updated
|
||||
implicitDeps = deps
|
||||
} else {
|
||||
orderOnlyDeps = deps
|
||||
}
|
||||
|
||||
if m.Config().KatiEnabled() {
|
||||
// When creating the install rule in Soong but embedding in Make, write the rule to a
|
||||
// makefile instead of directly to the ninja file so that main.mk can add the
|
||||
// dependencies from the `required` property that are hard to resolve in Soong.
|
||||
m.katiInstalls = append(m.katiInstalls, katiInstall{
|
||||
from: srcPath,
|
||||
to: fullInstallPath,
|
||||
implicitDeps: implicitDeps,
|
||||
orderOnlyDeps: orderOnlyDeps,
|
||||
executable: executable,
|
||||
extraFiles: extraZip,
|
||||
})
|
||||
} else {
|
||||
rule := Cp
|
||||
if executable {
|
||||
rule = CpExecutable
|
||||
}
|
||||
|
||||
extraCmds := ""
|
||||
if extraZip != nil {
|
||||
extraCmds += fmt.Sprintf(" && ( unzip -qDD -d '%s' '%s' 2>&1 | grep -v \"zipfile is empty\"; exit $${PIPESTATUS[0]} )",
|
||||
extraZip.dir.String(), extraZip.zip.String())
|
||||
extraCmds += " || ( code=$$?; if [ $$code -ne 0 -a $$code -ne 1 ]; then exit $$code; fi )"
|
||||
implicitDeps = append(implicitDeps, extraZip.zip)
|
||||
}
|
||||
|
||||
m.Build(pctx, BuildParams{
|
||||
Rule: rule,
|
||||
Description: "install " + fullInstallPath.Base(),
|
||||
Output: fullInstallPath,
|
||||
Input: srcPath,
|
||||
Implicits: implicitDeps,
|
||||
OrderOnly: orderOnlyDeps,
|
||||
Default: !m.Config().KatiEnabled(),
|
||||
Args: map[string]string{
|
||||
"extraCmds": extraCmds,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
m.installFiles = append(m.installFiles, fullInstallPath)
|
||||
}
|
||||
|
||||
m.packageFile(fullInstallPath, srcPath, executable)
|
||||
|
||||
m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
|
||||
|
||||
return fullInstallPath
|
||||
}
|
||||
|
||||
func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath {
|
||||
fullInstallPath := installPath.Join(m, name)
|
||||
m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, true)
|
||||
|
||||
relPath, err := filepath.Rel(path.Dir(fullInstallPath.String()), srcPath.String())
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Unable to generate symlink between %q and %q: %s", fullInstallPath.Base(), srcPath.Base(), err))
|
||||
}
|
||||
if !m.skipInstall() {
|
||||
|
||||
if m.Config().KatiEnabled() {
|
||||
// When creating the symlink rule in Soong but embedding in Make, write the rule to a
|
||||
// makefile instead of directly to the ninja file so that main.mk can add the
|
||||
// dependencies from the `required` property that are hard to resolve in Soong.
|
||||
m.katiSymlinks = append(m.katiSymlinks, katiInstall{
|
||||
from: srcPath,
|
||||
to: fullInstallPath,
|
||||
})
|
||||
} else {
|
||||
// The symlink doesn't need updating when the target is modified, but we sometimes
|
||||
// have a dependency on a symlink to a binary instead of to the binary directly, and
|
||||
// the mtime of the symlink must be updated when the binary is modified, so use a
|
||||
// normal dependency here instead of an order-only dependency.
|
||||
m.Build(pctx, BuildParams{
|
||||
Rule: Symlink,
|
||||
Description: "install symlink " + fullInstallPath.Base(),
|
||||
Output: fullInstallPath,
|
||||
Input: srcPath,
|
||||
Default: !m.Config().KatiEnabled(),
|
||||
Args: map[string]string{
|
||||
"fromPath": relPath,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
m.installFiles = append(m.installFiles, fullInstallPath)
|
||||
m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
|
||||
}
|
||||
|
||||
m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
|
||||
relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
|
||||
srcPath: nil,
|
||||
symlinkTarget: relPath,
|
||||
executable: false,
|
||||
partition: fullInstallPath.partition,
|
||||
})
|
||||
|
||||
return fullInstallPath
|
||||
}
|
||||
|
||||
// installPath/name -> absPath where absPath might be a path that is available only at runtime
|
||||
// (e.g. /apex/...)
|
||||
func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath {
|
||||
fullInstallPath := installPath.Join(m, name)
|
||||
m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true)
|
||||
|
||||
if !m.skipInstall() {
|
||||
if m.Config().KatiEnabled() {
|
||||
// When creating the symlink rule in Soong but embedding in Make, write the rule to a
|
||||
// makefile instead of directly to the ninja file so that main.mk can add the
|
||||
// dependencies from the `required` property that are hard to resolve in Soong.
|
||||
m.katiSymlinks = append(m.katiSymlinks, katiInstall{
|
||||
absFrom: absPath,
|
||||
to: fullInstallPath,
|
||||
})
|
||||
} else {
|
||||
m.Build(pctx, BuildParams{
|
||||
Rule: Symlink,
|
||||
Description: "install symlink " + fullInstallPath.Base() + " -> " + absPath,
|
||||
Output: fullInstallPath,
|
||||
Default: !m.Config().KatiEnabled(),
|
||||
Args: map[string]string{
|
||||
"fromPath": absPath,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
m.installFiles = append(m.installFiles, fullInstallPath)
|
||||
}
|
||||
|
||||
m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
|
||||
relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
|
||||
srcPath: nil,
|
||||
symlinkTarget: absPath,
|
||||
executable: false,
|
||||
partition: fullInstallPath.partition,
|
||||
})
|
||||
|
||||
return fullInstallPath
|
||||
}
|
||||
|
||||
func (m *moduleContext) CheckbuildFile(srcPath Path) {
|
||||
m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
|
||||
}
|
||||
|
||||
func (m *moduleContext) blueprintModuleContext() blueprint.ModuleContext {
|
||||
return m.bp
|
||||
}
|
||||
|
||||
func (m *moduleContext) LicenseMetadataFile() Path {
|
||||
return m.module.base().licenseMetadataFile
|
||||
}
|
||||
|
||||
// Returns a list of paths expanded from globs and modules referenced using ":module" syntax. The property must
|
||||
// be tagged with `android:"path" to support automatic source module dependency resolution.
|
||||
//
|
||||
// Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead.
|
||||
func (m *moduleContext) ExpandSources(srcFiles, excludes []string) Paths {
|
||||
return PathsForModuleSrcExcludes(m, srcFiles, excludes)
|
||||
}
|
||||
|
||||
// Returns a single path expanded from globs and modules referenced using ":module" syntax. The property must
|
||||
// be tagged with `android:"path" to support automatic source module dependency resolution.
|
||||
//
|
||||
// Deprecated: use PathForModuleSrc instead.
|
||||
func (m *moduleContext) ExpandSource(srcFile, _ string) Path {
|
||||
return PathForModuleSrc(m, srcFile)
|
||||
}
|
||||
|
||||
// Returns an optional single path expanded from globs and modules referenced using ":module" syntax if
|
||||
// the srcFile is non-nil. The property must be tagged with `android:"path" to support automatic source module
|
||||
// dependency resolution.
|
||||
func (m *moduleContext) ExpandOptionalSource(srcFile *string, _ string) OptionalPath {
|
||||
if srcFile != nil {
|
||||
return OptionalPathForPath(PathForModuleSrc(m, *srcFile))
|
||||
}
|
||||
return OptionalPath{}
|
||||
}
|
||||
|
||||
func (m *moduleContext) RequiredModuleNames() []string {
|
||||
return m.module.RequiredModuleNames()
|
||||
}
|
||||
|
||||
func (m *moduleContext) HostRequiredModuleNames() []string {
|
||||
return m.module.HostRequiredModuleNames()
|
||||
}
|
||||
|
||||
func (m *moduleContext) TargetRequiredModuleNames() []string {
|
||||
return m.module.TargetRequiredModuleNames()
|
||||
}
|
Reference in New Issue
Block a user