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