From d42609e15c63e4384efe68f3ae0819161f6a020d Mon Sep 17 00:00:00 2001 From: Sasha Smundak Date: Thu, 21 Nov 2019 13:23:44 -0800 Subject: [PATCH] Expand namespaces explanation. Test: N/A Change-Id: Iec7d40e6886285046fbe00aea8e19073c6c1ba73 --- README.md | 127 +++++++++++++++++++++++++++++++++-------- docs/best_practices.md | 4 +- 2 files changed, 104 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 37feb1de2..b6fda509d 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ cc_binary { ``` Variables are scoped to the remainder of the file they are declared in, as well -as any child blueprint files. Variables are immutable with one exception - they +as any child Android.bp files. Variables are immutable with one exception - they can be appended to with a += assignment, but only before they have been referenced. @@ -168,37 +168,114 @@ package { } ``` -### Name resolution +### Referencing Modules -Soong provides the ability for modules in different directories to specify -the same name, as long as each module is declared within a separate namespace. -A namespace can be declared like this: +A module `libfoo` can be referenced by its name ``` -soong_namespace { - imports: ["path/to/otherNamespace1", "path/to/otherNamespace2"], +cc_binary { + name: "app", + shared_libs: ["libfoo"], } ``` -Each Soong module is assigned a namespace based on its location in the tree. -Each Soong module is considered to be in the namespace defined by the -soong_namespace found in an Android.bp in the current directory or closest -ancestor directory, unless no such soong_namespace module is found, in which -case the module is considered to be in the implicit root namespace. +Obviously, this works only if there is only one `libfoo` module in the source +tree. Ensuring such name uniqueness for larger trees may become problematic. We +might also want to use the same name in multiple mutually exclusive subtrees +(for example, implementing different devices) deliberately in order to describe +a functionally equivalent module. Enter Soong namespaces. -When Soong attempts to resolve dependency D declared my module M in namespace -N which imports namespaces I1, I2, I3..., then if D is a fully-qualified name -of the form "//namespace:module", only the specified namespace will be searched -for the specified module name. Otherwise, Soong will first look for a module -named D declared in namespace N. If that module does not exist, Soong will look -for a module named D in namespaces I1, I2, I3... Lastly, Soong will look in the -root namespace. +#### Namespaces -Until we have fully converted from Make to Soong, it will be necessary for the -Make product config to specify a value of PRODUCT_SOONG_NAMESPACES. Its value -should be a space-separated list of namespaces that Soong export to Make to be -built by the `m` command. After we have fully converted from Make to Soong, the -details of enabling namespaces could potentially change. +A presense of the `soong_namespace {..}` in an Android.bp file defines a +**namespace**. For instance, having + +``` +soong_namespace { + ... +} +... +``` + +in `device/google/bonito/Android.bp` informs Soong that within the +`device/google/bonito` package the module names are unique, that is, all the +modules defined in the Android.bp files in the `device/google/bonito/` tree have +unique names. However, there may be modules with the same names outside +`device/google/bonito` tree. Indeed, there is a module `"pixelstats-vendor"` +both in `device/google/bonito/pixelstats` and in +`device/google/coral/pixelstats`. + +The name of a namespace is the path of its directory. The name of the namespace +in the example above is thus `device/google/bonito`. + +An implicit **global namespace** corresponds to the source tree as a whole. It +has empty name. + +A module name's **scope** is the smallest namespace containing it. Suppose a +source tree has `device/my` and `device/my/display` namespaces. If `libfoo` +module is defined in `device/co/display/lib/Android.bp`, its namespace is +`device/co/display`. + +The name uniqueness thus means that module's name is unique within its scope. In +other words, "//_scope_:_name_" is globally unique module reference, e.g, +`"//device/google/bonito:pixelstats-vendor"`. _Note_ that the name of the +namespace for a module may be different from module's package name: `libfoo` +belongs to `device/my/display` namespace but is contained in +`device/my/display/lib` package. + +#### Name Resolution + +The form of a module reference determines how Soong locates the module. + +For a **global reference** of the "//_scope_:_name_" form, Soong verifies there +is a namespace called "_scope_", then verifies it contains a "_name_" module and +uses it. Soong verifies there is only one "_name_" in "_scope_" at the beginning +when it parses Android.bp files. + +A **local reference** has "_name_" form, and resolving it involves looking for a +module "_name_" in one or more namespaces. By default only the global namespace +is searched for "_name_" (in other words, only the modules not belonging to an +explicitly defined scope are considered). The `imports` attribute of the +`soong_namespaces` allows to specify where to look for modules . For instance, +with `device/google/bonito/Android.bp` containing + +``` +soong_namespace { + imports: [ + "hardware/google/interfaces", + "hardware/google/pixel", + "hardware/qcom/bootctrl", + ], +} +``` + +a reference to `"libpixelstats"` will resolve to the module defined in +`hardware/google/pixel/pixelstats/Android.bp` because this module is in +`hardware/google/pixel` namespace. + +**TODO**: Conventionally, languages with similar concepts provide separate +constructs for namespace definition and name resolution (`namespace` and `using` +in C++, for instance). Should Soong do that, too? + +#### Referencing modules in makefiles + +While we are gradually converting makefiles to Android.bp files, Android build +is described by a mixture of Android.bp and Android.mk files, and a module +defined in an Android.mk file can reference a module defined in Android.bp file. +For instance, a binary still defined in an Android.mk file may have a library +defined in already converted Android.bp as a dependency. + +A module defined in an Android.bp file and belonging to the global namespace can +be referenced from a makefile without additional effort. If a module belongs to +an explicit namespace, it can be referenced from a makefile only after after the +name of the namespace has been added to the value of PRODUCT_SOONG_NAMESPACES +variable. + +Note that makefiles have no notion of namespaces and exposing namespaces with +the same modules via PRODUCT_SOONG_NAMESPACES may cause Make failure. For +instance, exposing both `device/google/bonito` and `device/google/coral` +namespaces will cause Make failure because it will see two targets for the +`pixelstats-vendor` module. ### Visibility @@ -266,7 +343,7 @@ owner's responsibility to replace that with a more appropriate visibility. ### Formatter -Soong includes a canonical formatter for blueprint files, similar to +Soong includes a canonical formatter for Android.bp files, similar to [gofmt](https://golang.org/cmd/gofmt/). To recursively reformat all Android.bp files in the current directory: ``` diff --git a/docs/best_practices.md b/docs/best_practices.md index 93be3192e..bc760b876 100644 --- a/docs/best_practices.md +++ b/docs/best_practices.md @@ -240,8 +240,8 @@ PRODUCT_PROPERTY_OVERRIDES += ro.hardware.gralloc=soc_a In cases where the names cannot be made unique a `soong_namespace` should be used to partition a set of modules so that they are built only when the namespace is listed in `PRODUCT_SOONG_NAMESPACES`. See the -[Name resolution](../README.md#name-resolution) section of the Soong README.md -for more on namespaces. +[Referencing Modules](../README.md#referencing-modules) section of the Soong +README.md for more on namespaces. ### Module with name based on variable