blob: 3b9ae3a87024916ea2e0f3dd0d902adaa54aa490 [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() {
Paul Duffin4fbfb592021-07-09 16:47:38 +010030 registerNamespaceBuildComponents(InitRegistrationContext)
31}
32
33func registerNamespaceBuildComponents(ctx RegistrationContext) {
34 ctx.RegisterModuleType("soong_namespace", NamespaceFactory)
Jeff Gaston088e29e2017-11-29 16:47:17 -080035}
36
37// threadsafe sorted list
38type sortedNamespaces struct {
39 lock sync.Mutex
40 items []*Namespace
41 sorted bool
42}
43
44func (s *sortedNamespaces) add(namespace *Namespace) {
45 s.lock.Lock()
46 defer s.lock.Unlock()
47 if s.sorted {
48 panic("It is not supported to call sortedNamespaces.add() after sortedNamespaces.sortedItems()")
49 }
50 s.items = append(s.items, namespace)
51}
52
53func (s *sortedNamespaces) sortedItems() []*Namespace {
54 s.lock.Lock()
55 defer s.lock.Unlock()
56 if !s.sorted {
57 less := func(i int, j int) bool {
58 return s.items[i].Path < s.items[j].Path
59 }
60 sort.Slice(s.items, less)
61 s.sorted = true
62 }
63 return s.items
64}
65
Jeff Gastonb274ed32017-12-01 17:10:33 -080066func (s *sortedNamespaces) index(namespace *Namespace) int {
67 for i, candidate := range s.sortedItems() {
68 if namespace == candidate {
69 return i
70 }
71 }
72 return -1
73}
74
Jeff Gaston088e29e2017-11-29 16:47:17 -080075// A NameResolver implements blueprint.NameInterface, and implements the logic to
76// find a module from namespaces based on a query string.
Usta Shresthac725f472022-01-11 02:44:21 -050077// A query string can be a module name or can be "//namespace_path:module_path"
Jeff Gaston088e29e2017-11-29 16:47:17 -080078type NameResolver struct {
79 rootNamespace *Namespace
80
81 // id counter for atomic.AddInt32
Jeff Gastonb274ed32017-12-01 17:10:33 -080082 nextNamespaceId int32
Jeff Gaston088e29e2017-11-29 16:47:17 -080083
84 // All namespaces, without duplicates.
85 sortedNamespaces sortedNamespaces
86
87 // Map from dir to namespace. Will have duplicates if two dirs are part of the same namespace.
88 namespacesByDir sync.Map // if generics were supported, this would be sync.Map[string]*Namespace
89
90 // func telling whether to export a namespace to Kati
91 namespaceExportFilter func(*Namespace) bool
92}
93
Paul Duffin3f7bf9f2022-11-08 12:21:15 +000094// NameResolverConfig provides the subset of the Config interface needed by the
95// NewNameResolver function.
96type NameResolverConfig interface {
97 // ExportedNamespaces is the list of namespaces that Soong must export to
98 // make.
99 ExportedNamespaces() []string
100}
101
102func NewNameResolver(config NameResolverConfig) *NameResolver {
103 namespacePathsToExport := make(map[string]bool)
104
105 for _, namespaceName := range config.ExportedNamespaces() {
106 namespacePathsToExport[namespaceName] = true
107 }
108
109 namespacePathsToExport["."] = true // always export the root namespace
110
111 namespaceExportFilter := func(namespace *Namespace) bool {
112 return namespacePathsToExport[namespace.Path]
113 }
114
Jeff Gaston088e29e2017-11-29 16:47:17 -0800115 r := &NameResolver{
Dan Willemsen59339a22018-07-22 21:18:45 -0700116 namespacesByDir: sync.Map{},
Jeff Gaston088e29e2017-11-29 16:47:17 -0800117 namespaceExportFilter: namespaceExportFilter,
118 }
119 r.rootNamespace = r.newNamespace(".")
120 r.rootNamespace.visibleNamespaces = []*Namespace{r.rootNamespace}
121 r.addNamespace(r.rootNamespace)
122
123 return r
124}
125
126func (r *NameResolver) newNamespace(path string) *Namespace {
127 namespace := NewNamespace(path)
128
129 namespace.exportToKati = r.namespaceExportFilter(namespace)
130
Jeff Gaston088e29e2017-11-29 16:47:17 -0800131 return namespace
132}
133
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800134func (r *NameResolver) addNewNamespaceForModule(module *NamespaceModule, path string) error {
135 fileName := filepath.Base(path)
136 if fileName != "Android.bp" {
137 return errors.New("A namespace may only be declared in a file named Android.bp")
138 }
139 dir := filepath.Dir(path)
140
Jeff Gaston088e29e2017-11-29 16:47:17 -0800141 namespace := r.newNamespace(dir)
142 module.namespace = namespace
143 module.resolver = r
144 namespace.importedNamespaceNames = module.properties.Imports
145 return r.addNamespace(namespace)
146}
147
148func (r *NameResolver) addNamespace(namespace *Namespace) (err error) {
149 existingNamespace, exists := r.namespaceAt(namespace.Path)
150 if exists {
151 if existingNamespace.Path == namespace.Path {
152 return fmt.Errorf("namespace %v already exists", namespace.Path)
153 } else {
154 // It would probably confuse readers if namespaces were declared anywhere but
155 // the top of the file, so we forbid declaring namespaces after anything else.
156 return fmt.Errorf("a namespace must be the first module in the file")
157 }
158 }
LuK1337422ed502022-01-16 20:44:58 +0100159 if (namespace.exportToKati) {
160 r.rootNamespace.visibleNamespaces = append(r.rootNamespace.visibleNamespaces, namespace)
161 }
Jeff Gaston088e29e2017-11-29 16:47:17 -0800162 r.sortedNamespaces.add(namespace)
163
164 r.namespacesByDir.Store(namespace.Path, namespace)
165 return nil
166}
167
168// non-recursive check for namespace
169func (r *NameResolver) namespaceAt(path string) (namespace *Namespace, found bool) {
170 mapVal, found := r.namespacesByDir.Load(path)
171 if !found {
172 return nil, false
173 }
174 return mapVal.(*Namespace), true
175}
176
177// recursive search upward for a namespace
178func (r *NameResolver) findNamespace(path string) (namespace *Namespace) {
179 namespace, found := r.namespaceAt(path)
180 if found {
181 return namespace
182 }
183 parentDir := filepath.Dir(path)
184 if parentDir == path {
185 return nil
186 }
187 namespace = r.findNamespace(parentDir)
188 r.namespacesByDir.Store(path, namespace)
189 return namespace
190}
191
Colin Crossa6389e92022-06-22 16:44:07 -0700192// A NamespacelessModule can never be looked up by name. It must still implement Name(), and the name
193// still has to be unique.
194type NamespacelessModule interface {
195 Namespaceless()
Colin Cross9d34f352019-11-22 16:03:51 -0800196}
197
Jeff Gaston088e29e2017-11-29 16:47:17 -0800198func (r *NameResolver) NewModule(ctx blueprint.NamespaceContext, moduleGroup blueprint.ModuleGroup, module blueprint.Module) (namespace blueprint.Namespace, errs []error) {
199 // if this module is a namespace, then save it to our list of namespaces
200 newNamespace, ok := module.(*NamespaceModule)
201 if ok {
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800202 err := r.addNewNamespaceForModule(newNamespace, ctx.ModulePath())
Jeff Gaston088e29e2017-11-29 16:47:17 -0800203 if err != nil {
204 return nil, []error{err}
205 }
206 return nil, nil
207 }
208
Colin Crossa6389e92022-06-22 16:44:07 -0700209 if _, ok := module.(NamespacelessModule); ok {
Colin Cross9d34f352019-11-22 16:03:51 -0800210 return nil, nil
211 }
212
Jeff Gaston088e29e2017-11-29 16:47:17 -0800213 // if this module is not a namespace, then save it into the appropriate namespace
214 ns := r.findNamespaceFromCtx(ctx)
215
216 _, errs = ns.moduleContainer.NewModule(ctx, moduleGroup, module)
217 if len(errs) > 0 {
218 return nil, errs
219 }
220
221 amod, ok := module.(Module)
222 if ok {
223 // inform the module whether its namespace is one that we want to export to Make
224 amod.base().commonProperties.NamespaceExportedToMake = ns.exportToKati
Colin Cross31a738b2019-12-30 18:45:15 -0800225 amod.base().commonProperties.DebugName = module.Name()
Jeff Gaston088e29e2017-11-29 16:47:17 -0800226 }
227
228 return ns, nil
229}
230
Sam Delmerico98a73292023-02-21 11:50:29 -0500231func (r *NameResolver) NewSkippedModule(ctx blueprint.NamespaceContext, name string, skipInfo blueprint.SkippedModuleInfo) {
232 r.rootNamespace.moduleContainer.NewSkippedModule(ctx, name, skipInfo)
233}
234
Jeff Gaston088e29e2017-11-29 16:47:17 -0800235func (r *NameResolver) AllModules() []blueprint.ModuleGroup {
236 childLists := [][]blueprint.ModuleGroup{}
237 totalCount := 0
238 for _, namespace := range r.sortedNamespaces.sortedItems() {
239 newModules := namespace.moduleContainer.AllModules()
240 totalCount += len(newModules)
241 childLists = append(childLists, newModules)
242 }
243
244 allModules := make([]blueprint.ModuleGroup, 0, totalCount)
245 for _, childList := range childLists {
246 allModules = append(allModules, childList...)
247 }
248 return allModules
249}
250
Sam Delmerico51211532023-03-30 14:21:42 -0400251func (r *NameResolver) SkippedModuleFromName(moduleName string, namespace blueprint.Namespace) (skipInfos []blueprint.SkippedModuleInfo, skipped bool) {
252 return r.rootNamespace.moduleContainer.SkippedModuleFromName(moduleName, namespace)
253}
254
Jeff Gaston088e29e2017-11-29 16:47:17 -0800255// parses a fully-qualified path (like "//namespace_path:module_name") into a namespace name and a
256// module name
257func (r *NameResolver) parseFullyQualifiedName(name string) (namespaceName string, moduleName string, ok bool) {
Paul Duffin2e61fa62019-03-28 14:10:57 +0000258 if !strings.HasPrefix(name, "//") {
Jeff Gaston088e29e2017-11-29 16:47:17 -0800259 return "", "", false
260 }
Paul Duffin2e61fa62019-03-28 14:10:57 +0000261 name = strings.TrimPrefix(name, "//")
262 components := strings.Split(name, ":")
Jeff Gaston088e29e2017-11-29 16:47:17 -0800263 if len(components) != 2 {
264 return "", "", false
265 }
266 return components[0], components[1], true
267
268}
269
Bob Badour38620ed2020-12-17 16:30:00 -0800270func (r *NameResolver) getNamespacesToSearchForModule(sourceNamespace blueprint.Namespace) (searchOrder []*Namespace) {
271 ns, ok := sourceNamespace.(*Namespace)
272 if !ok || ns.visibleNamespaces == nil {
Colin Crosscd84b4e2019-06-14 11:26:09 -0700273 // When handling dependencies before namespaceMutator, assume they are non-Soong Blueprint modules and give
274 // access to all namespaces.
275 return r.sortedNamespaces.sortedItems()
276 }
Bob Badour38620ed2020-12-17 16:30:00 -0800277 return ns.visibleNamespaces
Jeff Gaston088e29e2017-11-29 16:47:17 -0800278}
279
280func (r *NameResolver) ModuleFromName(name string, namespace blueprint.Namespace) (group blueprint.ModuleGroup, found bool) {
281 // handle fully qualified references like "//namespace_path:module_name"
282 nsName, moduleName, isAbs := r.parseFullyQualifiedName(name)
283 if isAbs {
284 namespace, found := r.namespaceAt(nsName)
285 if !found {
286 return blueprint.ModuleGroup{}, false
287 }
288 container := namespace.moduleContainer
289 return container.ModuleFromName(moduleName, nil)
290 }
Bob Badour38620ed2020-12-17 16:30:00 -0800291 for _, candidate := range r.getNamespacesToSearchForModule(namespace) {
Jeff Gaston088e29e2017-11-29 16:47:17 -0800292 group, found = candidate.moduleContainer.ModuleFromName(name, nil)
293 if found {
294 return group, true
295 }
296 }
297 return blueprint.ModuleGroup{}, false
298
299}
300
301func (r *NameResolver) Rename(oldName string, newName string, namespace blueprint.Namespace) []error {
Colin Crosseafb10c2018-04-16 13:58:10 -0700302 return namespace.(*Namespace).moduleContainer.Rename(oldName, newName, namespace)
Jeff Gaston088e29e2017-11-29 16:47:17 -0800303}
304
305// resolve each element of namespace.importedNamespaceNames and put the result in namespace.visibleNamespaces
306func (r *NameResolver) FindNamespaceImports(namespace *Namespace) (err error) {
307 namespace.visibleNamespaces = make([]*Namespace, 0, 2+len(namespace.importedNamespaceNames))
308 // search itself first
309 namespace.visibleNamespaces = append(namespace.visibleNamespaces, namespace)
310 // search its imports next
311 for _, name := range namespace.importedNamespaceNames {
312 imp, ok := r.namespaceAt(name)
313 if !ok {
Sam Delmerico98a73292023-02-21 11:50:29 -0500314 return fmt.Errorf("namespace %v does not exist; Some necessary modules may have been skipped by Soong. Check if PRODUCT_SOURCE_ROOT_DIRS is pruning necessary Android.bp files.", name)
Jeff Gaston088e29e2017-11-29 16:47:17 -0800315 }
316 namespace.visibleNamespaces = append(namespace.visibleNamespaces, imp)
317 }
318 // search the root namespace last
319 namespace.visibleNamespaces = append(namespace.visibleNamespaces, r.rootNamespace)
320 return nil
321}
322
Jeff Gastonb274ed32017-12-01 17:10:33 -0800323func (r *NameResolver) chooseId(namespace *Namespace) {
324 id := r.sortedNamespaces.index(namespace)
325 if id < 0 {
326 panic(fmt.Sprintf("Namespace not found: %v\n", namespace.id))
327 }
328 namespace.id = strconv.Itoa(id)
329}
330
Steven Moreland671dc232023-03-31 20:48:42 +0000331func (r *NameResolver) MissingDependencyError(depender string, dependerNamespace blueprint.Namespace, depName string, guess []string) (err error) {
332 text := fmt.Sprintf("%q depends on undefined module %q.", depender, depName)
Jeff Gaston088e29e2017-11-29 16:47:17 -0800333
334 _, _, isAbs := r.parseFullyQualifiedName(depName)
335 if isAbs {
336 // if the user gave a fully-qualified name, we don't need to look for other
337 // modules that they might have been referring to
338 return fmt.Errorf(text)
339 }
340
341 // determine which namespaces the module can be found in
342 foundInNamespaces := []string{}
Sam Delmerico51211532023-03-30 14:21:42 -0400343 skippedDepErrors := []error{}
Jeff Gaston088e29e2017-11-29 16:47:17 -0800344 for _, namespace := range r.sortedNamespaces.sortedItems() {
345 _, found := namespace.moduleContainer.ModuleFromName(depName, nil)
346 if found {
347 foundInNamespaces = append(foundInNamespaces, namespace.Path)
348 }
Sam Delmerico51211532023-03-30 14:21:42 -0400349 _, skipped := namespace.moduleContainer.SkippedModuleFromName(depName, nil)
350 if skipped {
Steven Moreland671dc232023-03-31 20:48:42 +0000351 skippedDepErrors = append(skippedDepErrors, namespace.moduleContainer.MissingDependencyError(depender, dependerNamespace, depName, nil))
Sam Delmerico51211532023-03-30 14:21:42 -0400352 }
Jeff Gaston088e29e2017-11-29 16:47:17 -0800353 }
Steven Moreland671dc232023-03-31 20:48:42 +0000354
Jeff Gaston088e29e2017-11-29 16:47:17 -0800355 if len(foundInNamespaces) > 0 {
356 // determine which namespaces are visible to dependerNamespace
357 dependerNs := dependerNamespace.(*Namespace)
358 searched := r.getNamespacesToSearchForModule(dependerNs)
359 importedNames := []string{}
360 for _, ns := range searched {
361 importedNames = append(importedNames, ns.Path)
362 }
363 text += fmt.Sprintf("\nModule %q is defined in namespace %q which can read these %v namespaces: %q", depender, dependerNs.Path, len(importedNames), importedNames)
364 text += fmt.Sprintf("\nModule %q can be found in these namespaces: %q", depName, foundInNamespaces)
365 }
Sam Delmerico51211532023-03-30 14:21:42 -0400366 for _, err := range skippedDepErrors {
367 text += fmt.Sprintf("\n%s", err.Error())
368 }
Jeff Gaston088e29e2017-11-29 16:47:17 -0800369
Steven Moreland671dc232023-03-31 20:48:42 +0000370 if len(guess) > 0 {
371 text += fmt.Sprintf("\nOr did you mean %q?", guess)
372 }
373
Jeff Gaston088e29e2017-11-29 16:47:17 -0800374 return fmt.Errorf(text)
375}
376
377func (r *NameResolver) GetNamespace(ctx blueprint.NamespaceContext) blueprint.Namespace {
378 return r.findNamespaceFromCtx(ctx)
379}
380
381func (r *NameResolver) findNamespaceFromCtx(ctx blueprint.NamespaceContext) *Namespace {
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800382 return r.findNamespace(filepath.Dir(ctx.ModulePath()))
Jeff Gaston088e29e2017-11-29 16:47:17 -0800383}
384
Jeff Gastonb274ed32017-12-01 17:10:33 -0800385func (r *NameResolver) UniqueName(ctx blueprint.NamespaceContext, name string) (unique string) {
386 prefix := r.findNamespaceFromCtx(ctx).id
387 if prefix != "" {
388 prefix = prefix + "-"
389 }
390 return prefix + name
391}
392
Jeff Gaston088e29e2017-11-29 16:47:17 -0800393var _ blueprint.NameInterface = (*NameResolver)(nil)
394
395type Namespace struct {
396 blueprint.NamespaceMarker
397 Path string
398
399 // names of namespaces listed as imports by this namespace
400 importedNamespaceNames []string
401 // all namespaces that should be searched when a module in this namespace declares a dependency
402 visibleNamespaces []*Namespace
403
404 id string
405
406 exportToKati bool
407
408 moduleContainer blueprint.NameInterface
409}
410
411func NewNamespace(path string) *Namespace {
412 return &Namespace{Path: path, moduleContainer: blueprint.NewSimpleNameInterface()}
413}
414
415var _ blueprint.Namespace = (*Namespace)(nil)
416
Patrice Arruda64765aa2019-03-13 09:36:46 -0700417type namespaceProperties struct {
418 // a list of namespaces that contain modules that will be referenced
419 // by modules in this namespace.
420 Imports []string `android:"path"`
421}
422
Jeff Gaston088e29e2017-11-29 16:47:17 -0800423type NamespaceModule struct {
424 ModuleBase
425
426 namespace *Namespace
427 resolver *NameResolver
428
Patrice Arruda64765aa2019-03-13 09:36:46 -0700429 properties namespaceProperties
Jeff Gaston088e29e2017-11-29 16:47:17 -0800430}
431
Jeff Gaston088e29e2017-11-29 16:47:17 -0800432func (n *NamespaceModule) GenerateAndroidBuildActions(ctx ModuleContext) {
433}
434
435func (n *NamespaceModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
436}
437
438func (n *NamespaceModule) Name() (name string) {
439 return *n.nameProperties.Name
440}
441
Patrice Arruda64765aa2019-03-13 09:36:46 -0700442// soong_namespace provides a scope to modules in an Android.bp file to prevent
443// module name conflicts with other defined modules in different Android.bp
444// files. Once soong_namespace has been defined in an Android.bp file, the
445// namespacing is applied to all modules that follow the soong_namespace in
446// the current Android.bp file, as well as modules defined in Android.bp files
447// in subdirectories. An Android.bp file in a subdirectory can define its own
448// soong_namespace which is applied to all its modules and as well as modules
449// defined in subdirectories Android.bp files. Modules in a soong_namespace are
450// visible to Make by listing the namespace path in PRODUCT_SOONG_NAMESPACES
451// make variable in a makefile.
Jeff Gaston088e29e2017-11-29 16:47:17 -0800452func NamespaceFactory() Module {
453 module := &NamespaceModule{}
454
455 name := "soong_namespace"
456 module.nameProperties.Name = &name
457
458 module.AddProperties(&module.properties)
459 return module
460}
461
462func RegisterNamespaceMutator(ctx RegisterMutatorsContext) {
Jeff Gastonb274ed32017-12-01 17:10:33 -0800463 ctx.BottomUp("namespace_deps", namespaceMutator).Parallel()
Jeff Gaston088e29e2017-11-29 16:47:17 -0800464}
465
Jeff Gastonb274ed32017-12-01 17:10:33 -0800466func namespaceMutator(ctx BottomUpMutatorContext) {
Jeff Gaston088e29e2017-11-29 16:47:17 -0800467 module, ok := ctx.Module().(*NamespaceModule)
468 if ok {
469 err := module.resolver.FindNamespaceImports(module.namespace)
470 if err != nil {
471 ctx.ModuleErrorf(err.Error())
472 }
Jeff Gastonb274ed32017-12-01 17:10:33 -0800473
474 module.resolver.chooseId(module.namespace)
Jeff Gaston088e29e2017-11-29 16:47:17 -0800475 }
476}