Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cbcb8675 authored by Paul Duffin's avatar Paul Duffin Committed by android-build-merger
Browse files

Merge changes from topic "package default_visibility" am: 4190926e

am: b9156584

Change-Id: Ib207ca13b58e789ea7e545cb99db789cb5d83cfe
parents f137467b b9156584
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ bootstrap_go_package {
        "android/notices.go",
        "android/onceper.go",
        "android/override_module.go",
        "android/package.go",
        "android/package_ctx.go",
        "android/path_properties.go",
        "android/paths.go",
@@ -88,6 +89,7 @@ bootstrap_go_package {
        "android/namespace_test.go",
        "android/neverallow_test.go",
        "android/onceper_test.go",
        "android/package_test.go",
        "android/path_properties_test.go",
        "android/paths_test.go",
        "android/prebuilt_test.go",
+37 −9
Original line number Diff line number Diff line
@@ -133,6 +133,25 @@ directory) there are two packages, `my/app`, and the subpackage `my/app/tests`.

This is based on the Bazel package concept.

The `package` module type allows information to be specified about a package. Only a single
`package` module can be specified per package and in the case where there are multiple `.bp` files
in the same package directory it is highly recommended that the `package` module (if required) is
specified in the `Android.bp` file.

Unlike most module type `package` does not have a `name` property. Instead the name is set to the
name of the package, e.g. if the package is in `top/intermediate/package` then the package name is
`//top/intermediate/package`.

E.g. The following will set the default visibility for all the modules defined in the package and
any subpackages that do not set their own default visibility (irrespective of whether they are in
the same `.bp` file as the `package` module) to be visible to all the subpackages by default.

```
package {
    default_visibility: [":__subpackages"]
}
```

### Name resolution

Soong provides the ability for modules in different directories to specify
@@ -191,7 +210,7 @@ this module. For example, `//project:rule`, `//project/library:lib` or
`//independent:evil`)
* `["//project"]`: This is shorthand for `["//project:__pkg__"]`
* `[":__subpackages__"]`: This is shorthand for `["//project:__subpackages__"]`
where `//project` is the module's package. e.g. using `[":__subpackages__"]` in
where `//project` is the module's package, e.g. using `[":__subpackages__"]` in
`packages/apps/Settings/Android.bp` is equivalent to
`//packages/apps/Settings:__subpackages__`.
* `["//visibility:legacy_public"]`: The default visibility, behaves as
@@ -207,13 +226,22 @@ in `vendor/`, e.g. a module in `libcore` cannot declare that it is visible to
say `vendor/google`, instead it must make itself visible to all packages within
`vendor/` using `//vendor:__subpackages__`.

If a module does not specify the `visibility` property the module is
`//visibility:legacy_public`. Once the build has been completely switched over to
soong it is possible that a global refactoring will be done to change this to
`//visibility:private` at which point all modules that do not currently specify
a `visibility` property will be updated to have
`visibility = [//visibility:legacy_public]` added. It will then be the owner's
responsibility to replace that with a more appropriate visibility.
If a module does not specify the `visibility` property then it uses the
`default_visibility` property of the `package` module in the module's package.

If the `default_visibility` property is not set for the module's package then
it will use the `default_visibility` of its closest ancestor package for which
a `default_visibility` property is specified.

If no `default_visibility` property can be found then the module uses the
global default of `//visibility:legacy_public`.

Once the build has been completely switched over to soong it is possible that a
global refactoring will be done to change this to `//visibility:private` at
which point all packages that do not currently specify a `default_visibility`
property will be updated to have
`default_visibility = [//visibility:legacy_public]` added. It will then be the
owner's responsibility to replace that with a more appropriate visibility.

### Formatter

+75 −0
Original line number Diff line number Diff line
@@ -202,6 +202,55 @@ type Module interface {
	BuildParamsForTests() []BuildParams
	RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams
	VariablesForTests() map[string]string

	// Get the qualified module id for this module.
	qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleName

	// Get information about the properties that can contain visibility rules.
	visibilityProperties() []visibilityProperty
}

// Qualified id for a module
type qualifiedModuleName struct {
	// The package (i.e. directory) in which the module is defined, without trailing /
	pkg string

	// The name of the module, empty string if package.
	name string
}

func (q qualifiedModuleName) String() string {
	if q.name == "" {
		return "//" + q.pkg
	}
	return "//" + q.pkg + ":" + q.name
}

func (q qualifiedModuleName) isRootPackage() bool {
	return q.pkg == "" && q.name == ""
}

// Get the id for the package containing this module.
func (q qualifiedModuleName) getContainingPackageId() qualifiedModuleName {
	pkg := q.pkg
	if q.name == "" {
		if pkg == "" {
			panic(fmt.Errorf("Cannot get containing package id of root package"))
		}

		index := strings.LastIndex(pkg, "/")
		if index == -1 {
			pkg = ""
		} else {
			pkg = pkg[:index]
		}
	}
	return newPackageId(pkg)
}

func newPackageId(pkg string) qualifiedModuleName {
	// A qualified id for a package module has no name.
	return qualifiedModuleName{pkg: pkg, name: ""}
}

type nameProperties struct {
@@ -236,6 +285,20 @@ type commonProperties struct {
	//      //packages/apps/Settings:__subpackages__.
	//  ["//visibility:legacy_public"]: The default visibility, behaves as //visibility:public
	//      for now. It is an error if it is used in a module.
	//
	// If a module does not specify the `visibility` property then it uses the
	// `default_visibility` property of the `package` module in the module's package.
	//
	// If a module does not specify the `visibility` property then it uses the
	// `default_visibility` property of the `package` module in the module's package.
	//
	// If the `default_visibility` property is not set for the module's package then
	// it will use the `default_visibility` of its closest ancestor package for which
	// a `default_visibility` property is specified.
	//
	// If no `default_visibility` property can be found then the module uses the
	// global default of `//visibility:legacy_public`.
	//
	// See https://android.googlesource.com/platform/build/soong/+/master/README.md#visibility for
	// more details.
	Visibility []string
@@ -571,6 +634,18 @@ func (m *ModuleBase) base() *ModuleBase {
	return m
}

func (m *ModuleBase) qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleName {
	return qualifiedModuleName{pkg: ctx.ModuleDir(), name: ctx.ModuleName()}
}

func (m *ModuleBase) visibilityProperties() []visibilityProperty {
	return []visibilityProperty{
		newVisibilityProperty("visibility", func() []string {
			return m.base().commonProperties.Visibility
		}),
	}
}

func (m *ModuleBase) SetTarget(target Target, multiTargets []Target, primary bool) {
	m.commonProperties.CompileTarget = target
	m.commonProperties.CompileMultiTargets = multiTargets
+2 −0
Original line number Diff line number Diff line
@@ -75,6 +75,8 @@ type RegisterMutatorFunc func(RegisterMutatorsContext)
var preArch = []RegisterMutatorFunc{
	registerLoadHookMutator,
	RegisterNamespaceMutator,
	// Rename package module types.
	registerPackageRenamer,
	RegisterPrebuiltsPreArchMutators,
	registerVisibilityRuleChecker,
	RegisterDefaultsPreArchMutators,

android/package.go

0 → 100644
+194 −0
Original line number Diff line number Diff line
// Copyright 2019 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"
	"sync/atomic"

	"github.com/google/blueprint"
)

func init() {
	RegisterModuleType("package", PackageFactory)
}

// The information maintained about each package.
type packageInfo struct {
	// The module from which this information was populated. If `duplicated` = true then this is the
	// module that has been renamed and must be used to report errors.
	module *packageModule

	// If true this indicates that there are two package statements in the same package which is not
	// allowed and will cause the build to fail. This flag is set by packageRenamer and checked in
	// packageErrorReporter
	duplicated bool
}

type packageProperties struct {
	Name string `blueprint:"mutated"`

	// Specifies the default visibility for all modules defined in this package.
	Default_visibility []string
}

type packageModule struct {
	ModuleBase

	properties  packageProperties
	packageInfo *packageInfo
}

func (p *packageModule) GenerateAndroidBuildActions(ModuleContext) {
	// Nothing to do.
}

func (p *packageModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
	// Nothing to do.
}

func (p *packageModule) qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleName {
	// Override to create a package id.
	return newPackageId(ctx.ModuleDir())
}

// Override to ensure that the default_visibility rules are checked by the visibility module during
// its checking phase.
func (p *packageModule) visibilityProperties() []visibilityProperty {
	return []visibilityProperty{
		newVisibilityProperty("default_visibility", func() []string {
			return p.properties.Default_visibility
		}),
	}
}

func (p *packageModule) Name() string {
	return p.properties.Name
}

func (p *packageModule) setName(name string) {
	p.properties.Name = name
}

// Counter to ensure package modules are created with a unique name within whatever namespace they
// belong.
var packageCount uint32 = 0

func PackageFactory() Module {
	module := &packageModule{}

	// Get a unique if for the package. Has to be done atomically as the creation of the modules are
	// done in parallel.
	id := atomic.AddUint32(&packageCount, 1)
	name := fmt.Sprintf("soong_package_%d", id)

	module.properties.Name = name

	module.AddProperties(&module.properties)
	return module
}

// Registers the function that renames the packages.
func registerPackageRenamer(ctx RegisterMutatorsContext) {
	ctx.BottomUp("packageRenamer", packageRenamer).Parallel()
	ctx.BottomUp("packageErrorReporter", packageErrorReporter).Parallel()
}

// Renames the package to match the package directory.
//
// This also creates a PackageInfo object for each package and uses that to detect and remember
// duplicates for later error reporting.
func packageRenamer(ctx BottomUpMutatorContext) {
	m, ok := ctx.Module().(*packageModule)
	if !ok {
		return
	}

	packageName := "//" + ctx.ModuleDir()

	pi := newPackageInfo(ctx, packageName, m)
	if pi.module != m {
		// Remember that the package was duplicated but do not rename as that will cause an error to
		// be logged with the generated name. Similarly, reporting the error here will use the generated
		// name as renames are only processed after this phase.
		pi.duplicated = true
	} else {
		// This is the first package module in this package so rename it to match the package name.
		m.setName(packageName)
		ctx.Rename(packageName)

		// Store a package info reference in the module.
		m.packageInfo = pi
	}
}

// Logs any deferred errors.
func packageErrorReporter(ctx BottomUpMutatorContext) {
	m, ok := ctx.Module().(*packageModule)
	if !ok {
		return
	}

	packageDir := ctx.ModuleDir()
	packageName := "//" + packageDir

	// Get the PackageInfo for the package. Should have been populated in the packageRenamer phase.
	pi := findPackageInfo(ctx, packageName)
	if pi == nil {
		ctx.ModuleErrorf("internal error, expected package info to be present for package '%s'",
			packageName)
		return
	}

	if pi.module != m {
		// The package module has been duplicated but this is not the module that has been renamed so
		// ignore it. An error will be logged for the renamed module which will ensure that the error
		// message uses the correct name.
		return
	}

	// Check to see whether there are duplicate package modules in the package.
	if pi.duplicated {
		ctx.ModuleErrorf("package {...} specified multiple times")
		return
	}
}

type defaultPackageInfoKey string

func newPackageInfo(
	ctx BaseModuleContext, packageName string, module *packageModule) *packageInfo {
	key := NewCustomOnceKey(defaultPackageInfoKey(packageName))

	return ctx.Config().Once(key, func() interface{} {
		return &packageInfo{module: module}
	}).(*packageInfo)
}

// Get the PackageInfo for the package name (starts with //, no trailing /), is nil if no package
// module type was specified.
func findPackageInfo(ctx BaseModuleContext, packageName string) *packageInfo {
	key := NewCustomOnceKey(defaultPackageInfoKey(packageName))

	pi := ctx.Config().Once(key, func() interface{} {
		return nil
	})

	if pi == nil {
		return nil
	} else {
		return pi.(*packageInfo)
	}
}
Loading