blob: ccda7c45a8cf1b7e459c3dbe17f7cd5990d31fd3 [file] [log] [blame]
Jeff Gaston088e29e2017-11-29 16:47:17 -08001// Copyright 2017 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 (
Jeff Gaston5c3886d2017-11-30 16:46:47 -080018 "errors"
Jeff Gaston088e29e2017-11-29 16:47:17 -080019 "fmt"
20 "path/filepath"
21 "sort"
22 "strconv"
23 "strings"
24 "sync"
Jeff Gaston088e29e2017-11-29 16:47:17 -080025
26 "github.com/google/blueprint"
27)
28
Jeff Gaston088e29e2017-11-29 16:47:17 -080029func init() {
30 RegisterModuleType("soong_namespace", NamespaceFactory)
31}
32
33// threadsafe sorted list
34type sortedNamespaces struct {
35 lock sync.Mutex
36 items []*Namespace
37 sorted bool
38}
39
40func (s *sortedNamespaces) add(namespace *Namespace) {
41 s.lock.Lock()
42 defer s.lock.Unlock()
43 if s.sorted {
44 panic("It is not supported to call sortedNamespaces.add() after sortedNamespaces.sortedItems()")
45 }
46 s.items = append(s.items, namespace)
47}
48
49func (s *sortedNamespaces) sortedItems() []*Namespace {
50 s.lock.Lock()
51 defer s.lock.Unlock()
52 if !s.sorted {
53 less := func(i int, j int) bool {
54 return s.items[i].Path < s.items[j].Path
55 }
56 sort.Slice(s.items, less)
57 s.sorted = true
58 }
59 return s.items
60}
61
Jeff Gastonb274ed32017-12-01 17:10:33 -080062func (s *sortedNamespaces) index(namespace *Namespace) int {
63 for i, candidate := range s.sortedItems() {
64 if namespace == candidate {
65 return i
66 }
67 }
68 return -1
69}
70
Jeff Gaston088e29e2017-11-29 16:47:17 -080071// A NameResolver implements blueprint.NameInterface, and implements the logic to
72// find a module from namespaces based on a query string.
73// A query string can be a module name or can be be "//namespace_path:module_path"
74type NameResolver struct {
75 rootNamespace *Namespace
76
77 // id counter for atomic.AddInt32
Jeff Gastonb274ed32017-12-01 17:10:33 -080078 nextNamespaceId int32
Jeff Gaston088e29e2017-11-29 16:47:17 -080079
80 // All namespaces, without duplicates.
81 sortedNamespaces sortedNamespaces
82
83 // Map from dir to namespace. Will have duplicates if two dirs are part of the same namespace.
84 namespacesByDir sync.Map // if generics were supported, this would be sync.Map[string]*Namespace
85
86 // func telling whether to export a namespace to Kati
87 namespaceExportFilter func(*Namespace) bool
88}
89
90func NewNameResolver(namespaceExportFilter func(*Namespace) bool) *NameResolver {
Jeff Gaston088e29e2017-11-29 16:47:17 -080091 r := &NameResolver{
Dan Willemsen59339a22018-07-22 21:18:45 -070092 namespacesByDir: sync.Map{},
Jeff Gaston088e29e2017-11-29 16:47:17 -080093 namespaceExportFilter: namespaceExportFilter,
94 }
95 r.rootNamespace = r.newNamespace(".")
96 r.rootNamespace.visibleNamespaces = []*Namespace{r.rootNamespace}
97 r.addNamespace(r.rootNamespace)
98
99 return r
100}
101
102func (r *NameResolver) newNamespace(path string) *Namespace {
103 namespace := NewNamespace(path)
104
105 namespace.exportToKati = r.namespaceExportFilter(namespace)
106
Jeff Gaston088e29e2017-11-29 16:47:17 -0800107 return namespace
108}
109
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800110func (r *NameResolver) addNewNamespaceForModule(module *NamespaceModule, path string) error {
111 fileName := filepath.Base(path)
112 if fileName != "Android.bp" {
113 return errors.New("A namespace may only be declared in a file named Android.bp")
114 }
115 dir := filepath.Dir(path)
116
Jeff Gaston088e29e2017-11-29 16:47:17 -0800117 namespace := r.newNamespace(dir)
118 module.namespace = namespace
119 module.resolver = r
120 namespace.importedNamespaceNames = module.properties.Imports
121 return r.addNamespace(namespace)
122}
123
124func (r *NameResolver) addNamespace(namespace *Namespace) (err error) {
125 existingNamespace, exists := r.namespaceAt(namespace.Path)
126 if exists {
127 if existingNamespace.Path == namespace.Path {
128 return fmt.Errorf("namespace %v already exists", namespace.Path)
129 } else {
130 // It would probably confuse readers if namespaces were declared anywhere but
131 // the top of the file, so we forbid declaring namespaces after anything else.
132 return fmt.Errorf("a namespace must be the first module in the file")
133 }
134 }
LuK1337fdcabeb2022-01-16 20:44:58 +0100135 if (namespace.exportToKati) {
136 r.rootNamespace.visibleNamespaces = append(r.rootNamespace.visibleNamespaces, namespace)
137 }
Jeff Gaston088e29e2017-11-29 16:47:17 -0800138 r.sortedNamespaces.add(namespace)
139
140 r.namespacesByDir.Store(namespace.Path, namespace)
141 return nil
142}
143
144// non-recursive check for namespace
145func (r *NameResolver) namespaceAt(path string) (namespace *Namespace, found bool) {
146 mapVal, found := r.namespacesByDir.Load(path)
147 if !found {
148 return nil, false
149 }
150 return mapVal.(*Namespace), true
151}
152
153// recursive search upward for a namespace
154func (r *NameResolver) findNamespace(path string) (namespace *Namespace) {
155 namespace, found := r.namespaceAt(path)
156 if found {
157 return namespace
158 }
159 parentDir := filepath.Dir(path)
160 if parentDir == path {
161 return nil
162 }
163 namespace = r.findNamespace(parentDir)
164 r.namespacesByDir.Store(path, namespace)
165 return namespace
166}
167
Colin Cross9d34f352019-11-22 16:03:51 -0800168// A NamelessModule can never be looked up by name. It must still implement Name(), but the return
169// value doesn't have to be unique.
170type NamelessModule interface {
171 Nameless()
172}
173
Jeff Gaston088e29e2017-11-29 16:47:17 -0800174func (r *NameResolver) NewModule(ctx blueprint.NamespaceContext, moduleGroup blueprint.ModuleGroup, module blueprint.Module) (namespace blueprint.Namespace, errs []error) {
175 // if this module is a namespace, then save it to our list of namespaces
176 newNamespace, ok := module.(*NamespaceModule)
177 if ok {
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800178 err := r.addNewNamespaceForModule(newNamespace, ctx.ModulePath())
Jeff Gaston088e29e2017-11-29 16:47:17 -0800179 if err != nil {
180 return nil, []error{err}
181 }
182 return nil, nil
183 }
184
Colin Cross9d34f352019-11-22 16:03:51 -0800185 if _, ok := module.(NamelessModule); ok {
186 return nil, nil
187 }
188
Jeff Gaston088e29e2017-11-29 16:47:17 -0800189 // if this module is not a namespace, then save it into the appropriate namespace
190 ns := r.findNamespaceFromCtx(ctx)
191
192 _, errs = ns.moduleContainer.NewModule(ctx, moduleGroup, module)
193 if len(errs) > 0 {
194 return nil, errs
195 }
196
197 amod, ok := module.(Module)
198 if ok {
199 // inform the module whether its namespace is one that we want to export to Make
200 amod.base().commonProperties.NamespaceExportedToMake = ns.exportToKati
Colin Cross31a738b2019-12-30 18:45:15 -0800201 amod.base().commonProperties.DebugName = module.Name()
Jeff Gaston088e29e2017-11-29 16:47:17 -0800202 }
203
204 return ns, nil
205}
206
207func (r *NameResolver) AllModules() []blueprint.ModuleGroup {
208 childLists := [][]blueprint.ModuleGroup{}
209 totalCount := 0
210 for _, namespace := range r.sortedNamespaces.sortedItems() {
211 newModules := namespace.moduleContainer.AllModules()
212 totalCount += len(newModules)
213 childLists = append(childLists, newModules)
214 }
215
216 allModules := make([]blueprint.ModuleGroup, 0, totalCount)
217 for _, childList := range childLists {
218 allModules = append(allModules, childList...)
219 }
220 return allModules
221}
222
223// parses a fully-qualified path (like "//namespace_path:module_name") into a namespace name and a
224// module name
225func (r *NameResolver) parseFullyQualifiedName(name string) (namespaceName string, moduleName string, ok bool) {
Paul Duffin2e61fa62019-03-28 14:10:57 +0000226 if !strings.HasPrefix(name, "//") {
Jeff Gaston088e29e2017-11-29 16:47:17 -0800227 return "", "", false
228 }
Paul Duffin2e61fa62019-03-28 14:10:57 +0000229 name = strings.TrimPrefix(name, "//")
230 components := strings.Split(name, ":")
Jeff Gaston088e29e2017-11-29 16:47:17 -0800231 if len(components) != 2 {
232 return "", "", false
233 }
234 return components[0], components[1], true
235
236}
237
Bob Badour38620ed2020-12-17 16:30:00 -0800238func (r *NameResolver) getNamespacesToSearchForModule(sourceNamespace blueprint.Namespace) (searchOrder []*Namespace) {
239 ns, ok := sourceNamespace.(*Namespace)
240 if !ok || ns.visibleNamespaces == nil {
Colin Crosscd84b4e2019-06-14 11:26:09 -0700241 // When handling dependencies before namespaceMutator, assume they are non-Soong Blueprint modules and give
242 // access to all namespaces.
243 return r.sortedNamespaces.sortedItems()
244 }
Bob Badour38620ed2020-12-17 16:30:00 -0800245 return ns.visibleNamespaces
Jeff Gaston088e29e2017-11-29 16:47:17 -0800246}
247
248func (r *NameResolver) ModuleFromName(name string, namespace blueprint.Namespace) (group blueprint.ModuleGroup, found bool) {
249 // handle fully qualified references like "//namespace_path:module_name"
250 nsName, moduleName, isAbs := r.parseFullyQualifiedName(name)
251 if isAbs {
252 namespace, found := r.namespaceAt(nsName)
253 if !found {
254 return blueprint.ModuleGroup{}, false
255 }
256 container := namespace.moduleContainer
257 return container.ModuleFromName(moduleName, nil)
258 }
Bob Badour38620ed2020-12-17 16:30:00 -0800259 for _, candidate := range r.getNamespacesToSearchForModule(namespace) {
Jeff Gaston088e29e2017-11-29 16:47:17 -0800260 group, found = candidate.moduleContainer.ModuleFromName(name, nil)
261 if found {
262 return group, true
263 }
264 }
265 return blueprint.ModuleGroup{}, false
266
267}
268
269func (r *NameResolver) Rename(oldName string, newName string, namespace blueprint.Namespace) []error {
Colin Crosseafb10c2018-04-16 13:58:10 -0700270 return namespace.(*Namespace).moduleContainer.Rename(oldName, newName, namespace)
Jeff Gaston088e29e2017-11-29 16:47:17 -0800271}
272
273// resolve each element of namespace.importedNamespaceNames and put the result in namespace.visibleNamespaces
274func (r *NameResolver) FindNamespaceImports(namespace *Namespace) (err error) {
275 namespace.visibleNamespaces = make([]*Namespace, 0, 2+len(namespace.importedNamespaceNames))
276 // search itself first
277 namespace.visibleNamespaces = append(namespace.visibleNamespaces, namespace)
278 // search its imports next
279 for _, name := range namespace.importedNamespaceNames {
280 imp, ok := r.namespaceAt(name)
281 if !ok {
282 return fmt.Errorf("namespace %v does not exist", name)
283 }
284 namespace.visibleNamespaces = append(namespace.visibleNamespaces, imp)
285 }
286 // search the root namespace last
287 namespace.visibleNamespaces = append(namespace.visibleNamespaces, r.rootNamespace)
288 return nil
289}
290
Jeff Gastonb274ed32017-12-01 17:10:33 -0800291func (r *NameResolver) chooseId(namespace *Namespace) {
292 id := r.sortedNamespaces.index(namespace)
293 if id < 0 {
294 panic(fmt.Sprintf("Namespace not found: %v\n", namespace.id))
295 }
296 namespace.id = strconv.Itoa(id)
297}
298
Jeff Gaston088e29e2017-11-29 16:47:17 -0800299func (r *NameResolver) MissingDependencyError(depender string, dependerNamespace blueprint.Namespace, depName string) (err error) {
300 text := fmt.Sprintf("%q depends on undefined module %q", depender, depName)
301
302 _, _, isAbs := r.parseFullyQualifiedName(depName)
303 if isAbs {
304 // if the user gave a fully-qualified name, we don't need to look for other
305 // modules that they might have been referring to
306 return fmt.Errorf(text)
307 }
308
309 // determine which namespaces the module can be found in
310 foundInNamespaces := []string{}
311 for _, namespace := range r.sortedNamespaces.sortedItems() {
312 _, found := namespace.moduleContainer.ModuleFromName(depName, nil)
313 if found {
314 foundInNamespaces = append(foundInNamespaces, namespace.Path)
315 }
316 }
317 if len(foundInNamespaces) > 0 {
318 // determine which namespaces are visible to dependerNamespace
319 dependerNs := dependerNamespace.(*Namespace)
320 searched := r.getNamespacesToSearchForModule(dependerNs)
321 importedNames := []string{}
322 for _, ns := range searched {
323 importedNames = append(importedNames, ns.Path)
324 }
325 text += fmt.Sprintf("\nModule %q is defined in namespace %q which can read these %v namespaces: %q", depender, dependerNs.Path, len(importedNames), importedNames)
326 text += fmt.Sprintf("\nModule %q can be found in these namespaces: %q", depName, foundInNamespaces)
327 }
328
329 return fmt.Errorf(text)
330}
331
332func (r *NameResolver) GetNamespace(ctx blueprint.NamespaceContext) blueprint.Namespace {
333 return r.findNamespaceFromCtx(ctx)
334}
335
336func (r *NameResolver) findNamespaceFromCtx(ctx blueprint.NamespaceContext) *Namespace {
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800337 return r.findNamespace(filepath.Dir(ctx.ModulePath()))
Jeff Gaston088e29e2017-11-29 16:47:17 -0800338}
339
Jeff Gastonb274ed32017-12-01 17:10:33 -0800340func (r *NameResolver) UniqueName(ctx blueprint.NamespaceContext, name string) (unique string) {
341 prefix := r.findNamespaceFromCtx(ctx).id
342 if prefix != "" {
343 prefix = prefix + "-"
344 }
345 return prefix + name
346}
347
Jeff Gaston088e29e2017-11-29 16:47:17 -0800348var _ blueprint.NameInterface = (*NameResolver)(nil)
349
350type Namespace struct {
351 blueprint.NamespaceMarker
352 Path string
353
354 // names of namespaces listed as imports by this namespace
355 importedNamespaceNames []string
356 // all namespaces that should be searched when a module in this namespace declares a dependency
357 visibleNamespaces []*Namespace
358
359 id string
360
361 exportToKati bool
362
363 moduleContainer blueprint.NameInterface
364}
365
366func NewNamespace(path string) *Namespace {
367 return &Namespace{Path: path, moduleContainer: blueprint.NewSimpleNameInterface()}
368}
369
370var _ blueprint.Namespace = (*Namespace)(nil)
371
Patrice Arruda64765aa2019-03-13 09:36:46 -0700372type namespaceProperties struct {
373 // a list of namespaces that contain modules that will be referenced
374 // by modules in this namespace.
375 Imports []string `android:"path"`
376}
377
Jeff Gaston088e29e2017-11-29 16:47:17 -0800378type NamespaceModule struct {
379 ModuleBase
380
381 namespace *Namespace
382 resolver *NameResolver
383
Patrice Arruda64765aa2019-03-13 09:36:46 -0700384 properties namespaceProperties
Jeff Gaston088e29e2017-11-29 16:47:17 -0800385}
386
Jeff Gaston088e29e2017-11-29 16:47:17 -0800387func (n *NamespaceModule) GenerateAndroidBuildActions(ctx ModuleContext) {
388}
389
390func (n *NamespaceModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
391}
392
393func (n *NamespaceModule) Name() (name string) {
394 return *n.nameProperties.Name
395}
396
Patrice Arruda64765aa2019-03-13 09:36:46 -0700397// soong_namespace provides a scope to modules in an Android.bp file to prevent
398// module name conflicts with other defined modules in different Android.bp
399// files. Once soong_namespace has been defined in an Android.bp file, the
400// namespacing is applied to all modules that follow the soong_namespace in
401// the current Android.bp file, as well as modules defined in Android.bp files
402// in subdirectories. An Android.bp file in a subdirectory can define its own
403// soong_namespace which is applied to all its modules and as well as modules
404// defined in subdirectories Android.bp files. Modules in a soong_namespace are
405// visible to Make by listing the namespace path in PRODUCT_SOONG_NAMESPACES
406// make variable in a makefile.
Jeff Gaston088e29e2017-11-29 16:47:17 -0800407func NamespaceFactory() Module {
408 module := &NamespaceModule{}
409
410 name := "soong_namespace"
411 module.nameProperties.Name = &name
412
413 module.AddProperties(&module.properties)
414 return module
415}
416
417func RegisterNamespaceMutator(ctx RegisterMutatorsContext) {
Jeff Gastonb274ed32017-12-01 17:10:33 -0800418 ctx.BottomUp("namespace_deps", namespaceMutator).Parallel()
Jeff Gaston088e29e2017-11-29 16:47:17 -0800419}
420
Jeff Gastonb274ed32017-12-01 17:10:33 -0800421func namespaceMutator(ctx BottomUpMutatorContext) {
Jeff Gaston088e29e2017-11-29 16:47:17 -0800422 module, ok := ctx.Module().(*NamespaceModule)
423 if ok {
424 err := module.resolver.FindNamespaceImports(module.namespace)
425 if err != nil {
426 ctx.ModuleErrorf(err.Error())
427 }
Jeff Gastonb274ed32017-12-01 17:10:33 -0800428
429 module.resolver.chooseId(module.namespace)
Jeff Gaston088e29e2017-11-29 16:47:17 -0800430 }
431}