blob: a2bd02426484d4b30248ecdce46ec527893538dc [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
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
Jeff Gastonb274ed32017-12-01 17:10:33 -080068func (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
Jeff Gaston088e29e2017-11-29 16:47:17 -080077// 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
Jeff Gastonb274ed32017-12-01 17:10:33 -080084 nextNamespaceId int32
Jeff Gaston088e29e2017-11-29 16:47:17 -080085
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 {
Jeff Gaston088e29e2017-11-29 16:47:17 -080097 r := &NameResolver{
Dan Willemsen59339a22018-07-22 21:18:45 -070098 namespacesByDir: sync.Map{},
Jeff Gaston088e29e2017-11-29 16:47:17 -080099 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
Jeff Gaston088e29e2017-11-29 16:47:17 -0800113 return namespace
114}
115
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800116func (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
Jeff Gaston088e29e2017-11-29 16:47:17 -0800123 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 {
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800175 err := r.addNewNamespaceForModule(newNamespace, ctx.ModulePath())
Jeff Gaston088e29e2017-11-29 16:47:17 -0800176 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) {
Colin Crossd602c382019-06-14 11:26:09 -0700231 if sourceNamespace.visibleNamespaces == nil {
232 // When handling dependencies before namespaceMutator, assume they are non-Soong Blueprint modules and give
233 // access to all namespaces.
234 return r.sortedNamespaces.sortedItems()
235 }
Jeff Gaston088e29e2017-11-29 16:47:17 -0800236 return sourceNamespace.visibleNamespaces
237}
238
239func (r *NameResolver) ModuleFromName(name string, namespace blueprint.Namespace) (group blueprint.ModuleGroup, found bool) {
240 // handle fully qualified references like "//namespace_path:module_name"
241 nsName, moduleName, isAbs := r.parseFullyQualifiedName(name)
242 if isAbs {
243 namespace, found := r.namespaceAt(nsName)
244 if !found {
245 return blueprint.ModuleGroup{}, false
246 }
247 container := namespace.moduleContainer
248 return container.ModuleFromName(moduleName, nil)
249 }
250 for _, candidate := range r.getNamespacesToSearchForModule(namespace.(*Namespace)) {
251 group, found = candidate.moduleContainer.ModuleFromName(name, nil)
252 if found {
253 return group, true
254 }
255 }
256 return blueprint.ModuleGroup{}, false
257
258}
259
260func (r *NameResolver) Rename(oldName string, newName string, namespace blueprint.Namespace) []error {
Colin Crosseafb10c2018-04-16 13:58:10 -0700261 return namespace.(*Namespace).moduleContainer.Rename(oldName, newName, namespace)
Jeff Gaston088e29e2017-11-29 16:47:17 -0800262}
263
264// resolve each element of namespace.importedNamespaceNames and put the result in namespace.visibleNamespaces
265func (r *NameResolver) FindNamespaceImports(namespace *Namespace) (err error) {
266 namespace.visibleNamespaces = make([]*Namespace, 0, 2+len(namespace.importedNamespaceNames))
267 // search itself first
268 namespace.visibleNamespaces = append(namespace.visibleNamespaces, namespace)
269 // search its imports next
270 for _, name := range namespace.importedNamespaceNames {
271 imp, ok := r.namespaceAt(name)
272 if !ok {
Rashed Abdel-Tawabd1e2bc42019-09-25 16:53:23 -0700273 if (name != "all") {
274 return fmt.Errorf("namespace %v does not exist", name)
275 } else {
276 namespace.visibleNamespaces = make([]*Namespace, 0, 2+len(namespace.importedNamespaceNames))
277 return nil
278 }
Jeff Gaston088e29e2017-11-29 16:47:17 -0800279 }
280 namespace.visibleNamespaces = append(namespace.visibleNamespaces, imp)
281 }
282 // search the root namespace last
283 namespace.visibleNamespaces = append(namespace.visibleNamespaces, r.rootNamespace)
284 return nil
285}
286
Jeff Gastonb274ed32017-12-01 17:10:33 -0800287func (r *NameResolver) chooseId(namespace *Namespace) {
288 id := r.sortedNamespaces.index(namespace)
289 if id < 0 {
290 panic(fmt.Sprintf("Namespace not found: %v\n", namespace.id))
291 }
292 namespace.id = strconv.Itoa(id)
293}
294
Jeff Gaston088e29e2017-11-29 16:47:17 -0800295func (r *NameResolver) MissingDependencyError(depender string, dependerNamespace blueprint.Namespace, depName string) (err error) {
296 text := fmt.Sprintf("%q depends on undefined module %q", depender, depName)
297
298 _, _, isAbs := r.parseFullyQualifiedName(depName)
299 if isAbs {
300 // if the user gave a fully-qualified name, we don't need to look for other
301 // modules that they might have been referring to
302 return fmt.Errorf(text)
303 }
304
305 // determine which namespaces the module can be found in
306 foundInNamespaces := []string{}
307 for _, namespace := range r.sortedNamespaces.sortedItems() {
308 _, found := namespace.moduleContainer.ModuleFromName(depName, nil)
309 if found {
310 foundInNamespaces = append(foundInNamespaces, namespace.Path)
311 }
312 }
313 if len(foundInNamespaces) > 0 {
314 // determine which namespaces are visible to dependerNamespace
315 dependerNs := dependerNamespace.(*Namespace)
316 searched := r.getNamespacesToSearchForModule(dependerNs)
317 importedNames := []string{}
318 for _, ns := range searched {
319 importedNames = append(importedNames, ns.Path)
320 }
321 text += fmt.Sprintf("\nModule %q is defined in namespace %q which can read these %v namespaces: %q", depender, dependerNs.Path, len(importedNames), importedNames)
322 text += fmt.Sprintf("\nModule %q can be found in these namespaces: %q", depName, foundInNamespaces)
323 }
324
325 return fmt.Errorf(text)
326}
327
328func (r *NameResolver) GetNamespace(ctx blueprint.NamespaceContext) blueprint.Namespace {
329 return r.findNamespaceFromCtx(ctx)
330}
331
332func (r *NameResolver) findNamespaceFromCtx(ctx blueprint.NamespaceContext) *Namespace {
Jeff Gaston5c3886d2017-11-30 16:46:47 -0800333 return r.findNamespace(filepath.Dir(ctx.ModulePath()))
Jeff Gaston088e29e2017-11-29 16:47:17 -0800334}
335
Jeff Gastonb274ed32017-12-01 17:10:33 -0800336func (r *NameResolver) UniqueName(ctx blueprint.NamespaceContext, name string) (unique string) {
337 prefix := r.findNamespaceFromCtx(ctx).id
338 if prefix != "" {
339 prefix = prefix + "-"
340 }
341 return prefix + name
342}
343
Jeff Gaston088e29e2017-11-29 16:47:17 -0800344var _ blueprint.NameInterface = (*NameResolver)(nil)
345
346type Namespace struct {
347 blueprint.NamespaceMarker
348 Path string
349
350 // names of namespaces listed as imports by this namespace
351 importedNamespaceNames []string
352 // all namespaces that should be searched when a module in this namespace declares a dependency
353 visibleNamespaces []*Namespace
354
355 id string
356
357 exportToKati bool
358
359 moduleContainer blueprint.NameInterface
360}
361
362func NewNamespace(path string) *Namespace {
363 return &Namespace{Path: path, moduleContainer: blueprint.NewSimpleNameInterface()}
364}
365
366var _ blueprint.Namespace = (*Namespace)(nil)
367
Patrice Arruda64765aa2019-03-13 09:36:46 -0700368type namespaceProperties struct {
369 // a list of namespaces that contain modules that will be referenced
370 // by modules in this namespace.
371 Imports []string `android:"path"`
372}
373
Jeff Gaston088e29e2017-11-29 16:47:17 -0800374type NamespaceModule struct {
375 ModuleBase
376
377 namespace *Namespace
378 resolver *NameResolver
379
Patrice Arruda64765aa2019-03-13 09:36:46 -0700380 properties namespaceProperties
Jeff Gaston088e29e2017-11-29 16:47:17 -0800381}
382
Jeff Gaston088e29e2017-11-29 16:47:17 -0800383func (n *NamespaceModule) GenerateAndroidBuildActions(ctx ModuleContext) {
384}
385
386func (n *NamespaceModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
387}
388
389func (n *NamespaceModule) Name() (name string) {
390 return *n.nameProperties.Name
391}
392
Patrice Arruda64765aa2019-03-13 09:36:46 -0700393// soong_namespace provides a scope to modules in an Android.bp file to prevent
394// module name conflicts with other defined modules in different Android.bp
395// files. Once soong_namespace has been defined in an Android.bp file, the
396// namespacing is applied to all modules that follow the soong_namespace in
397// the current Android.bp file, as well as modules defined in Android.bp files
398// in subdirectories. An Android.bp file in a subdirectory can define its own
399// soong_namespace which is applied to all its modules and as well as modules
400// defined in subdirectories Android.bp files. Modules in a soong_namespace are
401// visible to Make by listing the namespace path in PRODUCT_SOONG_NAMESPACES
402// make variable in a makefile.
Jeff Gaston088e29e2017-11-29 16:47:17 -0800403func NamespaceFactory() Module {
404 module := &NamespaceModule{}
405
406 name := "soong_namespace"
407 module.nameProperties.Name = &name
408
409 module.AddProperties(&module.properties)
410 return module
411}
412
413func RegisterNamespaceMutator(ctx RegisterMutatorsContext) {
Jeff Gastonb274ed32017-12-01 17:10:33 -0800414 ctx.BottomUp("namespace_deps", namespaceMutator).Parallel()
Jeff Gaston088e29e2017-11-29 16:47:17 -0800415}
416
Jeff Gastonb274ed32017-12-01 17:10:33 -0800417func namespaceMutator(ctx BottomUpMutatorContext) {
Jeff Gaston088e29e2017-11-29 16:47:17 -0800418 module, ok := ctx.Module().(*NamespaceModule)
419 if ok {
420 err := module.resolver.FindNamespaceImports(module.namespace)
421 if err != nil {
422 ctx.ModuleErrorf(err.Error())
423 }
Jeff Gastonb274ed32017-12-01 17:10:33 -0800424
425 module.resolver.chooseId(module.namespace)
Jeff Gaston088e29e2017-11-29 16:47:17 -0800426 }
427}