• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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