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