Add //visibility:any_partition
When we convert the partitions to be built with soong, there will likely be separate partition modules per product. This means that a lot of installable modules will have to be visible to a lot of partitions. To make this easier, add the //visibility:any_partition visibility spec, which allows the module to be used from any module of type android_filesystem or android_system_image. Fixes: 321000103 Test: go test Change-Id: Iea1f1ab7d88dfdb1fd00f19eb8c9941693a2375f
This commit is contained in:
parent
617b3e288a
commit
894bb3b530
4 changed files with 104 additions and 37 deletions
|
@ -314,6 +314,9 @@ subpackages) can use this module.
|
||||||
* `["//visibility:override"]`: Discards any rules inherited from defaults or a
|
* `["//visibility:override"]`: Discards any rules inherited from defaults or a
|
||||||
creating module. Can only be used at the beginning of a list of visibility
|
creating module. Can only be used at the beginning of a list of visibility
|
||||||
rules.
|
rules.
|
||||||
|
* `["//visibility:any_partition"]`: Any modules of type android_filesystem
|
||||||
|
or android_system_image can use this module. Intended for modules that no one
|
||||||
|
should link against, but should still be included in soong-built partitions.
|
||||||
* `["//some/package:__pkg__", "//other/package:__pkg__"]`: Only modules in
|
* `["//some/package:__pkg__", "//other/package:__pkg__"]`: Only modules in
|
||||||
`some/package` and `other/package` (defined in `some/package/*.bp` and
|
`some/package` and `other/package` (defined in `some/package/*.bp` and
|
||||||
`other/package/*.bp`) have access to this module. Note that sub-packages do not
|
`other/package/*.bp`) have access to this module. Note that sub-packages do not
|
||||||
|
|
|
@ -250,8 +250,8 @@ func (s *singletonContextAdaptor) FinalModule(module Module) Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *singletonContextAdaptor) ModuleVariantsFromName(referer Module, name string) []Module {
|
func (s *singletonContextAdaptor) ModuleVariantsFromName(referer Module, name string) []Module {
|
||||||
// get qualified module name for visibility enforcement
|
// get module reference for visibility enforcement
|
||||||
qualified := createQualifiedModuleName(s.ModuleName(referer), s.ModuleDir(referer))
|
qualified := createVisibilityModuleReference(s.ModuleName(referer), s.ModuleDir(referer), s.ModuleType(referer))
|
||||||
|
|
||||||
modules := s.SingletonContext.ModuleVariantsFromName(referer, name)
|
modules := s.SingletonContext.ModuleVariantsFromName(referer, name)
|
||||||
result := make([]Module, 0, len(modules))
|
result := make([]Module, 0, len(modules))
|
||||||
|
@ -262,7 +262,7 @@ func (s *singletonContextAdaptor) ModuleVariantsFromName(referer Module, name st
|
||||||
depDir := s.ModuleDir(module)
|
depDir := s.ModuleDir(module)
|
||||||
depQualified := qualifiedModuleName{depDir, depName}
|
depQualified := qualifiedModuleName{depDir, depName}
|
||||||
// Targets are always visible to other targets in their own package.
|
// Targets are always visible to other targets in their own package.
|
||||||
if depQualified.pkg != qualified.pkg {
|
if depQualified.pkg != qualified.name.pkg {
|
||||||
rule := effectiveVisibilityRules(s.Config(), depQualified)
|
rule := effectiveVisibilityRules(s.Config(), depQualified)
|
||||||
if !rule.matches(qualified) {
|
if !rule.matches(qualified) {
|
||||||
s.ModuleErrorf(referer, "module %q references %q which is not visible to this module\nYou may need to add %q to its visibility",
|
s.ModuleErrorf(referer, "module %q references %q which is not visible to this module\nYou may need to add %q to its visibility",
|
||||||
|
|
|
@ -57,12 +57,29 @@ const (
|
||||||
|
|
||||||
var visibilityRuleRegexp = regexp.MustCompile(visibilityRulePattern)
|
var visibilityRuleRegexp = regexp.MustCompile(visibilityRulePattern)
|
||||||
|
|
||||||
|
type visibilityModuleReference struct {
|
||||||
|
name qualifiedModuleName
|
||||||
|
isPartitionModule bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func createVisibilityModuleReference(name, dir, typ string) visibilityModuleReference {
|
||||||
|
isPartitionModule := false
|
||||||
|
switch typ {
|
||||||
|
case "android_filesystem", "android_system_image":
|
||||||
|
isPartitionModule = true
|
||||||
|
}
|
||||||
|
return visibilityModuleReference{
|
||||||
|
name: createQualifiedModuleName(name, dir),
|
||||||
|
isPartitionModule: isPartitionModule,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A visibility rule is associated with a module and determines which other modules it is visible
|
// A visibility rule is associated with a module and determines which other modules it is visible
|
||||||
// to, i.e. which other modules can depend on the rule's module.
|
// to, i.e. which other modules can depend on the rule's module.
|
||||||
type visibilityRule interface {
|
type visibilityRule interface {
|
||||||
// Check to see whether this rules matches m.
|
// Check to see whether this rules matches m.
|
||||||
// Returns true if it does, false otherwise.
|
// Returns true if it does, false otherwise.
|
||||||
matches(m qualifiedModuleName) bool
|
matches(m visibilityModuleReference) bool
|
||||||
|
|
||||||
String() string
|
String() string
|
||||||
}
|
}
|
||||||
|
@ -108,8 +125,10 @@ func (p visibilityPropertyImpl) getStrings() []string {
|
||||||
// ["//visibility:private"].
|
// ["//visibility:private"].
|
||||||
type compositeRule []visibilityRule
|
type compositeRule []visibilityRule
|
||||||
|
|
||||||
|
var _ visibilityRule = compositeRule{}
|
||||||
|
|
||||||
// A compositeRule matches if and only if any of its rules matches.
|
// A compositeRule matches if and only if any of its rules matches.
|
||||||
func (c compositeRule) matches(m qualifiedModuleName) bool {
|
func (c compositeRule) matches(m visibilityModuleReference) bool {
|
||||||
for _, r := range c {
|
for _, r := range c {
|
||||||
if r.matches(m) {
|
if r.matches(m) {
|
||||||
return true
|
return true
|
||||||
|
@ -135,8 +154,10 @@ type packageRule struct {
|
||||||
pkg string
|
pkg string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r packageRule) matches(m qualifiedModuleName) bool {
|
var _ visibilityRule = packageRule{}
|
||||||
return m.pkg == r.pkg
|
|
||||||
|
func (r packageRule) matches(m visibilityModuleReference) bool {
|
||||||
|
return m.name.pkg == r.pkg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r packageRule) String() string {
|
func (r packageRule) String() string {
|
||||||
|
@ -149,8 +170,10 @@ type subpackagesRule struct {
|
||||||
pkgPrefix string
|
pkgPrefix string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r subpackagesRule) matches(m qualifiedModuleName) bool {
|
var _ visibilityRule = subpackagesRule{}
|
||||||
return isAncestor(r.pkgPrefix, m.pkg)
|
|
||||||
|
func (r subpackagesRule) matches(m visibilityModuleReference) bool {
|
||||||
|
return isAncestor(r.pkgPrefix, m.name.pkg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isAncestor(p1 string, p2 string) bool {
|
func isAncestor(p1 string, p2 string) bool {
|
||||||
|
@ -168,7 +191,9 @@ func (r subpackagesRule) String() string {
|
||||||
// visibilityRule for //visibility:public
|
// visibilityRule for //visibility:public
|
||||||
type publicRule struct{}
|
type publicRule struct{}
|
||||||
|
|
||||||
func (r publicRule) matches(_ qualifiedModuleName) bool {
|
var _ visibilityRule = publicRule{}
|
||||||
|
|
||||||
|
func (r publicRule) matches(_ visibilityModuleReference) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +204,9 @@ func (r publicRule) String() string {
|
||||||
// visibilityRule for //visibility:private
|
// visibilityRule for //visibility:private
|
||||||
type privateRule struct{}
|
type privateRule struct{}
|
||||||
|
|
||||||
func (r privateRule) matches(_ qualifiedModuleName) bool {
|
var _ visibilityRule = privateRule{}
|
||||||
|
|
||||||
|
func (r privateRule) matches(_ visibilityModuleReference) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +214,19 @@ func (r privateRule) String() string {
|
||||||
return "//visibility:private"
|
return "//visibility:private"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// visibilityRule for //visibility:any_partition
|
||||||
|
type anyPartitionRule struct{}
|
||||||
|
|
||||||
|
var _ visibilityRule = anyPartitionRule{}
|
||||||
|
|
||||||
|
func (r anyPartitionRule) matches(m visibilityModuleReference) bool {
|
||||||
|
return m.isPartitionModule
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r anyPartitionRule) String() string {
|
||||||
|
return "//visibility:any_partition"
|
||||||
|
}
|
||||||
|
|
||||||
var visibilityRuleMap = NewOnceKey("visibilityRuleMap")
|
var visibilityRuleMap = NewOnceKey("visibilityRuleMap")
|
||||||
|
|
||||||
// The map from qualifiedModuleName to visibilityRule.
|
// The map from qualifiedModuleName to visibilityRule.
|
||||||
|
@ -237,13 +277,10 @@ func RegisterVisibilityRuleEnforcer(ctx RegisterMutatorsContext) {
|
||||||
|
|
||||||
// Checks the per-module visibility rule lists before defaults expansion.
|
// Checks the per-module visibility rule lists before defaults expansion.
|
||||||
func visibilityRuleChecker(ctx BottomUpMutatorContext) {
|
func visibilityRuleChecker(ctx BottomUpMutatorContext) {
|
||||||
qualified := createQualifiedModuleName(ctx.ModuleName(), ctx.ModuleDir())
|
visibilityProperties := ctx.Module().visibilityProperties()
|
||||||
if m, ok := ctx.Module().(Module); ok {
|
for _, p := range visibilityProperties {
|
||||||
visibilityProperties := m.visibilityProperties()
|
if visibility := p.getStrings(); visibility != nil {
|
||||||
for _, p := range visibilityProperties {
|
checkRules(ctx, ctx.ModuleDir(), p.getName(), visibility)
|
||||||
if visibility := p.getStrings(); visibility != nil {
|
|
||||||
checkRules(ctx, qualified.pkg, p.getName(), visibility)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,7 +303,7 @@ func checkRules(ctx BaseModuleContext, currentPkg, property string, visibility [
|
||||||
|
|
||||||
if pkg == "visibility" {
|
if pkg == "visibility" {
|
||||||
switch name {
|
switch name {
|
||||||
case "private", "public":
|
case "private", "public", "any_partition":
|
||||||
case "legacy_public":
|
case "legacy_public":
|
||||||
ctx.PropertyErrorf(property, "//visibility:legacy_public must not be used")
|
ctx.PropertyErrorf(property, "//visibility:legacy_public must not be used")
|
||||||
continue
|
continue
|
||||||
|
@ -305,10 +342,7 @@ func checkRules(ctx BaseModuleContext, currentPkg, property string, visibility [
|
||||||
//
|
//
|
||||||
// See ../README.md#Visibility for information on the format of the visibility rules.
|
// See ../README.md#Visibility for information on the format of the visibility rules.
|
||||||
func visibilityRuleGatherer(ctx BottomUpMutatorContext) {
|
func visibilityRuleGatherer(ctx BottomUpMutatorContext) {
|
||||||
m, ok := ctx.Module().(Module)
|
m := ctx.Module()
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
qualifiedModuleId := m.qualifiedModuleId(ctx)
|
qualifiedModuleId := m.qualifiedModuleId(ctx)
|
||||||
currentPkg := qualifiedModuleId.pkg
|
currentPkg := qualifiedModuleId.pkg
|
||||||
|
@ -355,6 +389,8 @@ func parseRules(ctx BaseModuleContext, currentPkg, property string, visibility [
|
||||||
hasNonPrivateRule = false
|
hasNonPrivateRule = false
|
||||||
// This does not actually create a rule so continue onto the next rule.
|
// This does not actually create a rule so continue onto the next rule.
|
||||||
continue
|
continue
|
||||||
|
case "any_partition":
|
||||||
|
r = anyPartitionRule{}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch name {
|
switch name {
|
||||||
|
@ -395,10 +431,7 @@ func parseRules(ctx BaseModuleContext, currentPkg, property string, visibility [
|
||||||
|
|
||||||
func isAllowedFromOutsideVendor(pkg string, name string) bool {
|
func isAllowedFromOutsideVendor(pkg string, name string) bool {
|
||||||
if pkg == "vendor" {
|
if pkg == "vendor" {
|
||||||
if name == "__subpackages__" {
|
return name == "__subpackages__"
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return !isAncestor("vendor", pkg)
|
return !isAncestor("vendor", pkg)
|
||||||
|
@ -434,11 +467,7 @@ func splitRule(ctx BaseModuleContext, ruleExpression string, currentPkg, propert
|
||||||
}
|
}
|
||||||
|
|
||||||
func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
|
func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
|
||||||
if _, ok := ctx.Module().(Module); !ok {
|
qualified := createVisibilityModuleReference(ctx.ModuleName(), ctx.ModuleDir(), ctx.ModuleType())
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
qualified := createQualifiedModuleName(ctx.ModuleName(), ctx.ModuleDir())
|
|
||||||
|
|
||||||
// Visit all the dependencies making sure that this module has access to them all.
|
// Visit all the dependencies making sure that this module has access to them all.
|
||||||
ctx.VisitDirectDeps(func(dep Module) {
|
ctx.VisitDirectDeps(func(dep Module) {
|
||||||
|
@ -453,7 +482,7 @@ func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
|
||||||
depQualified := qualifiedModuleName{depDir, depName}
|
depQualified := qualifiedModuleName{depDir, depName}
|
||||||
|
|
||||||
// Targets are always visible to other targets in their own package.
|
// Targets are always visible to other targets in their own package.
|
||||||
if depQualified.pkg == qualified.pkg {
|
if depQualified.pkg == qualified.name.pkg {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,7 +507,7 @@ func effectiveVisibilityRules(config Config, qualified qualifiedModuleName) comp
|
||||||
if ok {
|
if ok {
|
||||||
rule = value.(compositeRule)
|
rule = value.(compositeRule)
|
||||||
} else {
|
} else {
|
||||||
rule = packageDefaultVisibility(config, qualified)
|
rule = packageDefaultVisibility(moduleToVisibilityRule, qualified)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no rule is specified then return the default visibility rule to avoid
|
// If no rule is specified then return the default visibility rule to avoid
|
||||||
|
@ -494,8 +523,7 @@ func createQualifiedModuleName(moduleName, dir string) qualifiedModuleName {
|
||||||
return qualified
|
return qualified
|
||||||
}
|
}
|
||||||
|
|
||||||
func packageDefaultVisibility(config Config, moduleId qualifiedModuleName) compositeRule {
|
func packageDefaultVisibility(moduleToVisibilityRule *sync.Map, moduleId qualifiedModuleName) compositeRule {
|
||||||
moduleToVisibilityRule := moduleToVisibilityRuleMap(config)
|
|
||||||
packageQualifiedId := moduleId.getContainingPackageId()
|
packageQualifiedId := moduleId.getContainingPackageId()
|
||||||
for {
|
for {
|
||||||
value, ok := moduleToVisibilityRule.Load(packageQualifiedId)
|
value, ok := moduleToVisibilityRule.Load(packageQualifiedId)
|
||||||
|
@ -574,10 +602,12 @@ func EffectiveVisibilityRules(ctx BaseModuleContext, module Module) VisibilityRu
|
||||||
|
|
||||||
rule := effectiveVisibilityRules(ctx.Config(), qualified)
|
rule := effectiveVisibilityRules(ctx.Config(), qualified)
|
||||||
|
|
||||||
|
currentModule := createVisibilityModuleReference(moduleName, dir, ctx.OtherModuleType(module))
|
||||||
|
|
||||||
// Modules are implicitly visible to other modules in the same package,
|
// Modules are implicitly visible to other modules in the same package,
|
||||||
// without checking the visibility rules. Here we need to add that visibility
|
// without checking the visibility rules. Here we need to add that visibility
|
||||||
// explicitly.
|
// explicitly.
|
||||||
if !rule.matches(qualified) {
|
if !rule.matches(currentModule) {
|
||||||
if len(rule) == 1 {
|
if len(rule) == 1 {
|
||||||
if _, ok := rule[0].(privateRule); ok {
|
if _, ok := rule[0].(privateRule); ok {
|
||||||
// If the rule is //visibility:private we can't append another
|
// If the rule is //visibility:private we can't append another
|
||||||
|
|
|
@ -1904,6 +1904,38 @@ var visibilityTests = []struct {
|
||||||
}`),
|
}`),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "any_partition visibility works",
|
||||||
|
fs: MockFS{
|
||||||
|
"top/Android.bp": []byte(`
|
||||||
|
android_filesystem {
|
||||||
|
name: "foo",
|
||||||
|
deps: ["bar"],
|
||||||
|
}`),
|
||||||
|
"top/nested/Android.bp": []byte(`
|
||||||
|
package(default_visibility=["//visibility:private"])
|
||||||
|
mock_library {
|
||||||
|
name: "bar",
|
||||||
|
visibility: ["//visibility:any_partition"],
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "any_partition visibility doesn't work for non-partitions",
|
||||||
|
fs: MockFS{
|
||||||
|
"top/Android.bp": []byte(`
|
||||||
|
mock_library {
|
||||||
|
name: "foo",
|
||||||
|
deps: ["bar"],
|
||||||
|
}`),
|
||||||
|
"top/nested/Android.bp": []byte(`
|
||||||
|
mock_library {
|
||||||
|
name: "bar",
|
||||||
|
visibility: ["//visibility:any_partition"],
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
expectedErrors: []string{`module "foo" variant "android_common": depends on //top/nested:bar which is not visible to this module`},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVisibility(t *testing.T) {
|
func TestVisibility(t *testing.T) {
|
||||||
|
@ -1925,6 +1957,8 @@ func TestVisibility(t *testing.T) {
|
||||||
ctx.RegisterModuleType("mock_library", newMockLibraryModule)
|
ctx.RegisterModuleType("mock_library", newMockLibraryModule)
|
||||||
ctx.RegisterModuleType("mock_parent", newMockParentFactory)
|
ctx.RegisterModuleType("mock_parent", newMockParentFactory)
|
||||||
ctx.RegisterModuleType("mock_defaults", defaultsFactory)
|
ctx.RegisterModuleType("mock_defaults", defaultsFactory)
|
||||||
|
// For testing //visibility:any_partition. The module type doesn't matter, just that it's registered under the name "android_filesystem"
|
||||||
|
ctx.RegisterModuleType("android_filesystem", newMockLibraryModule)
|
||||||
}),
|
}),
|
||||||
prepareForTestWithFakePrebuiltModules,
|
prepareForTestWithFakePrebuiltModules,
|
||||||
// Add additional files to the mock filesystem
|
// Add additional files to the mock filesystem
|
||||||
|
|
Loading…
Reference in a new issue