blob: 880d6a97bcecb15c12777fe22acaa80f121e2e15 [file] [log] [blame]
Paul Duffine2453c72019-05-31 14:00:04 +01001// Copyright 2019 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package android
16
17import (
18 "fmt"
19 "sync/atomic"
20
21 "github.com/google/blueprint"
22)
23
24func init() {
25 RegisterModuleType("package", PackageFactory)
26}
27
28// The information maintained about each package.
29type packageInfo struct {
30 // The module from which this information was populated. If `duplicated` = true then this is the
31 // module that has been renamed and must be used to report errors.
32 module *packageModule
33
34 // If true this indicates that there are two package statements in the same package which is not
35 // allowed and will cause the build to fail. This flag is set by packageRenamer and checked in
36 // packageErrorReporter
37 duplicated bool
38}
39
40type packageProperties struct {
41 Name string `blueprint:"mutated"`
42
43 // Specifies the default visibility for all modules defined in this package.
44 Default_visibility []string
45}
46
47type packageModule struct {
48 ModuleBase
49
50 properties packageProperties
51 packageInfo *packageInfo
52}
53
54func (p *packageModule) GenerateAndroidBuildActions(ModuleContext) {
55 // Nothing to do.
56}
57
58func (p *packageModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
59 // Nothing to do.
60}
61
62func (p *packageModule) qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleName {
63 // Override to create a package id.
64 return newPackageId(ctx.ModuleDir())
65}
66
Paul Duffine2453c72019-05-31 14:00:04 +010067func (p *packageModule) Name() string {
68 return p.properties.Name
69}
70
71func (p *packageModule) setName(name string) {
72 p.properties.Name = name
73}
74
75// Counter to ensure package modules are created with a unique name within whatever namespace they
76// belong.
77var packageCount uint32 = 0
78
79func PackageFactory() Module {
80 module := &packageModule{}
81
82 // Get a unique if for the package. Has to be done atomically as the creation of the modules are
83 // done in parallel.
84 id := atomic.AddUint32(&packageCount, 1)
85 name := fmt.Sprintf("soong_package_%d", id)
86
87 module.properties.Name = name
88
89 module.AddProperties(&module.properties)
Paul Duffin63c6e182019-07-24 14:24:38 +010090
91 // The default_visibility property needs to be checked and parsed by the visibility module during
92 // its checking and parsing phases.
93 module.primaryVisibilityProperty =
94 newVisibilityProperty("default_visibility", &module.properties.Default_visibility)
95 module.visibilityPropertyInfo = []visibilityProperty{module.primaryVisibilityProperty}
96
Paul Duffine2453c72019-05-31 14:00:04 +010097 return module
98}
99
100// Registers the function that renames the packages.
101func registerPackageRenamer(ctx RegisterMutatorsContext) {
102 ctx.BottomUp("packageRenamer", packageRenamer).Parallel()
103 ctx.BottomUp("packageErrorReporter", packageErrorReporter).Parallel()
104}
105
106// Renames the package to match the package directory.
107//
108// This also creates a PackageInfo object for each package and uses that to detect and remember
109// duplicates for later error reporting.
110func packageRenamer(ctx BottomUpMutatorContext) {
111 m, ok := ctx.Module().(*packageModule)
112 if !ok {
113 return
114 }
115
116 packageName := "//" + ctx.ModuleDir()
117
118 pi := newPackageInfo(ctx, packageName, m)
119 if pi.module != m {
120 // Remember that the package was duplicated but do not rename as that will cause an error to
121 // be logged with the generated name. Similarly, reporting the error here will use the generated
122 // name as renames are only processed after this phase.
123 pi.duplicated = true
124 } else {
125 // This is the first package module in this package so rename it to match the package name.
126 m.setName(packageName)
127 ctx.Rename(packageName)
128
129 // Store a package info reference in the module.
130 m.packageInfo = pi
131 }
132}
133
134// Logs any deferred errors.
135func packageErrorReporter(ctx BottomUpMutatorContext) {
136 m, ok := ctx.Module().(*packageModule)
137 if !ok {
138 return
139 }
140
141 packageDir := ctx.ModuleDir()
142 packageName := "//" + packageDir
143
144 // Get the PackageInfo for the package. Should have been populated in the packageRenamer phase.
145 pi := findPackageInfo(ctx, packageName)
146 if pi == nil {
147 ctx.ModuleErrorf("internal error, expected package info to be present for package '%s'",
148 packageName)
149 return
150 }
151
152 if pi.module != m {
153 // The package module has been duplicated but this is not the module that has been renamed so
154 // ignore it. An error will be logged for the renamed module which will ensure that the error
155 // message uses the correct name.
156 return
157 }
158
159 // Check to see whether there are duplicate package modules in the package.
160 if pi.duplicated {
161 ctx.ModuleErrorf("package {...} specified multiple times")
162 return
163 }
164}
165
166type defaultPackageInfoKey string
167
168func newPackageInfo(
169 ctx BaseModuleContext, packageName string, module *packageModule) *packageInfo {
170 key := NewCustomOnceKey(defaultPackageInfoKey(packageName))
171
172 return ctx.Config().Once(key, func() interface{} {
173 return &packageInfo{module: module}
174 }).(*packageInfo)
175}
176
177// Get the PackageInfo for the package name (starts with //, no trailing /), is nil if no package
178// module type was specified.
179func findPackageInfo(ctx BaseModuleContext, packageName string) *packageInfo {
180 key := NewCustomOnceKey(defaultPackageInfoKey(packageName))
181
182 pi := ctx.Config().Once(key, func() interface{} {
183 return nil
184 })
185
186 if pi == nil {
187 return nil
188 } else {
189 return pi.(*packageInfo)
190 }
191}