diff --git a/android/namespace.go b/android/namespace.go index b3e718af3..1f8ef5a66 100644 --- a/android/namespace.go +++ b/android/namespace.go @@ -22,7 +22,6 @@ import ( "strconv" "strings" "sync" - "sync/atomic" "github.com/google/blueprint" ) @@ -66,6 +65,15 @@ func (s *sortedNamespaces) sortedItems() []*Namespace { return s.items } +func (s *sortedNamespaces) index(namespace *Namespace) int { + for i, candidate := range s.sortedItems() { + if namespace == candidate { + return i + } + } + return -1 +} + // A NameResolver implements blueprint.NameInterface, and implements the logic to // find a module from namespaces based on a query string. // A query string can be a module name or can be be "//namespace_path:module_path" @@ -73,7 +81,7 @@ type NameResolver struct { rootNamespace *Namespace // id counter for atomic.AddInt32 - numNamespaces int32 + nextNamespaceId int32 // All namespaces, without duplicates. sortedNamespaces sortedNamespaces @@ -104,14 +112,6 @@ func (r *NameResolver) newNamespace(path string) *Namespace { namespace.exportToKati = r.namespaceExportFilter(namespace) - nextId := atomic.AddInt32(&r.numNamespaces, 1) - id := nextId - 1 - stringId := "" - if id > 0 { - stringId = strconv.Itoa(int(id)) - } - namespace.id = stringId - return namespace } @@ -291,6 +291,14 @@ func (r *NameResolver) FindNamespaceImports(namespace *Namespace) (err error) { return nil } +func (r *NameResolver) chooseId(namespace *Namespace) { + id := r.sortedNamespaces.index(namespace) + if id < 0 { + panic(fmt.Sprintf("Namespace not found: %v\n", namespace.id)) + } + namespace.id = strconv.Itoa(id) +} + func (r *NameResolver) MissingDependencyError(depender string, dependerNamespace blueprint.Namespace, depName string) (err error) { text := fmt.Sprintf("%q depends on undefined module %q", depender, depName) @@ -332,6 +340,14 @@ func (r *NameResolver) findNamespaceFromCtx(ctx blueprint.NamespaceContext) *Nam return r.findNamespace(filepath.Dir(ctx.ModulePath())) } +func (r *NameResolver) UniqueName(ctx blueprint.NamespaceContext, name string) (unique string) { + prefix := r.findNamespaceFromCtx(ctx).id + if prefix != "" { + prefix = prefix + "-" + } + return prefix + name +} + var _ blueprint.NameInterface = (*NameResolver)(nil) type Namespace struct { @@ -391,15 +407,17 @@ func NamespaceFactory() Module { } func RegisterNamespaceMutator(ctx RegisterMutatorsContext) { - ctx.BottomUp("namespace_deps", namespaceDeps) + ctx.BottomUp("namespace_deps", namespaceMutator).Parallel() } -func namespaceDeps(ctx BottomUpMutatorContext) { +func namespaceMutator(ctx BottomUpMutatorContext) { module, ok := ctx.Module().(*NamespaceModule) if ok { err := module.resolver.FindNamespaceImports(module.namespace) if err != nil { ctx.ModuleErrorf(err.Error()) } + + module.resolver.chooseId(module.namespace) } } diff --git a/android/namespace_test.go b/android/namespace_test.go index 13da88b42..9ab186b00 100644 --- a/android/namespace_test.go +++ b/android/namespace_test.go @@ -19,6 +19,7 @@ import ( "io/ioutil" "os" "path/filepath" + "reflect" "testing" "github.com/google/blueprint" @@ -562,6 +563,25 @@ func TestDeclaringNamespaceInNonAndroidBpFile(t *testing.T) { } } +// so that the generated .ninja file will have consistent names +func TestConsistentNamespaceNames(t *testing.T) { + ctx := setupTest(t, + map[string]string{ + "dir1": "soong_namespace{}", + "dir2": "soong_namespace{}", + "dir3": "soong_namespace{}", + }) + + ns1, _ := ctx.NameResolver.namespaceAt("dir1") + ns2, _ := ctx.NameResolver.namespaceAt("dir2") + ns3, _ := ctx.NameResolver.namespaceAt("dir3") + actualIds := []string{ns1.id, ns2.id, ns3.id} + expectedIds := []string{"1", "2", "3"} + if !reflect.DeepEqual(actualIds, expectedIds) { + t.Errorf("Incorrect namespace ids.\nactual: %s\nexpected: %s\n", actualIds, expectedIds) + } +} + // some utils to support the tests func mockFiles(bps map[string]string) (files map[string][]byte) { diff --git a/android/testing.go b/android/testing.go index 4f2a2da4f..1c0fac10d 100644 --- a/android/testing.go +++ b/android/testing.go @@ -23,14 +23,17 @@ import ( ) func NewTestContext() *TestContext { - ctx := &TestContext{ - Context: blueprint.NewContext(), - } - namespaceExportFilter := func(namespace *Namespace) bool { return true } - ctx.SetNameInterface(NewNameResolver(namespaceExportFilter)) + + nameResolver := NewNameResolver(namespaceExportFilter) + ctx := &TestContext{ + Context: blueprint.NewContext(), + NameResolver: nameResolver, + } + + ctx.SetNameInterface(nameResolver) return ctx } @@ -44,6 +47,7 @@ func NewTestArchContext() *TestContext { type TestContext struct { *blueprint.Context preArch, preDeps, postDeps []RegisterMutatorFunc + NameResolver *NameResolver } func (ctx *TestContext) PreArchMutators(f RegisterMutatorFunc) {