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 29func 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 62func (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 71// 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 78 nextNamespaceId int32 79 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 { 91 r := &NameResolver{ 92 namespacesByDir: sync.Map{}, 93 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 107 return namespace 108} 109 110func (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 117 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 } 135 r.sortedNamespaces.add(namespace) 136 137 r.namespacesByDir.Store(namespace.Path, namespace) 138 return nil 139} 140 141// non-recursive check for namespace 142func (r *NameResolver) namespaceAt(path string) (namespace *Namespace, found bool) { 143 mapVal, found := r.namespacesByDir.Load(path) 144 if !found { 145 return nil, false 146 } 147 return mapVal.(*Namespace), true 148} 149 150// recursive search upward for a namespace 151func (r *NameResolver) findNamespace(path string) (namespace *Namespace) { 152 namespace, found := r.namespaceAt(path) 153 if found { 154 return namespace 155 } 156 parentDir := filepath.Dir(path) 157 if parentDir == path { 158 return nil 159 } 160 namespace = r.findNamespace(parentDir) 161 r.namespacesByDir.Store(path, namespace) 162 return namespace 163} 164 165// A NamelessModule can never be looked up by name. It must still implement Name(), but the return 166// value doesn't have to be unique. 167type NamelessModule interface { 168 Nameless() 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 _, ok := module.(NamelessModule); ok { 183 return nil, nil 184 } 185 186 // if this module is not a namespace, then save it into the appropriate namespace 187 ns := r.findNamespaceFromCtx(ctx) 188 189 _, errs = ns.moduleContainer.NewModule(ctx, moduleGroup, module) 190 if len(errs) > 0 { 191 return nil, errs 192 } 193 194 amod, ok := module.(Module) 195 if ok { 196 // inform the module whether its namespace is one that we want to export to Make 197 amod.base().commonProperties.NamespaceExportedToMake = ns.exportToKati 198 amod.base().commonProperties.DebugName = module.Name() 199 } 200 201 return ns, nil 202} 203 204func (r *NameResolver) AllModules() []blueprint.ModuleGroup { 205 childLists := [][]blueprint.ModuleGroup{} 206 totalCount := 0 207 for _, namespace := range r.sortedNamespaces.sortedItems() { 208 newModules := namespace.moduleContainer.AllModules() 209 totalCount += len(newModules) 210 childLists = append(childLists, newModules) 211 } 212 213 allModules := make([]blueprint.ModuleGroup, 0, totalCount) 214 for _, childList := range childLists { 215 allModules = append(allModules, childList...) 216 } 217 return allModules 218} 219 220// parses a fully-qualified path (like "//namespace_path:module_name") into a namespace name and a 221// module name 222func (r *NameResolver) parseFullyQualifiedName(name string) (namespaceName string, moduleName string, ok bool) { 223 if !strings.HasPrefix(name, "//") { 224 return "", "", false 225 } 226 name = strings.TrimPrefix(name, "//") 227 components := strings.Split(name, ":") 228 if len(components) != 2 { 229 return "", "", false 230 } 231 return components[0], components[1], true 232 233} 234 235func (r *NameResolver) getNamespacesToSearchForModule(sourceNamespace blueprint.Namespace) (searchOrder []*Namespace) { 236 ns, ok := sourceNamespace.(*Namespace) 237 if !ok || ns.visibleNamespaces == nil { 238 // When handling dependencies before namespaceMutator, assume they are non-Soong Blueprint modules and give 239 // access to all namespaces. 240 return r.sortedNamespaces.sortedItems() 241 } 242 return ns.visibleNamespaces 243} 244 245func (r *NameResolver) ModuleFromName(name string, namespace blueprint.Namespace) (group blueprint.ModuleGroup, found bool) { 246 // handle fully qualified references like "//namespace_path:module_name" 247 nsName, moduleName, isAbs := r.parseFullyQualifiedName(name) 248 if isAbs { 249 namespace, found := r.namespaceAt(nsName) 250 if !found { 251 return blueprint.ModuleGroup{}, false 252 } 253 container := namespace.moduleContainer 254 return container.ModuleFromName(moduleName, nil) 255 } 256 for _, candidate := range r.getNamespacesToSearchForModule(namespace) { 257 group, found = candidate.moduleContainer.ModuleFromName(name, nil) 258 if found { 259 return group, true 260 } 261 } 262 return blueprint.ModuleGroup{}, false 263 264} 265 266func (r *NameResolver) Rename(oldName string, newName string, namespace blueprint.Namespace) []error { 267 return namespace.(*Namespace).moduleContainer.Rename(oldName, newName, namespace) 268} 269 270// resolve each element of namespace.importedNamespaceNames and put the result in namespace.visibleNamespaces 271func (r *NameResolver) FindNamespaceImports(namespace *Namespace) (err error) { 272 namespace.visibleNamespaces = make([]*Namespace, 0, 2+len(namespace.importedNamespaceNames)) 273 // search itself first 274 namespace.visibleNamespaces = append(namespace.visibleNamespaces, namespace) 275 // search its imports next 276 for _, name := range namespace.importedNamespaceNames { 277 imp, ok := r.namespaceAt(name) 278 if !ok { 279 return fmt.Errorf("namespace %v does not exist", name) 280 } 281 namespace.visibleNamespaces = append(namespace.visibleNamespaces, imp) 282 } 283 // search the root namespace last 284 namespace.visibleNamespaces = append(namespace.visibleNamespaces, r.rootNamespace) 285 return nil 286} 287 288func (r *NameResolver) chooseId(namespace *Namespace) { 289 id := r.sortedNamespaces.index(namespace) 290 if id < 0 { 291 panic(fmt.Sprintf("Namespace not found: %v\n", namespace.id)) 292 } 293 namespace.id = strconv.Itoa(id) 294} 295 296func (r *NameResolver) MissingDependencyError(depender string, dependerNamespace blueprint.Namespace, depName string) (err error) { 297 text := fmt.Sprintf("%q depends on undefined module %q", depender, depName) 298 299 _, _, isAbs := r.parseFullyQualifiedName(depName) 300 if isAbs { 301 // if the user gave a fully-qualified name, we don't need to look for other 302 // modules that they might have been referring to 303 return fmt.Errorf(text) 304 } 305 306 // determine which namespaces the module can be found in 307 foundInNamespaces := []string{} 308 for _, namespace := range r.sortedNamespaces.sortedItems() { 309 _, found := namespace.moduleContainer.ModuleFromName(depName, nil) 310 if found { 311 foundInNamespaces = append(foundInNamespaces, namespace.Path) 312 } 313 } 314 if len(foundInNamespaces) > 0 { 315 // determine which namespaces are visible to dependerNamespace 316 dependerNs := dependerNamespace.(*Namespace) 317 searched := r.getNamespacesToSearchForModule(dependerNs) 318 importedNames := []string{} 319 for _, ns := range searched { 320 importedNames = append(importedNames, ns.Path) 321 } 322 text += fmt.Sprintf("\nModule %q is defined in namespace %q which can read these %v namespaces: %q", depender, dependerNs.Path, len(importedNames), importedNames) 323 text += fmt.Sprintf("\nModule %q can be found in these namespaces: %q", depName, foundInNamespaces) 324 } 325 326 return fmt.Errorf(text) 327} 328 329func (r *NameResolver) GetNamespace(ctx blueprint.NamespaceContext) blueprint.Namespace { 330 return r.findNamespaceFromCtx(ctx) 331} 332 333func (r *NameResolver) findNamespaceFromCtx(ctx blueprint.NamespaceContext) *Namespace { 334 return r.findNamespace(filepath.Dir(ctx.ModulePath())) 335} 336 337func (r *NameResolver) UniqueName(ctx blueprint.NamespaceContext, name string) (unique string) { 338 prefix := r.findNamespaceFromCtx(ctx).id 339 if prefix != "" { 340 prefix = prefix + "-" 341 } 342 return prefix + name 343} 344 345var _ blueprint.NameInterface = (*NameResolver)(nil) 346 347type Namespace struct { 348 blueprint.NamespaceMarker 349 Path string 350 351 // names of namespaces listed as imports by this namespace 352 importedNamespaceNames []string 353 // all namespaces that should be searched when a module in this namespace declares a dependency 354 visibleNamespaces []*Namespace 355 356 id string 357 358 exportToKati bool 359 360 moduleContainer blueprint.NameInterface 361} 362 363func NewNamespace(path string) *Namespace { 364 return &Namespace{Path: path, moduleContainer: blueprint.NewSimpleNameInterface()} 365} 366 367var _ blueprint.Namespace = (*Namespace)(nil) 368 369type namespaceProperties struct { 370 // a list of namespaces that contain modules that will be referenced 371 // by modules in this namespace. 372 Imports []string `android:"path"` 373} 374 375type NamespaceModule struct { 376 ModuleBase 377 378 namespace *Namespace 379 resolver *NameResolver 380 381 properties namespaceProperties 382} 383 384func (n *NamespaceModule) GenerateAndroidBuildActions(ctx ModuleContext) { 385} 386 387func (n *NamespaceModule) GenerateBuildActions(ctx blueprint.ModuleContext) { 388} 389 390func (n *NamespaceModule) Name() (name string) { 391 return *n.nameProperties.Name 392} 393 394// soong_namespace provides a scope to modules in an Android.bp file to prevent 395// module name conflicts with other defined modules in different Android.bp 396// files. Once soong_namespace has been defined in an Android.bp file, the 397// namespacing is applied to all modules that follow the soong_namespace in 398// the current Android.bp file, as well as modules defined in Android.bp files 399// in subdirectories. An Android.bp file in a subdirectory can define its own 400// soong_namespace which is applied to all its modules and as well as modules 401// defined in subdirectories Android.bp files. Modules in a soong_namespace are 402// visible to Make by listing the namespace path in PRODUCT_SOONG_NAMESPACES 403// make variable in a makefile. 404func NamespaceFactory() Module { 405 module := &NamespaceModule{} 406 407 name := "soong_namespace" 408 module.nameProperties.Name = &name 409 410 module.AddProperties(&module.properties) 411 return module 412} 413 414func RegisterNamespaceMutator(ctx RegisterMutatorsContext) { 415 ctx.BottomUp("namespace_deps", namespaceMutator).Parallel() 416} 417 418func namespaceMutator(ctx BottomUpMutatorContext) { 419 module, ok := ctx.Module().(*NamespaceModule) 420 if ok { 421 err := module.resolver.FindNamespaceImports(module.namespace) 422 if err != nil { 423 ctx.ModuleErrorf(err.Error()) 424 } 425 426 module.resolver.chooseId(module.namespace) 427 } 428} 429