blob: 03f6a1e3d7085dbcd5188225cf0c2e65818980bf [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
67// Override to ensure that the default_visibility rules are checked by the visibility module during
68// its checking phase.
69func (p *packageModule) visibilityProperties() []visibilityProperty {
70 return []visibilityProperty{
71 newVisibilityProperty("default_visibility", func() []string {
72 return p.properties.Default_visibility
73 }),
74 }
75}
76
77func (p *packageModule) Name() string {
78 return p.properties.Name
79}
80
81func (p *packageModule) setName(name string) {
82 p.properties.Name = name
83}
84
85// Counter to ensure package modules are created with a unique name within whatever namespace they
86// belong.
87var packageCount uint32 = 0
88
89func PackageFactory() Module {
90 module := &packageModule{}
91
92 // Get a unique if for the package. Has to be done atomically as the creation of the modules are
93 // done in parallel.
94 id := atomic.AddUint32(&packageCount, 1)
95 name := fmt.Sprintf("soong_package_%d", id)
96
97 module.properties.Name = name
98
99 module.AddProperties(&module.properties)
100 return module
101}
102
103// Registers the function that renames the packages.
104func registerPackageRenamer(ctx RegisterMutatorsContext) {
105 ctx.BottomUp("packageRenamer", packageRenamer).Parallel()
106 ctx.BottomUp("packageErrorReporter", packageErrorReporter).Parallel()
107}
108
109// Renames the package to match the package directory.
110//
111// This also creates a PackageInfo object for each package and uses that to detect and remember
112// duplicates for later error reporting.
113func packageRenamer(ctx BottomUpMutatorContext) {
114 m, ok := ctx.Module().(*packageModule)
115 if !ok {
116 return
117 }
118
119 packageName := "//" + ctx.ModuleDir()
120
121 pi := newPackageInfo(ctx, packageName, m)
122 if pi.module != m {
123 // Remember that the package was duplicated but do not rename as that will cause an error to
124 // be logged with the generated name. Similarly, reporting the error here will use the generated
125 // name as renames are only processed after this phase.
126 pi.duplicated = true
127 } else {
128 // This is the first package module in this package so rename it to match the package name.
129 m.setName(packageName)
130 ctx.Rename(packageName)
131
132 // Store a package info reference in the module.
133 m.packageInfo = pi
134 }
135}
136
137// Logs any deferred errors.
138func packageErrorReporter(ctx BottomUpMutatorContext) {
139 m, ok := ctx.Module().(*packageModule)
140 if !ok {
141 return
142 }
143
144 packageDir := ctx.ModuleDir()
145 packageName := "//" + packageDir
146
147 // Get the PackageInfo for the package. Should have been populated in the packageRenamer phase.
148 pi := findPackageInfo(ctx, packageName)
149 if pi == nil {
150 ctx.ModuleErrorf("internal error, expected package info to be present for package '%s'",
151 packageName)
152 return
153 }
154
155 if pi.module != m {
156 // The package module has been duplicated but this is not the module that has been renamed so
157 // ignore it. An error will be logged for the renamed module which will ensure that the error
158 // message uses the correct name.
159 return
160 }
161
162 // Check to see whether there are duplicate package modules in the package.
163 if pi.duplicated {
164 ctx.ModuleErrorf("package {...} specified multiple times")
165 return
166 }
167}
168
169type defaultPackageInfoKey string
170
171func newPackageInfo(
172 ctx BaseModuleContext, packageName string, module *packageModule) *packageInfo {
173 key := NewCustomOnceKey(defaultPackageInfoKey(packageName))
174
175 return ctx.Config().Once(key, func() interface{} {
176 return &packageInfo{module: module}
177 }).(*packageInfo)
178}
179
180// Get the PackageInfo for the package name (starts with //, no trailing /), is nil if no package
181// module type was specified.
182func findPackageInfo(ctx BaseModuleContext, packageName string) *packageInfo {
183 key := NewCustomOnceKey(defaultPackageInfoKey(packageName))
184
185 pi := ctx.Config().Once(key, func() interface{} {
186 return nil
187 })
188
189 if pi == nil {
190 return nil
191 } else {
192 return pi.(*packageInfo)
193 }
194}