Merge "Use tree representation for class loader context in Make."
diff --git a/Android.bp b/Android.bp
index 866ed25..1012dba 100644
--- a/Android.bp
+++ b/Android.bp
@@ -222,3 +222,8 @@
srcs: [":linker"],
out: ["linker.flags"],
}
+
+// Instantiate the dex_bootjars singleton module.
+dex_bootjars {
+ name: "dex_bootjars",
+}
diff --git a/README.md b/README.md
index f1857f8..b7e93f4 100644
--- a/README.md
+++ b/README.md
@@ -430,14 +430,24 @@
soong_config_string_variable {
name: "board",
- values: ["soc_a", "soc_b"],
+ values: ["soc_a", "soc_b", "soc_c"],
}
```
This example describes a new `acme_cc_defaults` module type that extends the
`cc_defaults` module type, with three additional conditionals based on
variables `board`, `feature` and `width`, which can affect properties `cflags`
-and `srcs`.
+and `srcs`. Additionally, each conditional will contain a `conditions_default`
+property can affect `cflags` and `srcs` in the following conditions:
+
+* bool variable (e.g. `feature`): the variable is unspecified or not set to a true value
+* value variable (e.g. `width`): the variable is unspecified
+* string variable (e.g. `board`): the variable is unspecified or the variable is set to a string unused in the
+given module. For example, with `board`, if the `board`
+conditional contains the properties `soc_a` and `conditions_default`, when
+board=soc_b, the `cflags` and `srcs` values under `conditions_default` will be
+used. To specify that no properties should be amended for `soc_b`, you can set
+`soc_b: {},`.
The values of the variables can be set from a product's `BoardConfig.mk` file:
```
@@ -445,6 +455,7 @@
SOONG_CONFIG_acme += \
board \
feature \
+ width \
SOONG_CONFIG_acme_board := soc_a
SOONG_CONFIG_acme_feature := true
@@ -473,12 +484,21 @@
soc_b: {
cflags: ["-DSOC_B"],
},
+ conditions_default: {
+ cflags: ["-DSOC_DEFAULT"],
+ },
},
feature: {
cflags: ["-DFEATURE"],
+ conditions_default: {
+ cflags: ["-DFEATURE_DEFAULT"],
+ },
},
width: {
cflags: ["-DWIDTH=%s"],
+ conditions_default: {
+ cflags: ["-DWIDTH=DEFAULT"],
+ },
},
},
}
@@ -490,8 +510,37 @@
}
```
-With the `BoardConfig.mk` snippet above, libacme_foo would build with
-cflags "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200".
+With the `BoardConfig.mk` snippet above, `libacme_foo` would build with
+`cflags: "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200"`.
+
+Alternatively, with `DefaultBoardConfig.mk`:
+
+```
+SOONG_CONFIG_NAMESPACES += acme
+SOONG_CONFIG_acme += \
+ board \
+ feature \
+ width \
+
+SOONG_CONFIG_acme_feature := false
+```
+
+then `libacme_foo` would build with `cflags: "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT"`.
+
+Alternatively, with `DefaultBoardConfig.mk`:
+
+```
+SOONG_CONFIG_NAMESPACES += acme
+SOONG_CONFIG_acme += \
+ board \
+ feature \
+ width \
+
+SOONG_CONFIG_acme_board := soc_c
+```
+
+then `libacme_foo` would build with `cflags: "-DGENERIC -DSOC_DEFAULT
+-DFEATURE_DEFAULT -DSIZE=DEFAULT"`.
`soong_config_module_type` modules will work best when used to wrap defaults
modules (`cc_defaults`, `java_defaults`, etc.), which can then be referenced
diff --git a/android/arch.go b/android/arch.go
index 34f9b29..baee9be 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -617,11 +617,15 @@
}
// Some modules want compile_multilib: "first" to mean 32-bit, not 64-bit.
- // This is used for Windows support and for HOST_PREFER_32_BIT=true support for Art modules.
+ // This is used for HOST_PREFER_32_BIT=true support for Art modules.
prefer32 := false
if base.prefer32 != nil {
prefer32 = base.prefer32(mctx, base, os)
}
+ if os == Windows {
+ // Windows builds always prefer 32-bit
+ prefer32 = true
+ }
// Determine the multilib selection for this module.
multilib, extraMultilib := decodeMultilib(base, os.Class)
diff --git a/android/filegroup.go b/android/filegroup.go
index 9425616..fd4a2fe 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -17,10 +17,50 @@
import (
"android/soong/bazel"
"strings"
+
+ "github.com/google/blueprint/proptools"
)
func init() {
RegisterModuleType("filegroup", FileGroupFactory)
+ RegisterBp2BuildMutator("filegroup", bp2buildMutator)
+}
+
+// https://docs.bazel.build/versions/master/be/general.html#filegroup
+type bazelFilegroupAttributes struct {
+ Name *string
+ Srcs []string
+}
+
+type bazelFilegroup struct {
+ BazelTargetModuleBase
+ bazelFilegroupAttributes
+}
+
+func BazelFileGroupFactory() Module {
+ module := &bazelFilegroup{}
+ module.AddProperties(&module.bazelFilegroupAttributes)
+ InitBazelTargetModule(module)
+ return module
+}
+
+func (bfg *bazelFilegroup) Name() string {
+ return bfg.BaseModuleName()
+}
+
+func (bfg *bazelFilegroup) GenerateAndroidBuildActions(ctx ModuleContext) {}
+
+// TODO: Create helper functions to avoid this boilerplate.
+func bp2buildMutator(ctx TopDownMutatorContext) {
+ if m, ok := ctx.Module().(*fileGroup); ok {
+ name := "__bp2build__" + m.base().BaseModuleName()
+ ctx.CreateModule(BazelFileGroupFactory, &bazelFilegroupAttributes{
+ Name: proptools.StringPtr(name),
+ Srcs: m.properties.Srcs,
+ }, &bazel.BazelTargetModuleProperties{
+ Rule_class: "filegroup",
+ })
+ }
}
type fileGroupProperties struct {
diff --git a/android/module.go b/android/module.go
index d189d1a..68008c2 100644
--- a/android/module.go
+++ b/android/module.go
@@ -15,6 +15,7 @@
package android
import (
+ "android/soong/bazel"
"fmt"
"os"
"path"
@@ -491,6 +492,26 @@
TransitivePackagingSpecs() []PackagingSpec
}
+type BazelTargetModule interface {
+ Module
+
+ BazelTargetModuleProperties() *bazel.BazelTargetModuleProperties
+}
+
+func InitBazelTargetModule(module BazelTargetModule) {
+ module.AddProperties(module.BazelTargetModuleProperties())
+ InitAndroidModule(module)
+}
+
+type BazelTargetModuleBase struct {
+ ModuleBase
+ Properties bazel.BazelTargetModuleProperties
+}
+
+func (btmb *BazelTargetModuleBase) BazelTargetModuleProperties() *bazel.BazelTargetModuleProperties {
+ return &btmb.Properties
+}
+
// Qualified id for a module
type qualifiedModuleName struct {
// The package (i.e. directory) in which the module is defined, without trailing /
@@ -1069,6 +1090,9 @@
archProperties [][]interface{}
customizableProperties []interface{}
+ // Properties specific to the Blueprint to BUILD migration.
+ bazelTargetModuleProperties bazel.BazelTargetModuleProperties
+
// Information about all the properties on the module that contains visibility rules that need
// checking.
visibilityPropertyInfo []visibilityProperty
diff --git a/android/mutator.go b/android/mutator.go
index 72c68b2..2a2be6c 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -44,9 +44,16 @@
}
}
-func registerMutatorsForBazelConversion(ctx *blueprint.Context) {
- // FIXME(b/171263886): Start bringing in mutators to make the Bionic
- // module subgraph suitable for automated conversion.
+// RegisterMutatorsForBazelConversion is a alternate registration pipeline for bp2build. Exported for testing.
+func RegisterMutatorsForBazelConversion(ctx *blueprint.Context, bp2buildMutators []RegisterMutatorFunc) {
+ mctx := ®isterMutatorsContext{}
+
+ // Register bp2build mutators
+ for _, f := range bp2buildMutators {
+ f(mctx)
+ }
+
+ registerMutatorsToContext(ctx, mctx.mutators)
}
func registerMutators(ctx *blueprint.Context, preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc) {
@@ -196,6 +203,21 @@
finalDeps = append(finalDeps, f)
}
+var bp2buildMutators = []RegisterMutatorFunc{}
+
+// RegisterBp2BuildMutator registers specially crafted mutators for
+// converting Blueprint/Android modules into special modules that can
+// be code-generated into Bazel BUILD targets.
+//
+// TODO(b/178068862): bring this into TestContext.
+func RegisterBp2BuildMutator(moduleType string, m func(TopDownMutatorContext)) {
+ mutatorName := moduleType + "_bp2build"
+ f := func(ctx RegisterMutatorsContext) {
+ ctx.TopDown(mutatorName, m)
+ }
+ bp2buildMutators = append(bp2buildMutators, f)
+}
+
type BaseMutatorContext interface {
BaseModuleContext
diff --git a/android/register.go b/android/register.go
index f84acad..02fc97e 100644
--- a/android/register.go
+++ b/android/register.go
@@ -115,7 +115,7 @@
ctx.RegisterSingletonType(t.name, SingletonFactoryAdaptor(ctx, t.factory))
}
- registerMutatorsForBazelConversion(ctx.Context)
+ RegisterMutatorsForBazelConversion(ctx.Context, bp2buildMutators)
}
// Register the pipeline of singletons, module types, and mutators for
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index 619cf86..289e910 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -51,6 +51,16 @@
// variables from another Android.bp file. The imported module type will exist for all
// modules after the import in the Android.bp file.
//
+// Each soong_config_variable supports an additional value `conditions_default`. The properties
+// specified in `conditions_default` will only be used under the following conditions:
+// bool variable: the variable is unspecified or not set to a true value
+// value variable: the variable is unspecified
+// string variable: the variable is unspecified or the variable is set to a string unused in the
+// given module. For example, string variable `test` takes values: "a" and "b",
+// if the module contains a property `a` and `conditions_default`, when test=b,
+// the properties under `conditions_default` will be used. To specify that no
+// properties should be amended for `b`, you can set `b: {},`.
+//
// For example, an Android.bp file could have:
//
// soong_config_module_type_import {
@@ -69,12 +79,21 @@
// soc_b: {
// cflags: ["-DSOC_B"],
// },
+// conditions_default: {
+// cflags: ["-DSOC_DEFAULT"],
+// },
// },
// feature: {
// cflags: ["-DFEATURE"],
+// conditions_default: {
+// cflags: ["-DFEATURE_DEFAULT"],
+// },
// },
// width: {
// cflags: ["-DWIDTH=%s"],
+// conditions_default: {
+// cflags: ["-DWIDTH=DEFAULT"],
+// },
// },
// },
// }
@@ -99,7 +118,7 @@
//
// soong_config_string_variable {
// name: "board",
-// values: ["soc_a", "soc_b"],
+// values: ["soc_a", "soc_b", "soc_c"],
// }
//
// If an acme BoardConfig.mk file contained:
@@ -114,6 +133,31 @@
// SOONG_CONFIG_acme_width := 200
//
// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200".
+//
+// Alternatively, if acme BoardConfig.mk file contained:
+//
+// SOONG_CONFIG_NAMESPACES += acme
+// SOONG_CONFIG_acme += \
+// board \
+// feature \
+//
+// SOONG_CONFIG_acme_feature := false
+//
+// Then libacme_foo would build with cflags:
+// "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT".
+//
+// Similarly, if acme BoardConfig.mk file contained:
+//
+// SOONG_CONFIG_NAMESPACES += acme
+// SOONG_CONFIG_acme += \
+// board \
+// feature \
+//
+// SOONG_CONFIG_acme_board := soc_c
+//
+// Then libacme_foo would build with cflags:
+// "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT".
+
func soongConfigModuleTypeImportFactory() Module {
module := &soongConfigModuleTypeImport{}
@@ -148,6 +192,16 @@
// in an Android.bp file, and can be imported into other Android.bp files using
// soong_config_module_type_import.
//
+// Each soong_config_variable supports an additional value `conditions_default`. The properties
+// specified in `conditions_default` will only be used under the following conditions:
+// bool variable: the variable is unspecified or not set to a true value
+// value variable: the variable is unspecified
+// string variable: the variable is unspecified or the variable is set to a string unused in the
+// given module. For example, string variable `test` takes values: "a" and "b",
+// if the module contains a property `a` and `conditions_default`, when test=b,
+// the properties under `conditions_default` will be used. To specify that no
+// properties should be amended for `b`, you can set `b: {},`.
+//
// For example, an Android.bp file could have:
//
// soong_config_module_type {
@@ -176,12 +230,21 @@
// soc_b: {
// cflags: ["-DSOC_B"],
// },
+// conditions_default: {
+// cflags: ["-DSOC_DEFAULT"],
+// },
// },
// feature: {
// cflags: ["-DFEATURE"],
+// conditions_default: {
+// cflags: ["-DFEATURE_DEFAULT"],
+// },
// },
// width: {
// cflags: ["-DWIDTH=%s"],
+// conditions_default: {
+// cflags: ["-DWIDTH=DEFAULT"],
+// },
// },
// },
// }
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
index b1810b3..45463fd 100644
--- a/android/soong_config_modules_test.go
+++ b/android/soong_config_modules_test.go
@@ -60,15 +60,20 @@
name: "acme_test",
module_type: "test",
config_namespace: "acme",
- variables: ["board", "feature1", "FEATURE3"],
- bool_variables: ["feature2"],
- value_variables: ["size"],
+ variables: ["board", "feature1", "FEATURE3", "unused_string_var"],
+ bool_variables: ["feature2", "unused_feature"],
+ value_variables: ["size", "unused_size"],
properties: ["cflags", "srcs", "defaults"],
}
soong_config_string_variable {
name: "board",
- values: ["soc_a", "soc_b"],
+ values: ["soc_a", "soc_b", "soc_c", "soc_d"],
+ }
+
+ soong_config_string_variable {
+ name: "unused_string_var",
+ values: ["a", "b"],
}
soong_config_bool_variable {
@@ -105,15 +110,28 @@
soc_b: {
cflags: ["-DSOC_B"],
},
+ soc_c: {},
+ conditions_default: {
+ cflags: ["-DSOC_CONDITIONS_DEFAULT"],
+ },
},
size: {
cflags: ["-DSIZE=%s"],
+ conditions_default: {
+ cflags: ["-DSIZE=CONDITIONS_DEFAULT"],
+ },
},
feature1: {
+ conditions_default: {
+ cflags: ["-DF1_CONDITIONS_DEFAULT"],
+ },
cflags: ["-DFEATURE1"],
},
feature2: {
cflags: ["-DFEATURE2"],
+ conditions_default: {
+ cflags: ["-DF2_CONDITIONS_DEFAULT"],
+ },
},
FEATURE3: {
cflags: ["-DFEATURE3"],
@@ -145,6 +163,7 @@
cflags: ["-DSOC_B"],
defaults: ["foo_defaults_b"],
},
+ soc_c: {},
},
size: {
cflags: ["-DSIZE=%s"],
@@ -163,43 +182,120 @@
`
run := func(t *testing.T, bp string, fs map[string][]byte) {
- config := TestConfig(buildDir, nil, bp, fs)
+ testCases := []struct {
+ name string
+ config Config
+ fooExpectedFlags []string
+ fooDefaultsExpectedFlags []string
+ }{
+ {
+ name: "withValues",
+ config: testConfigWithVendorVars(buildDir, bp, fs, map[string]map[string]string{
+ "acme": map[string]string{
+ "board": "soc_a",
+ "size": "42",
+ "feature1": "true",
+ "feature2": "false",
+ // FEATURE3 unset
+ "unused_feature": "true", // unused
+ "unused_size": "1", // unused
+ "unused_string_var": "a", // unused
+ },
+ }),
+ fooExpectedFlags: []string{
+ "DEFAULT",
+ "-DGENERIC",
+ "-DF2_CONDITIONS_DEFAULT",
+ "-DSIZE=42",
+ "-DSOC_A",
+ "-DFEATURE1",
+ },
+ fooDefaultsExpectedFlags: []string{
+ "DEFAULT_A",
+ "DEFAULT",
+ "-DGENERIC",
+ "-DSIZE=42",
+ "-DSOC_A",
+ "-DFEATURE1",
+ },
+ },
+ {
+ name: "empty_prop_for_string_var",
+ config: testConfigWithVendorVars(buildDir, bp, fs, map[string]map[string]string{
+ "acme": map[string]string{"board": "soc_c"}}),
+ fooExpectedFlags: []string{
+ "DEFAULT",
+ "-DGENERIC",
+ "-DF2_CONDITIONS_DEFAULT",
+ "-DSIZE=CONDITIONS_DEFAULT",
+ "-DF1_CONDITIONS_DEFAULT",
+ },
+ fooDefaultsExpectedFlags: []string{
+ "DEFAULT",
+ "-DGENERIC",
+ },
+ },
+ {
+ name: "unused_string_var",
+ config: testConfigWithVendorVars(buildDir, bp, fs, map[string]map[string]string{
+ "acme": map[string]string{"board": "soc_d"}}),
+ fooExpectedFlags: []string{
+ "DEFAULT",
+ "-DGENERIC",
+ "-DF2_CONDITIONS_DEFAULT",
+ "-DSIZE=CONDITIONS_DEFAULT",
+ "-DSOC_CONDITIONS_DEFAULT", // foo does not contain a prop "soc_d", so we use the default
+ "-DF1_CONDITIONS_DEFAULT",
+ },
+ fooDefaultsExpectedFlags: []string{
+ "DEFAULT",
+ "-DGENERIC",
+ },
+ },
- config.TestProductVariables.VendorVars = map[string]map[string]string{
- "acme": map[string]string{
- "board": "soc_a",
- "size": "42",
- "feature1": "true",
- "feature2": "false",
- // FEATURE3 unset
+ {
+ name: "conditions_default",
+ config: testConfigWithVendorVars(buildDir, bp, fs, map[string]map[string]string{}),
+ fooExpectedFlags: []string{
+ "DEFAULT",
+ "-DGENERIC",
+ "-DF2_CONDITIONS_DEFAULT",
+ "-DSIZE=CONDITIONS_DEFAULT",
+ "-DSOC_CONDITIONS_DEFAULT",
+ "-DF1_CONDITIONS_DEFAULT",
+ },
+ fooDefaultsExpectedFlags: []string{
+ "DEFAULT",
+ "-DGENERIC",
+ },
},
}
- ctx := NewTestContext(config)
- ctx.RegisterModuleType("soong_config_module_type_import", soongConfigModuleTypeImportFactory)
- ctx.RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
- ctx.RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
- ctx.RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
- ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory)
- ctx.RegisterModuleType("test", soongConfigTestModuleFactory)
- ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
- ctx.Register()
+ for _, tc := range testCases {
+ ctx := NewTestContext(tc.config)
+ ctx.RegisterModuleType("soong_config_module_type_import", soongConfigModuleTypeImportFactory)
+ ctx.RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
+ ctx.RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
+ ctx.RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
+ ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory)
+ ctx.RegisterModuleType("test", soongConfigTestModuleFactory)
+ ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
+ ctx.Register()
- _, errs := ctx.ParseBlueprintsFiles("Android.bp")
- FailIfErrored(t, errs)
- _, errs = ctx.PrepareBuildActions(config)
- FailIfErrored(t, errs)
+ _, errs := ctx.ParseBlueprintsFiles("Android.bp")
+ FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(tc.config)
+ FailIfErrored(t, errs)
- basicCFlags := []string{"DEFAULT", "-DGENERIC", "-DSIZE=42", "-DSOC_A", "-DFEATURE1"}
+ foo := ctx.ModuleForTests("foo", "").Module().(*soongConfigTestModule)
+ if g, w := foo.props.Cflags, tc.fooExpectedFlags; !reflect.DeepEqual(g, w) {
+ t.Errorf("%s: wanted foo cflags %q, got %q", tc.name, w, g)
+ }
- foo := ctx.ModuleForTests("foo", "").Module().(*soongConfigTestModule)
- if g, w := foo.props.Cflags, basicCFlags; !reflect.DeepEqual(g, w) {
- t.Errorf("wanted foo cflags %q, got %q", w, g)
- }
-
- fooDefaults := ctx.ModuleForTests("foo_with_defaults", "").Module().(*soongConfigTestModule)
- if g, w := fooDefaults.props.Cflags, append([]string{"DEFAULT_A"}, basicCFlags...); !reflect.DeepEqual(g, w) {
- t.Errorf("wanted foo_with_defaults cflags %q, got %q", w, g)
+ fooDefaults := ctx.ModuleForTests("foo_with_defaults", "").Module().(*soongConfigTestModule)
+ if g, w := fooDefaults.props.Cflags, tc.fooDefaultsExpectedFlags; !reflect.DeepEqual(g, w) {
+ t.Errorf("%s: wanted foo_with_defaults cflags %q, got %q", tc.name, w, g)
+ }
}
}
@@ -214,3 +310,11 @@
})
})
}
+
+func testConfigWithVendorVars(buildDir, bp string, fs map[string][]byte, vendorVars map[string]map[string]string) Config {
+ config := TestConfig(buildDir, nil, bp, fs)
+
+ config.TestProductVariables.VendorVars = vendorVars
+
+ return config
+}
diff --git a/android/soongconfig/Android.bp b/android/soongconfig/Android.bp
index df912e6..6bb68eb 100644
--- a/android/soongconfig/Android.bp
+++ b/android/soongconfig/Android.bp
@@ -10,4 +10,7 @@
"config.go",
"modules.go",
],
+ testSrcs: [
+ "modules_test.go",
+ ],
}
diff --git a/android/soongconfig/config.go b/android/soongconfig/config.go
index 39a776c..c72da2f 100644
--- a/android/soongconfig/config.go
+++ b/android/soongconfig/config.go
@@ -14,7 +14,10 @@
package soongconfig
-import "strings"
+import (
+ "fmt"
+ "strings"
+)
type SoongConfig interface {
// Bool interprets the variable named `name` as a boolean, returning true if, after
@@ -31,7 +34,16 @@
}
func Config(vars map[string]string) SoongConfig {
- return soongConfig(vars)
+ configVars := make(map[string]string)
+ if len(vars) > 0 {
+ for k, v := range vars {
+ configVars[k] = v
+ }
+ if _, exists := configVars[conditionsDefault]; exists {
+ panic(fmt.Sprintf("%q is a reserved soong config variable name", conditionsDefault))
+ }
+ }
+ return soongConfig(configVars)
}
type soongConfig map[string]string
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index 9f3f804..c62e76d 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -26,6 +26,8 @@
"github.com/google/blueprint/proptools"
)
+const conditionsDefault = "conditions_default"
+
var soongConfigProperty = proptools.FieldNameForProperty("soong_config_variables")
// loadSoongConfigModuleTypeDefinition loads module types from an Android.bp file. It caches the
@@ -145,32 +147,10 @@
return errs
}
- mt := &ModuleType{
- affectableProperties: props.Properties,
- ConfigNamespace: props.Config_namespace,
- BaseModuleType: props.Module_type,
- variableNames: props.Variables,
- }
- v.ModuleTypes[props.Name] = mt
-
- for _, name := range props.Bool_variables {
- if name == "" {
- return []error{fmt.Errorf("bool_variable name must not be blank")}
- }
-
- mt.Variables = append(mt.Variables, newBoolVariable(name))
- }
-
- for _, name := range props.Value_variables {
- if name == "" {
- return []error{fmt.Errorf("value_variables entry must not be blank")}
- }
-
- mt.Variables = append(mt.Variables, &valueVariable{
- baseVariable: baseVariable{
- variable: name,
- },
- })
+ if mt, errs := newModuleType(props); len(errs) > 0 {
+ return errs
+ } else {
+ v.ModuleTypes[props.Name] = mt
}
return nil
@@ -196,6 +176,12 @@
return []error{fmt.Errorf("values property must be set")}
}
+ for _, name := range stringProps.Values {
+ if err := checkVariableName(name); err != nil {
+ return []error{fmt.Errorf("soong_config_string_variable: values property error %s", err)}
+ }
+ }
+
v.variables[base.variable] = &stringVariable{
baseVariable: base,
values: CanonicalizeToProperties(stringProps.Values),
@@ -417,8 +403,7 @@
// PropertiesToApply returns the applicable properties from a ModuleType that should be applied
// based on SoongConfig values.
// Expects that props contains a struct field with name soong_config_variables. The fields within
-// soong_config_variables are expected to be in the same order as moduleType.Variables. In general,
-// props should be generated via CreateProperties.
+// soong_config_variables are expected to be in the same order as moduleType.Variables.
func PropertiesToApply(moduleType *ModuleType, props reflect.Value, config SoongConfig) ([]interface{}, error) {
var ret []interface{}
props = props.Elem().FieldByName(soongConfigProperty)
@@ -441,6 +426,46 @@
variableNames []string
}
+func newModuleType(props *ModuleTypeProperties) (*ModuleType, []error) {
+ mt := &ModuleType{
+ affectableProperties: props.Properties,
+ ConfigNamespace: props.Config_namespace,
+ BaseModuleType: props.Module_type,
+ variableNames: props.Variables,
+ }
+
+ for _, name := range props.Bool_variables {
+ if err := checkVariableName(name); err != nil {
+ return nil, []error{fmt.Errorf("bool_variables %s", err)}
+ }
+
+ mt.Variables = append(mt.Variables, newBoolVariable(name))
+ }
+
+ for _, name := range props.Value_variables {
+ if err := checkVariableName(name); err != nil {
+ return nil, []error{fmt.Errorf("value_variables %s", err)}
+ }
+
+ mt.Variables = append(mt.Variables, &valueVariable{
+ baseVariable: baseVariable{
+ variable: name,
+ },
+ })
+ }
+
+ return mt, nil
+}
+
+func checkVariableName(name string) error {
+ if name == "" {
+ return fmt.Errorf("name must not be blank")
+ } else if name == conditionsDefault {
+ return fmt.Errorf("%q is reserved", conditionsDefault)
+ }
+ return nil
+}
+
type soongConfigVariable interface {
// variableProperty returns the name of the variable.
variableProperty() string
@@ -474,7 +499,10 @@
func (s *stringVariable) variableValuesType() reflect.Type {
var fields []reflect.StructField
- for _, v := range s.values {
+ var values []string
+ values = append(values, s.values...)
+ values = append(values, conditionsDefault)
+ for _, v := range values {
fields = append(fields, reflect.StructField{
Name: proptools.FieldNameForProperty(v),
Type: emptyInterfaceType,
@@ -484,26 +512,36 @@
return reflect.StructOf(fields)
}
+// initializeProperties initializes properties to zero value of typ for supported values and a final
+// conditions default field.
func (s *stringVariable) initializeProperties(v reflect.Value, typ reflect.Type) {
for i := range s.values {
v.Field(i).Set(reflect.Zero(typ))
}
+ v.Field(len(s.values)).Set(reflect.Zero(typ)) // conditions default is the final value
}
+// Extracts an interface from values containing the properties to apply based on config.
+// If config does not match a value with a non-nil property set, the default value will be returned.
func (s *stringVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
for j, v := range s.values {
- if config.String(s.variable) == v {
- return values.Field(j).Interface(), nil
+ f := values.Field(j)
+ if config.String(s.variable) == v && !f.Elem().IsNil() {
+ return f.Interface(), nil
}
}
-
- return nil, nil
+ // if we have reached this point, we have checked all valid values of string and either:
+ // * the value was not set
+ // * the value was set but that value was not specified in the Android.bp file
+ return values.Field(len(s.values)).Interface(), nil
}
+// Struct to allow conditions set based on a boolean variable
type boolVariable struct {
baseVariable
}
+// newBoolVariable constructs a boolVariable with the given name
func newBoolVariable(name string) *boolVariable {
return &boolVariable{
baseVariable{
@@ -516,18 +554,82 @@
return emptyInterfaceType
}
+// initializeProperties initializes a property to zero value of typ with an additional conditions
+// default field.
func (b boolVariable) initializeProperties(v reflect.Value, typ reflect.Type) {
- v.Set(reflect.Zero(typ))
+ initializePropertiesWithDefault(v, typ)
}
-func (b boolVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
- if config.Bool(b.variable) {
- return values.Interface(), nil
+// initializePropertiesWithDefault, initialize with zero value, v to contain a field for each field
+// in typ, with an additional field for defaults of type typ. This should be used to initialize
+// boolVariable, valueVariable, or any future implementations of soongConfigVariable which support
+// one variable and a default.
+func initializePropertiesWithDefault(v reflect.Value, typ reflect.Type) {
+ sTyp := typ.Elem()
+ var fields []reflect.StructField
+ for i := 0; i < sTyp.NumField(); i++ {
+ fields = append(fields, sTyp.Field(i))
}
+ // create conditions_default field
+ nestedFieldName := proptools.FieldNameForProperty(conditionsDefault)
+ fields = append(fields, reflect.StructField{
+ Name: nestedFieldName,
+ Type: typ,
+ })
+
+ newTyp := reflect.PtrTo(reflect.StructOf(fields))
+ v.Set(reflect.Zero(newTyp))
+}
+
+// conditionsDefaultField extracts the conditions_default field from v. This is always the final
+// field if initialized with initializePropertiesWithDefault.
+func conditionsDefaultField(v reflect.Value) reflect.Value {
+ return v.Field(v.NumField() - 1)
+}
+
+// removeDefault removes the conditions_default field from values while retaining values from all
+// other fields. This allows
+func removeDefault(values reflect.Value) reflect.Value {
+ v := values.Elem().Elem()
+ s := conditionsDefaultField(v)
+ // if conditions_default field was not set, there will be no issues extending properties.
+ if !s.IsValid() {
+ return v
+ }
+
+ // If conditions_default field was set, it has the correct type for our property. Create a new
+ // reflect.Value of the conditions_default type and copy all fields (except for
+ // conditions_default) based on values to the result.
+ res := reflect.New(s.Type().Elem())
+ for i := 0; i < res.Type().Elem().NumField(); i++ {
+ val := v.Field(i)
+ res.Elem().Field(i).Set(val)
+ }
+
+ return res
+}
+
+// PropertiesToApply returns an interface{} value based on initializeProperties to be applied to
+// the module. If the value was not set, conditions_default interface will be returned; otherwise,
+// the interface in values, without conditions_default will be returned.
+func (b boolVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
+ // If this variable was not referenced in the module, there are no properties to apply.
+ if values.Elem().IsZero() {
+ return nil, nil
+ }
+ if config.Bool(b.variable) {
+ values = removeDefault(values)
+ return values.Interface(), nil
+ }
+ v := values.Elem().Elem()
+ if f := conditionsDefaultField(v); f.IsValid() {
+ return f.Interface(), nil
+ }
return nil, nil
}
+// Struct to allow conditions set based on a value variable, supporting string substitution.
type valueVariable struct {
baseVariable
}
@@ -536,17 +638,28 @@
return emptyInterfaceType
}
+// initializeProperties initializes a property to zero value of typ with an additional conditions
+// default field.
func (s *valueVariable) initializeProperties(v reflect.Value, typ reflect.Type) {
- v.Set(reflect.Zero(typ))
+ initializePropertiesWithDefault(v, typ)
}
+// PropertiesToApply returns an interface{} value based on initializeProperties to be applied to
+// the module. If the variable was not set, conditions_default interface will be returned;
+// otherwise, the interface in values, without conditions_default will be returned with all
+// appropriate string substitutions based on variable being set.
func (s *valueVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
- if !config.IsSet(s.variable) || !values.IsValid() {
+ // If this variable was not referenced in the module, there are no properties to apply.
+ if !values.IsValid() || values.Elem().IsZero() {
return nil, nil
}
+ if !config.IsSet(s.variable) {
+ return conditionsDefaultField(values.Elem().Elem()).Interface(), nil
+ }
configValue := config.String(s.variable)
- propStruct := values.Elem().Elem()
+ values = removeDefault(values)
+ propStruct := values.Elem()
if !propStruct.IsValid() {
return nil, nil
}
diff --git a/android/soongconfig/modules_test.go b/android/soongconfig/modules_test.go
index fb0e189..b824c78 100644
--- a/android/soongconfig/modules_test.go
+++ b/android/soongconfig/modules_test.go
@@ -254,67 +254,75 @@
A *string
B bool
}
-type soongConfigVariables struct {
- Bool_var properties
- Other_bool_var properties
+
+type boolVarProps struct {
+ A *string
+ B bool
+ Conditions_default *properties
}
-type soongConfigProps struct {
- Soong_config_variables soongConfigVariables
+type soongConfigVars struct {
+ Bool_var interface{}
}
func Test_PropertiesToApply(t *testing.T) {
-
- mt := &ModuleType{
- BaseModuleType: "foo",
- ConfigNamespace: "bar",
- Variables: []soongConfigVariable{
- newBoolVariable("bool_var"),
- newBoolVariable("other_bool_var"),
- },
- affectableProperties: []string{
- "a",
- "b",
- },
+ mt, _ := newModuleType(&ModuleTypeProperties{
+ Module_type: "foo",
+ Config_namespace: "bar",
+ Bool_variables: []string{"bool_var"},
+ Properties: []string{"a", "b"},
+ })
+ boolVarPositive := &properties{
+ A: proptools.StringPtr("A"),
+ B: true,
}
- props := soongConfigProps{
- Soong_config_variables: soongConfigVariables{
- Bool_var: properties{
- A: proptools.StringPtr("a"),
- B: true,
- },
- Other_bool_var: properties{
- A: proptools.StringPtr("other"),
- B: false,
+ conditionsDefault := &properties{
+ A: proptools.StringPtr("default"),
+ B: false,
+ }
+ actualProps := &struct {
+ Soong_config_variables soongConfigVars
+ }{
+ Soong_config_variables: soongConfigVars{
+ Bool_var: &boolVarProps{
+ A: boolVarPositive.A,
+ B: boolVarPositive.B,
+ Conditions_default: conditionsDefault,
},
},
}
+ props := reflect.ValueOf(actualProps)
testCases := []struct {
+ name string
config SoongConfig
wantProps []interface{}
}{
{
- config: Config(map[string]string{}),
+ name: "no_vendor_config",
+ config: Config(map[string]string{}),
+ wantProps: []interface{}{conditionsDefault},
},
{
+ name: "vendor_config_false",
+ config: Config(map[string]string{"bool_var": "n"}),
+ wantProps: []interface{}{conditionsDefault},
+ },
+ {
+ name: "bool_var_true",
config: Config(map[string]string{"bool_var": "y"}),
- wantProps: []interface{}{props.Soong_config_variables.Bool_var},
- },
- {
- config: Config(map[string]string{"other_bool_var": "y"}),
- wantProps: []interface{}{props.Soong_config_variables.Other_bool_var},
+ wantProps: []interface{}{boolVarPositive},
},
}
for _, tc := range testCases {
- gotProps, err := PropertiesToApply(mt, reflect.ValueOf(&props), tc.config)
+ gotProps, err := PropertiesToApply(mt, props, tc.config)
if err != nil {
- t.Errorf("Unexpected error in PropertiesToApply: %s", err)
+ t.Errorf("%s: Unexpected error in PropertiesToApply: %s", tc.name, err)
}
if !reflect.DeepEqual(gotProps, tc.wantProps) {
- t.Errorf("Expected %s, got %s", tc.wantProps, gotProps)
+ t.Errorf("%s: Expected %s, got %s", tc.name, tc.wantProps, gotProps)
}
}
}
diff --git a/android/testing.go b/android/testing.go
index 470cfd6..76172d1 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -57,6 +57,7 @@
type TestContext struct {
*Context
preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc
+ bp2buildMutators []RegisterMutatorFunc
NameResolver *NameResolver
}
@@ -81,12 +82,27 @@
ctx.finalDeps = append(ctx.finalDeps, f)
}
+// RegisterBp2BuildMutator registers a BazelTargetModule mutator for converting a module
+// type to the equivalent Bazel target.
+func (ctx *TestContext) RegisterBp2BuildMutator(moduleType string, m func(TopDownMutatorContext)) {
+ mutatorName := moduleType + "_bp2build"
+ f := func(ctx RegisterMutatorsContext) {
+ ctx.TopDown(mutatorName, m)
+ }
+ bp2buildMutators = append(bp2buildMutators, f)
+}
+
func (ctx *TestContext) Register() {
registerMutators(ctx.Context.Context, ctx.preArch, ctx.preDeps, ctx.postDeps, ctx.finalDeps)
ctx.RegisterSingletonType("env", EnvSingleton)
}
+// RegisterForBazelConversion prepares a test context for bp2build conversion.
+func (ctx *TestContext) RegisterForBazelConversion() {
+ RegisterMutatorsForBazelConversion(ctx.Context.Context, bp2buildMutators)
+}
+
func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) {
// This function adapts the old style ParseFileList calls that are spread throughout the tests
// to the new style that takes a config.
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index a5cfb83..c4ea381 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -171,7 +171,10 @@
ExtServices-core(minSdkVersion:current)
flatbuffer_headers(minSdkVersion:(no version))
fmtlib(minSdkVersion:29)
+framework-permission(minSdkVersion:30)
framework-permission(minSdkVersion:current)
+framework-permission-s(minSdkVersion:30)
+framework-permission-s-shared(minSdkVersion:30)
framework-sdkextensions(minSdkVersion:30)
framework-sdkextensions(minSdkVersion:current)
framework-statsd(minSdkVersion:current)
@@ -456,6 +459,7 @@
mediaswcodec(minSdkVersion:29)
metrics-constants-protos(minSdkVersion:29)
modules-utils-build(minSdkVersion:29)
+modules-utils-os(minSdkVersion:30)
ndk_crtbegin_so.19(minSdkVersion:(no version))
ndk_crtbegin_so.21(minSdkVersion:(no version))
ndk_crtbegin_so.27(minSdkVersion:(no version))
@@ -573,7 +577,9 @@
prebuilt_test_framework-sdkextensions(minSdkVersion:(no version))
server_configurable_flags(minSdkVersion:29)
service-media-s(minSdkVersion:29)
+service-permission(minSdkVersion:30)
service-permission(minSdkVersion:current)
+service-permission-shared(minSdkVersion:30)
service-statsd(minSdkVersion:current)
SettingsLibActionBarShadow(minSdkVersion:21)
SettingsLibAppPreference(minSdkVersion:21)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index d288414..b1e8480 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -248,6 +248,7 @@
cc.RegisterRequiredBuildComponentsForTest(ctx)
rust.RegisterRequiredBuildComponentsForTest(ctx)
+ java.RegisterRequiredBuildComponentsForTest(ctx)
ctx.RegisterModuleType("cc_test", cc.TestFactory)
ctx.RegisterModuleType("vndk_prebuilt_shared", cc.VndkPrebuiltSharedFactory)
@@ -256,14 +257,6 @@
ctx.RegisterModuleType("platform_compat_config", java.PlatformCompatConfigFactory)
ctx.RegisterModuleType("sh_binary", sh.ShBinaryFactory)
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
- java.RegisterJavaBuildComponents(ctx)
- java.RegisterSystemModulesBuildComponents(ctx)
- java.RegisterAppBuildComponents(ctx)
- java.RegisterAppImportBuildComponents(ctx)
- java.RegisterAppSetBuildComponents(ctx)
- java.RegisterRuntimeResourceOverlayBuildComponents(ctx)
- java.RegisterSdkLibraryBuildComponents(ctx)
- java.RegisterPrebuiltApisBuildComponents(ctx)
ctx.RegisterSingletonType("apex_keys_text", apexKeysTextFactory)
ctx.RegisterModuleType("bpf", bpf.BpfFactory)
@@ -5957,17 +5950,13 @@
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
android.RegisterPrebuiltMutators(ctx)
cc.RegisterRequiredBuildComponentsForTest(ctx)
- java.RegisterJavaBuildComponents(ctx)
- java.RegisterSystemModulesBuildComponents(ctx)
- java.RegisterAppBuildComponents(ctx)
- java.RegisterDexpreoptBootJarsComponents(ctx)
+ java.RegisterRequiredBuildComponentsForTest(ctx)
ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
ctx.PreDepsMutators(RegisterPreDepsMutators)
ctx.PostDepsMutators(RegisterPostDepsMutators)
ctx.Register()
- _ = dexpreopt.GlobalSoongConfigForTests(config)
dexpreopt.RegisterToolModulesForTest(ctx)
pathCtx := android.PathContextForTesting(config)
dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
@@ -6164,9 +6153,7 @@
ctx.RegisterModuleType("apex_key", ApexKeyFactory)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
cc.RegisterRequiredBuildComponentsForTest(ctx)
- java.RegisterJavaBuildComponents(ctx)
- java.RegisterSystemModulesBuildComponents(ctx)
- java.RegisterDexpreoptBootJarsComponents(ctx)
+ java.RegisterRequiredBuildComponentsForTest(ctx)
ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
ctx.PreDepsMutators(RegisterPreDepsMutators)
ctx.PostDepsMutators(RegisterPostDepsMutators)
diff --git a/bazel/properties.go b/bazel/properties.go
index 8bb1956..ac0047b 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -19,9 +19,16 @@
Label string
}
-// Properties contains common module properties for migration purposes.
+// Properties contains common module properties for Bazel migration purposes.
type Properties struct {
// In USE_BAZEL_ANALYSIS=1 mode, this represents the Bazel target replacing
// this Soong module.
Bazel_module bazelModuleProperties
}
+
+// BazelTargetModuleProperties contain properties and metadata used for
+// Blueprint to BUILD file conversion.
+type BazelTargetModuleProperties struct {
+ // The Bazel rule class for this target.
+ Rule_class string
+}
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 49587f4..8007574 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -10,6 +10,7 @@
],
deps: [
"soong-android",
+ "soong-bazel",
],
testSrcs: [
"build_conversion_test.go",
diff --git a/bp2build/androidbp_to_build_templates.go b/bp2build/androidbp_to_build_templates.go
index 75c3ccb..9bac86b 100644
--- a/bp2build/androidbp_to_build_templates.go
+++ b/bp2build/androidbp_to_build_templates.go
@@ -15,7 +15,7 @@
package bp2build
const (
- // The default `load` preamble for every generated BUILD file.
+ // The default `load` preamble for every generated queryview BUILD file.
soongModuleLoad = `package(default_visibility = ["//visibility:public"])
load("//build/bazel/queryview_rules:soong_module.bzl", "soong_module")
@@ -31,6 +31,10 @@
module_deps = %s,
%s)`
+ bazelTarget = `%s(
+ name = "%s",
+%s)`
+
// A simple provider to mark and differentiate Soong module rule shims from
// regular Bazel rules. Every Soong module rule shim returns a
// SoongModuleInfo provider, and can only depend on rules returning
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index 49729e0..75b6097 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -28,9 +28,9 @@
ruleShims := CreateRuleShims(android.ModuleTypeFactories())
- buildToTargets := GenerateSoongModuleTargets(ctx.Context())
+ buildToTargets := GenerateSoongModuleTargets(ctx.Context(), true)
- filesToWrite := CreateBazelFiles(ruleShims, buildToTargets)
+ filesToWrite := CreateBazelFiles(ruleShims, buildToTargets, true)
for _, f := range filesToWrite {
if err := writeFile(outputDir, ctx, f); err != nil {
fmt.Errorf("Failed to write %q (dir %q) due to %q", f.Basename, f.Dir, err)
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index bece8f6..da2fb7f 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -73,16 +73,51 @@
return attributes
}
-func GenerateSoongModuleTargets(ctx bpToBuildContext) map[string][]BazelTarget {
+func GenerateSoongModuleTargets(ctx bpToBuildContext, bp2buildEnabled bool) map[string][]BazelTarget {
buildFileToTargets := make(map[string][]BazelTarget)
ctx.VisitAllModules(func(m blueprint.Module) {
dir := ctx.ModuleDir(m)
- t := generateSoongModuleTarget(ctx, m)
+ var t BazelTarget
+
+ if bp2buildEnabled {
+ if _, ok := m.(android.BazelTargetModule); !ok {
+ return
+ }
+ t = generateBazelTarget(ctx, m)
+ } else {
+ t = generateSoongModuleTarget(ctx, m)
+ }
+
buildFileToTargets[ctx.ModuleDir(m)] = append(buildFileToTargets[dir], t)
})
return buildFileToTargets
}
+func generateBazelTarget(ctx bpToBuildContext, m blueprint.Module) BazelTarget {
+ // extract the bazel attributes from the module.
+ props := getBuildProperties(ctx, m)
+
+ // extract the rule class name from the attributes. Since the string value
+ // will be string-quoted, remove the quotes here.
+ ruleClass := strings.Replace(props.Attrs["rule_class"], "\"", "", 2)
+ // Delete it from being generated in the BUILD file.
+ delete(props.Attrs, "rule_class")
+
+ // Return the Bazel target with rule class and attributes, ready to be
+ // code-generated.
+ attributes := propsToAttributes(props.Attrs)
+ targetName := targetNameForBp2Build(ctx, m)
+ return BazelTarget{
+ name: targetName,
+ content: fmt.Sprintf(
+ bazelTarget,
+ ruleClass,
+ targetName,
+ attributes,
+ ),
+ }
+}
+
// Convert a module and its deps and props into a Bazel macro/rule
// representation in the BUILD file.
func generateSoongModuleTarget(ctx bpToBuildContext, m blueprint.Module) BazelTarget {
@@ -306,6 +341,10 @@
return strings.Repeat(" ", indent)
}
+func targetNameForBp2Build(c bpToBuildContext, logicModule blueprint.Module) string {
+ return strings.Replace(c.ModuleName(logicModule), "__bp2build__", "", 1)
+}
+
func targetNameWithVariant(c bpToBuildContext, logicModule blueprint.Module) string {
name := ""
if c.ModuleSubDir(logicModule) != "" {
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 4e31aa7..5fd3999 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -200,9 +200,9 @@
_, errs = ctx.PrepareBuildActions(config)
android.FailIfErrored(t, errs)
- bazelTargets := GenerateSoongModuleTargets(ctx.Context.Context)[dir]
- if g, w := len(bazelTargets), 1; g != w {
- t.Fatalf("Expected %d bazel target, got %d", w, g)
+ bazelTargets := GenerateSoongModuleTargets(ctx.Context.Context, false)[dir]
+ if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount {
+ t.Fatalf("Expected %d bazel target, got %d", expectedCount, actualCount)
}
actualBazelTarget := bazelTargets[0]
@@ -210,7 +210,123 @@
t.Errorf(
"Expected generated Bazel target to be '%s', got '%s'",
testCase.expectedBazelTarget,
- actualBazelTarget,
+ actualBazelTarget.content,
+ )
+ }
+ }
+}
+
+func TestGenerateBazelTargetModules(t *testing.T) {
+ testCases := []struct {
+ bp string
+ expectedBazelTarget string
+ }{
+ {
+ bp: `custom {
+ name: "foo",
+ string_list_prop: ["a", "b"],
+ string_prop: "a",
+}`,
+ expectedBazelTarget: `custom(
+ name = "foo",
+ string_list_prop = [
+ "a",
+ "b",
+ ],
+ string_prop = "a",
+)`,
+ },
+ }
+
+ dir := "."
+ for _, testCase := range testCases {
+ config := android.TestConfig(buildDir, nil, testCase.bp, nil)
+ ctx := android.NewTestContext(config)
+ ctx.RegisterModuleType("custom", customModuleFactory)
+ ctx.RegisterBp2BuildMutator("custom", customBp2BuildMutator)
+ ctx.RegisterForBazelConversion()
+
+ _, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.ResolveDependencies(config)
+ android.FailIfErrored(t, errs)
+
+ bazelTargets := GenerateSoongModuleTargets(ctx.Context.Context, true)[dir]
+ if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount {
+ t.Fatalf("Expected %d bazel target, got %d", expectedCount, actualCount)
+ }
+
+ actualBazelTarget := bazelTargets[0]
+ if actualBazelTarget.content != testCase.expectedBazelTarget {
+ t.Errorf(
+ "Expected generated Bazel target to be '%s', got '%s'",
+ testCase.expectedBazelTarget,
+ actualBazelTarget.content,
+ )
+ }
+ }
+}
+
+func TestModuleTypeBp2Build(t *testing.T) {
+ testCases := []struct {
+ moduleTypeUnderTest string
+ moduleTypeUnderTestFactory android.ModuleFactory
+ bp string
+ expectedBazelTarget string
+ }{
+ {
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
+ bp: `filegroup {
+ name: "foo",
+ srcs: [],
+}`,
+ expectedBazelTarget: `filegroup(
+ name = "foo",
+ srcs = [
+ ],
+)`,
+ },
+ {
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
+ bp: `filegroup {
+ name: "foo",
+ srcs: ["a", "b"],
+}`,
+ expectedBazelTarget: `filegroup(
+ name = "foo",
+ srcs = [
+ "a",
+ "b",
+ ],
+)`,
+ },
+ }
+
+ dir := "."
+ for _, testCase := range testCases {
+ config := android.TestConfig(buildDir, nil, testCase.bp, nil)
+ ctx := android.NewTestContext(config)
+ ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+ ctx.RegisterForBazelConversion()
+
+ _, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.ResolveDependencies(config)
+ android.FailIfErrored(t, errs)
+
+ bazelTargets := GenerateSoongModuleTargets(ctx.Context.Context, true)[dir]
+ if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount {
+ t.Fatalf("Expected %d bazel target, got %d", expectedCount, actualCount)
+ }
+
+ actualBazelTarget := bazelTargets[0]
+ if actualBazelTarget.content != testCase.expectedBazelTarget {
+ t.Errorf(
+ "Expected generated Bazel target to be '%s', got '%s'",
+ testCase.expectedBazelTarget,
+ actualBazelTarget.content,
)
}
}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index 8bea3f6..01c7271 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -172,7 +172,7 @@
content: "irrelevant",
},
}
- files := CreateBazelFiles(ruleShims, make(map[string][]BazelTarget))
+ files := CreateBazelFiles(ruleShims, make(map[string][]BazelTarget), false)
var actualSoongModuleBzl BazelFile
for _, f := range files {
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index cdfb38b..cccc474 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -17,7 +17,8 @@
func CreateBazelFiles(
ruleShims map[string]RuleShim,
- buildToTargets map[string][]BazelTarget) []BazelFile {
+ buildToTargets map[string][]BazelTarget,
+ bp2buildEnabled bool) []BazelFile {
files := make([]BazelFile, 0, len(ruleShims)+len(buildToTargets)+numAdditionalFiles)
// Write top level files: WORKSPACE and BUILD. These files are empty.
@@ -26,22 +27,30 @@
files = append(files, newFile("", "BUILD", ""))
files = append(files, newFile(bazelRulesSubDir, "BUILD", ""))
- files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl))
- for bzlFileName, ruleShim := range ruleShims {
- files = append(files, newFile(bazelRulesSubDir, bzlFileName+".bzl", ruleShim.content))
+ if !bp2buildEnabled {
+ // These files are only used for queryview.
+ files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl))
+
+ for bzlFileName, ruleShim := range ruleShims {
+ files = append(files, newFile(bazelRulesSubDir, bzlFileName+".bzl", ruleShim.content))
+ }
+ files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims)))
}
- files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims)))
- files = append(files, createBuildFiles(buildToTargets)...)
+ files = append(files, createBuildFiles(buildToTargets, bp2buildEnabled)...)
return files
}
-func createBuildFiles(buildToTargets map[string][]BazelTarget) []BazelFile {
+func createBuildFiles(buildToTargets map[string][]BazelTarget, bp2buildEnabled bool) []BazelFile {
files := make([]BazelFile, 0, len(buildToTargets))
for _, dir := range android.SortedStringKeys(buildToTargets) {
content := soongModuleLoad
+ if bp2buildEnabled {
+ // No need to load soong_module for bp2build BUILD files.
+ content = ""
+ }
targets := buildToTargets[dir]
sort.Slice(targets, func(i, j int) bool { return targets[i].name < targets[j].name })
for _, t := range targets {
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index a38fa6a..b40aa1b 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -19,12 +19,44 @@
"testing"
)
-func TestCreateBazelFiles_AddsTopLevelFiles(t *testing.T) {
- files := CreateBazelFiles(map[string]RuleShim{}, map[string][]BazelTarget{})
- expectedFilePaths := []struct {
- dir string
- basename string
- }{
+type filepath struct {
+ dir string
+ basename string
+}
+
+func assertFilecountsAreEqual(t *testing.T, actual []BazelFile, expected []filepath) {
+ if a, e := len(actual), len(expected); a != e {
+ t.Errorf("Expected %d files, got %d", e, a)
+ }
+}
+
+func assertFileContent(t *testing.T, actual []BazelFile, expected []filepath) {
+ for i := range actual {
+ if g, w := actual[i], expected[i]; g.Dir != w.dir || g.Basename != w.basename {
+ t.Errorf("Did not find expected file %s/%s", g.Dir, g.Basename)
+ } else if g.Basename == "BUILD" || g.Basename == "WORKSPACE" {
+ if g.Contents != "" {
+ t.Errorf("Expected %s to have no content.", g)
+ }
+ } else if g.Contents == "" {
+ t.Errorf("Contents of %s unexpected empty.", g)
+ }
+ }
+}
+
+func sortFiles(files []BazelFile) {
+ sort.Slice(files, func(i, j int) bool {
+ if dir1, dir2 := files[i].Dir, files[j].Dir; dir1 == dir2 {
+ return files[i].Basename < files[j].Basename
+ } else {
+ return dir1 < dir2
+ }
+ })
+}
+
+func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) {
+ files := CreateBazelFiles(map[string]RuleShim{}, map[string][]BazelTarget{}, false)
+ expectedFilePaths := []filepath{
{
dir: "",
basename: "BUILD",
@@ -47,27 +79,29 @@
},
}
- if g, w := len(files), len(expectedFilePaths); g != w {
- t.Errorf("Expected %d files, got %d", w, g)
+ assertFilecountsAreEqual(t, files, expectedFilePaths)
+ sortFiles(files)
+ assertFileContent(t, files, expectedFilePaths)
+}
+
+func TestCreateBazelFiles_Bp2Build_AddsTopLevelFiles(t *testing.T) {
+ files := CreateBazelFiles(map[string]RuleShim{}, map[string][]BazelTarget{}, true)
+ expectedFilePaths := []filepath{
+ {
+ dir: "",
+ basename: "BUILD",
+ },
+ {
+ dir: "",
+ basename: "WORKSPACE",
+ },
+ {
+ dir: bazelRulesSubDir,
+ basename: "BUILD",
+ },
}
- sort.Slice(files, func(i, j int) bool {
- if dir1, dir2 := files[i].Dir, files[j].Dir; dir1 == dir2 {
- return files[i].Basename < files[j].Basename
- } else {
- return dir1 < dir2
- }
- })
-
- for i := range files {
- if g, w := files[i], expectedFilePaths[i]; g.Dir != w.dir || g.Basename != w.basename {
- t.Errorf("Did not find expected file %s/%s", g.Dir, g.Basename)
- } else if g.Basename == "BUILD" || g.Basename == "WORKSPACE" {
- if g.Contents != "" {
- t.Errorf("Expected %s to have no content.", g)
- }
- } else if g.Contents == "" {
- t.Errorf("Contents of %s unexpected empty.", g)
- }
- }
+ assertFilecountsAreEqual(t, files, expectedFilePaths)
+ sortFiles(files)
+ assertFileContent(t, files, expectedFilePaths)
}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 2da32c6..4c31d2d 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -2,6 +2,9 @@
import (
"android/soong/android"
+ "android/soong/bazel"
+
+ "github.com/google/blueprint/proptools"
)
type nestedProps struct {
@@ -100,3 +103,37 @@
android.InitDefaultsModule(m)
return m
}
+
+type customBazelModuleAttributes struct {
+ Name *string
+ String_prop string
+ String_list_prop []string
+}
+
+type customBazelModule struct {
+ android.BazelTargetModuleBase
+ customBazelModuleAttributes
+}
+
+func customBazelModuleFactory() android.Module {
+ module := &customBazelModule{}
+ module.AddProperties(&module.customBazelModuleAttributes)
+ android.InitBazelTargetModule(module)
+ return module
+}
+
+func (m *customBazelModule) Name() string { return m.BaseModuleName() }
+func (m *customBazelModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
+
+func customBp2BuildMutator(ctx android.TopDownMutatorContext) {
+ if m, ok := ctx.Module().(*customModule); ok {
+ name := "__bp2build__" + m.Name()
+ ctx.CreateModule(customBazelModuleFactory, &customBazelModuleAttributes{
+ Name: proptools.StringPtr(name),
+ String_prop: m.props.String_prop,
+ String_list_prop: m.props.String_list_prop,
+ }, &bazel.BazelTargetModuleProperties{
+ Rule_class: "custom",
+ })
+ }
+}
diff --git a/cc/cc.go b/cc/cc.go
index 75b13fd..8755efe 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1043,10 +1043,6 @@
c.AddProperties(feature.props()...)
}
- c.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, os android.OsType) bool {
- // Windows builds always prefer 32-bit
- return os == android.Windows
- })
android.InitAndroidArchModule(c, c.hod, c.multilib)
android.InitApexModule(c)
android.InitSdkAwareModule(c)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 0cd83a7..d0d8759 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -1624,17 +1624,19 @@
assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a")
}
-func assertExcludeFromVendorSnapshotIs(t *testing.T, c *Module, expected bool) {
+func assertExcludeFromVendorSnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool) {
t.Helper()
- if c.ExcludeFromVendorSnapshot() != expected {
- t.Errorf("expected %q ExcludeFromVendorSnapshot to be %t", c.String(), expected)
+ m := ctx.ModuleForTests(name, vendorVariant).Module().(*Module)
+ if m.ExcludeFromVendorSnapshot() != expected {
+ t.Errorf("expected %q ExcludeFromVendorSnapshot to be %t", m.String(), expected)
}
}
-func assertExcludeFromRecoverySnapshotIs(t *testing.T, c *Module, expected bool) {
+func assertExcludeFromRecoverySnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool) {
t.Helper()
- if c.ExcludeFromRecoverySnapshot() != expected {
- t.Errorf("expected %q ExcludeFromRecoverySnapshot to be %t", c.String(), expected)
+ m := ctx.ModuleForTests(name, recoveryVariant).Module().(*Module)
+ if m.ExcludeFromRecoverySnapshot() != expected {
+ t.Errorf("expected %q ExcludeFromRecoverySnapshot to be %t", m.String(), expected)
}
}
@@ -1658,6 +1660,12 @@
vendor: true,
exclude_from_vendor_snapshot: true,
}
+ cc_library_shared {
+ name: "libavailable_exclude",
+ srcs: ["src/exclude.cpp"],
+ vendor_available: true,
+ exclude_from_vendor_snapshot: true,
+ }
`
vendorProprietaryBp := `
@@ -1691,13 +1699,13 @@
android.FailIfErrored(t, errs)
// Test an include and exclude framework module.
- assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libinclude", coreVariant).Module().(*Module), false)
- assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libinclude", vendorVariant).Module().(*Module), false)
- assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libexclude", vendorVariant).Module().(*Module), true)
+ assertExcludeFromVendorSnapshotIs(t, ctx, "libinclude", false)
+ assertExcludeFromVendorSnapshotIs(t, ctx, "libexclude", true)
+ assertExcludeFromVendorSnapshotIs(t, ctx, "libavailable_exclude", true)
// A vendor module is excluded, but by its path, not the
// exclude_from_vendor_snapshot property.
- assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libvendor", vendorVariant).Module().(*Module), false)
+ assertExcludeFromVendorSnapshotIs(t, ctx, "libvendor", false)
// Verify the content of the vendor snapshot.
@@ -1728,6 +1736,8 @@
excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json"))
checkSnapshotExclude(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json"))
+ checkSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant)
+ excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json"))
}
// Verify that each json file for an included module has a rule.
@@ -1789,53 +1799,6 @@
})
}
-func TestVendorSnapshotExcludeWithVendorAvailable(t *testing.T) {
-
- // This test verifies that using the exclude_from_vendor_snapshot
- // property on a module that is vendor available generates an error. A
- // vendor available module must be captured in the vendor snapshot and
- // must not built from source when building the vendor image against
- // the vendor snapshot.
-
- frameworkBp := `
- cc_library_shared {
- name: "libinclude",
- srcs: ["src/include.cpp"],
- vendor_available: true,
- exclude_from_vendor_snapshot: true,
- }
- `
-
- depsBp := GatherRequiredDepsForTest(android.Android)
-
- mockFS := map[string][]byte{
- "deps/Android.bp": []byte(depsBp),
- "framework/Android.bp": []byte(frameworkBp),
- "framework/include.cpp": nil,
- }
-
- config := TestConfig(buildDir, android.Android, nil, "", mockFS)
- config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
- config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
- ctx := CreateTestContext(config)
- ctx.Register()
-
- _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp"})
- android.FailIfErrored(t, errs)
-
- _, errs = ctx.PrepareBuildActions(config)
- android.CheckErrorsAgainstExpectations(t, errs, []string{
- `module "libinclude\{.+,image:,arch:arm64_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`,
- `module "libinclude\{.+,image:,arch:arm_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`,
- `module "libinclude\{.+,image:vendor.+,arch:arm64_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`,
- `module "libinclude\{.+,image:vendor.+,arch:arm_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`,
- `module "libinclude\{.+,image:,arch:arm64_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`,
- `module "libinclude\{.+,image:,arch:arm_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`,
- `module "libinclude\{.+,image:vendor.+,arch:arm64_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`,
- `module "libinclude\{.+,image:vendor.+,arch:arm_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`,
- })
-}
-
func TestRecoverySnapshotCapture(t *testing.T) {
bp := `
cc_library {
@@ -1973,7 +1936,7 @@
cc_library_shared {
name: "libinclude",
srcs: ["src/include.cpp"],
- recovery_available: true,
+ recovery_available: true,
}
cc_library_shared {
name: "libexclude",
@@ -1981,12 +1944,18 @@
recovery: true,
exclude_from_recovery_snapshot: true,
}
+ cc_library_shared {
+ name: "libavailable_exclude",
+ srcs: ["src/exclude.cpp"],
+ recovery_available: true,
+ exclude_from_recovery_snapshot: true,
+ }
`
vendorProprietaryBp := `
cc_library_shared {
- name: "libvendor",
- srcs: ["vendor.cpp"],
+ name: "librecovery",
+ srcs: ["recovery.cpp"],
recovery: true,
}
`
@@ -1999,7 +1968,7 @@
"framework/include.cpp": nil,
"framework/exclude.cpp": nil,
"device/Android.bp": []byte(vendorProprietaryBp),
- "device/vendor.cpp": nil,
+ "device/recovery.cpp": nil,
}
config := TestConfig(buildDir, android.Android, nil, "", mockFS)
@@ -2014,13 +1983,13 @@
android.FailIfErrored(t, errs)
// Test an include and exclude framework module.
- assertExcludeFromRecoverySnapshotIs(t, ctx.ModuleForTests("libinclude", coreVariant).Module().(*Module), false)
- assertExcludeFromRecoverySnapshotIs(t, ctx.ModuleForTests("libinclude", recoveryVariant).Module().(*Module), false)
- assertExcludeFromRecoverySnapshotIs(t, ctx.ModuleForTests("libexclude", recoveryVariant).Module().(*Module), true)
+ assertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false)
+ assertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true)
+ assertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true)
- // A vendor module is excluded, but by its path, not the
+ // A recovery module is excluded, but by its path, not the
// exclude_from_recovery_snapshot property.
- assertExcludeFromRecoverySnapshotIs(t, ctx.ModuleForTests("libvendor", recoveryVariant).Module().(*Module), false)
+ assertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false)
// Verify the content of the recovery snapshot.
@@ -2048,8 +2017,10 @@
// Excluded modules
checkSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant)
excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json"))
- checkSnapshotExclude(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
- excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json"))
+ checkSnapshotExclude(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
+ excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json"))
+ checkSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant)
+ excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json"))
}
// Verify that each json file for an included module has a rule.
diff --git a/cc/config/x86_darwin_host.go b/cc/config/x86_darwin_host.go
index d7ff580..1035df3 100644
--- a/cc/config/x86_darwin_host.go
+++ b/cc/config/x86_darwin_host.go
@@ -67,6 +67,7 @@
"10.14",
"10.15",
"11.0",
+ "11.1",
}
darwinAvailableLibraries = append(
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index d9c46ea..2003e03 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -40,10 +40,10 @@
// evalution of a function that may be not be defined.
inImage(m *Module) func() bool
- // Returns the value of the "available" property for a given module for
- // and snapshot, e.g., "vendor_available", "recovery_available", etc.
- // or nil if the property is not defined.
- available(m *Module) *bool
+ // Returns true if the module is private and must not be included in the
+ // snapshot. For example VNDK-private modules must return true for the
+ // vendor snapshots. But false for the recovery snapshots.
+ private(m *Module) bool
// Returns true if a dir under source tree is an SoC-owned proprietary
// directory, such as device/, vendor/, etc.
@@ -112,8 +112,8 @@
return m.InVendor
}
-func (vendorSnapshotImage) available(m *Module) *bool {
- return m.VendorProperties.Vendor_available
+func (vendorSnapshotImage) private(m *Module) bool {
+ return m.IsVndkPrivate()
}
func (vendorSnapshotImage) isProprietaryPath(dir string) bool {
@@ -227,8 +227,9 @@
return m.InRecovery
}
-func (recoverySnapshotImage) available(m *Module) *bool {
- return m.Properties.Recovery_available
+// recovery snapshot does not have private libraries.
+func (recoverySnapshotImage) private(m *Module) bool {
+ return false
}
func (recoverySnapshotImage) isProprietaryPath(dir string) bool {
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 6bd095f..7346aac 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -23,8 +23,6 @@
"sort"
"strings"
- "github.com/google/blueprint/proptools"
-
"android/soong/android"
)
@@ -177,15 +175,15 @@
func isRecoveryProprietaryModule(ctx android.BaseModuleContext) bool {
- // Any module in a vendor proprietary path is a vendor proprietary
+ // Any module in a recovery proprietary path is a recovery proprietary
// module.
if isRecoveryProprietaryPath(ctx.ModuleDir()) {
return true
}
- // However if the module is not in a vendor proprietary path, it may
- // still be a vendor proprietary module. This happens for cc modules
- // that are excluded from the vendor snapshot, and it means that the
+ // However if the module is not in a recovery proprietary path, it may
+ // still be a recovery proprietary module. This happens for cc modules
+ // that are excluded from the recovery snapshot, and it means that the
// vendor has assumed control of the framework-provided module.
if c, ok := ctx.Module().(*Module); ok {
@@ -264,7 +262,7 @@
}
}
if l.static() {
- return m.outputFile.Valid() && proptools.BoolDefault(image.available(m), true)
+ return m.outputFile.Valid() && !image.private(m)
}
if l.shared() {
if !m.outputFile.Valid() {
@@ -282,7 +280,7 @@
// Binaries and Objects
if m.binary() || m.object() {
- return m.outputFile.Valid() && proptools.BoolDefault(image.available(m), true)
+ return m.outputFile.Valid()
}
return false
@@ -526,17 +524,6 @@
ctx.Errorf("module %q in vendor proprietary path %q may not use \"exclude_from_vendor_snapshot: true\"", m.String(), moduleDir)
return
}
- if Bool(c.image.available(m)) {
- // Error: may not combine "vendor_available:
- // true" with "exclude_from_vendor_snapshot:
- // true".
- ctx.Errorf(
- "module %q may not use both \""+
- c.name+
- "_available: true\" and \"exclude_from_vendor_snapshot: true\"",
- m.String())
- return
- }
}
if !isSnapshotAware(ctx.DeviceConfig(), m, inProprietaryPath, apexInfo, c.image) {
diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go
index 79ea94a..305a224 100644
--- a/cmd/soong_build/queryview.go
+++ b/cmd/soong_build/queryview.go
@@ -24,9 +24,9 @@
func createBazelQueryView(ctx *android.Context, bazelQueryViewDir string) error {
ruleShims := bp2build.CreateRuleShims(android.ModuleTypeFactories())
- buildToTargets := bp2build.GenerateSoongModuleTargets(*ctx)
+ buildToTargets := bp2build.GenerateSoongModuleTargets(*ctx, false)
- filesToWrite := bp2build.CreateBazelFiles(ruleShims, buildToTargets)
+ filesToWrite := bp2build.CreateBazelFiles(ruleShims, buildToTargets, false)
for _, f := range filesToWrite {
if err := writeReadOnlyFile(bazelQueryViewDir, f); err != nil {
return err
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index feddfc0..867ece6 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -363,13 +363,6 @@
// createGlobalSoongConfig creates a GlobalSoongConfig from the current context.
// Should not be used in dexpreopt_gen.
func createGlobalSoongConfig(ctx android.ModuleContext) *GlobalSoongConfig {
- if ctx.Config().TestProductVariables != nil {
- // If we're called in a test there'll be a confusing error from the path
- // functions below that gets reported without a stack trace, so let's panic
- // properly with a more helpful message.
- panic("This should not be called from tests. Please call GlobalSoongConfigForTests somewhere in the test setup.")
- }
-
return &GlobalSoongConfig{
Profman: ctx.Config().HostToolPath(ctx, "profman"),
Dex2oat: dex2oatPathFromDep(ctx),
@@ -389,8 +382,7 @@
// being at least one ordinary module with a Dex2oatDepTag dependency.
//
// TODO(b/147613152): Implement a way to deal with dependencies from singletons,
-// and then possibly remove this cache altogether (but the use in
-// GlobalSoongConfigForTests also needs to be rethought).
+// and then possibly remove this cache altogether.
var globalSoongConfigOnceKey = android.NewOnceKey("DexpreoptGlobalSoongConfig")
// GetGlobalSoongConfig creates a GlobalSoongConfig the first time it's called,
@@ -550,18 +542,14 @@
}
}
-func GlobalSoongConfigForTests(config android.Config) *GlobalSoongConfig {
- // Install the test GlobalSoongConfig in the Once cache so that later calls to
- // Get(Cached)GlobalSoongConfig returns it without trying to create a real one.
- return config.Once(globalSoongConfigOnceKey, func() interface{} {
- return &GlobalSoongConfig{
- Profman: android.PathForTesting("profman"),
- Dex2oat: android.PathForTesting("dex2oat"),
- Aapt: android.PathForTesting("aapt"),
- SoongZip: android.PathForTesting("soong_zip"),
- Zip2zip: android.PathForTesting("zip2zip"),
- ManifestCheck: android.PathForTesting("manifest_check"),
- ConstructContext: android.PathForTesting("construct_context"),
- }
- }).(*GlobalSoongConfig)
+func globalSoongConfigForTests() *GlobalSoongConfig {
+ return &GlobalSoongConfig{
+ Profman: android.PathForTesting("profman"),
+ Dex2oat: android.PathForTesting("dex2oat"),
+ Aapt: android.PathForTesting("aapt"),
+ SoongZip: android.PathForTesting("soong_zip"),
+ Zip2zip: android.PathForTesting("zip2zip"),
+ ManifestCheck: android.PathForTesting("manifest_check"),
+ ConstructContext: android.PathForTesting("construct_context"),
+ }
}
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 59278fd..af73d0c 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -61,7 +61,7 @@
func TestDexPreopt(t *testing.T) {
config := android.TestConfig("out", nil, "", nil)
ctx := android.BuilderContextForTesting(config)
- globalSoong := GlobalSoongConfigForTests(config)
+ globalSoong := globalSoongConfigForTests()
global := GlobalConfigForTests(ctx)
module := testSystemModuleConfig(ctx, "test")
@@ -83,7 +83,7 @@
func TestDexPreoptSystemOther(t *testing.T) {
config := android.TestConfig("out", nil, "", nil)
ctx := android.BuilderContextForTesting(config)
- globalSoong := GlobalSoongConfigForTests(config)
+ globalSoong := globalSoongConfigForTests()
global := GlobalConfigForTests(ctx)
systemModule := testSystemModuleConfig(ctx, "Stest")
systemProductModule := testSystemProductModuleConfig(ctx, "SPtest")
@@ -143,7 +143,7 @@
func TestDexPreoptProfile(t *testing.T) {
config := android.TestConfig("out", nil, "", nil)
ctx := android.BuilderContextForTesting(config)
- globalSoong := GlobalSoongConfigForTests(config)
+ globalSoong := globalSoongConfigForTests()
global := GlobalConfigForTests(ctx)
module := testSystemModuleConfig(ctx, "test")
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index c8f9538..004cbbb 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -25,6 +25,18 @@
"github.com/google/blueprint/proptools"
)
+// =================================================================================================
+// WIP - see http://b/177892522 for details
+//
+// The build support for boot images is currently being migrated away from singleton to modules so
+// the documentation may not be strictly accurate. Rather than update the documentation at every
+// step which will create a lot of churn the changes that have been made will be listed here and the
+// documentation will be updated once it is closer to the final result.
+//
+// Changes:
+// 1) dex_bootjars is now a singleton module and not a plain singleton.
+// =================================================================================================
+
// This comment describes:
// 1. ART boot images in general (their types, structure, file layout, etc.)
// 2. build system support for boot images
@@ -124,7 +136,7 @@
// The primary ART boot image needs to be compiled with one dex2oat invocation that depends on DEX
// jars for the core libraries. Framework boot image extension needs to be compiled with one dex2oat
// invocation that depends on the primary ART boot image and all bootclasspath DEX jars except the
-// Core libraries.
+// core libraries as they are already part of the primary ART boot image.
//
// 2.1. Libraries that go in the boot images
// -----------------------------------------
@@ -339,20 +351,24 @@
return append(imageLocations, dexpreopt.PathToLocation(image.images, image.target.Arch.ArchType))
}
-func dexpreoptBootJarsFactory() android.Singleton {
- return &dexpreoptBootJars{}
+func dexpreoptBootJarsFactory() android.SingletonModule {
+ m := &dexpreoptBootJars{}
+ android.InitAndroidModule(m)
+ return m
}
func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) {
- ctx.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
+ ctx.RegisterSingletonModuleType("dex_bootjars", dexpreoptBootJarsFactory)
}
func SkipDexpreoptBootJars(ctx android.PathContext) bool {
return dexpreopt.GetGlobalConfig(ctx).DisablePreoptBootImages
}
-// Singleton for generating boot image build rules.
+// Singleton module for generating boot image build rules.
type dexpreoptBootJars struct {
+ android.SingletonModuleBase
+
// Default boot image config (currently always the Framework boot image extension). It should be
// noted that JIT-Zygote builds use ART APEX image instead of the Framework boot image extension,
// but the switch is handled not here, but in the makefiles (triggered with
@@ -385,8 +401,15 @@
return files
}
+// Provide paths to boot images for use by modules that depend upon them.
+//
+// The build rules are created in GenerateSingletonBuildActions().
+func (d *dexpreoptBootJars) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // Placeholder for now.
+}
+
// Generate build rules for boot images.
-func (d *dexpreoptBootJars) GenerateBuildActions(ctx android.SingletonContext) {
+func (d *dexpreoptBootJars) GenerateSingletonBuildActions(ctx android.SingletonContext) {
if SkipDexpreoptBootJars(ctx) {
return
}
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index 95fe5e1..48bc244 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -52,7 +52,6 @@
dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
ctx := testContext(config)
- RegisterDexpreoptBootJarsComponents(ctx)
run(t, ctx, config)
dexpreoptBootJars := ctx.SingletonForTests("dex_bootjars")
diff --git a/java/java_test.go b/java/java_test.go
index 1c0738f..7b89848 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -61,33 +61,16 @@
func testConfig(env map[string]string, bp string, fs map[string][]byte) android.Config {
bp += dexpreopt.BpToolModulesForTest()
- config := TestConfig(buildDir, env, bp, fs)
-
- // Set up the global Once cache used for dexpreopt.GlobalSoongConfig, so that
- // it doesn't create a real one, which would fail.
- _ = dexpreopt.GlobalSoongConfigForTests(config)
-
- return config
+ return TestConfig(buildDir, env, bp, fs)
}
func testContext(config android.Config) *android.TestContext {
ctx := android.NewTestArchContext(config)
- RegisterJavaBuildComponents(ctx)
- RegisterAppBuildComponents(ctx)
- RegisterAppImportBuildComponents(ctx)
- RegisterAppSetBuildComponents(ctx)
- RegisterAARBuildComponents(ctx)
- RegisterGenRuleBuildComponents(ctx)
- RegisterRuntimeResourceOverlayBuildComponents(ctx)
- RegisterSystemModulesBuildComponents(ctx)
+ RegisterRequiredBuildComponentsForTest(ctx)
ctx.RegisterModuleType("java_plugin", PluginFactory)
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
ctx.RegisterModuleType("python_binary_host", python.PythonBinaryHostFactory)
- RegisterDocsBuildComponents(ctx)
- RegisterStubsBuildComponents(ctx)
- RegisterPrebuiltApisBuildComponents(ctx)
- RegisterSdkLibraryBuildComponents(ctx)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
ctx.PreArchMutators(android.RegisterComponentsMutator)
diff --git a/java/testing.go b/java/testing.go
index fc4e477..0b1e2eb 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -95,6 +95,29 @@
return fs
}
+// Register build components provided by this package that are needed by tests.
+//
+// In particular this must register all the components that are used in the `Android.bp` snippet
+// returned by GatherRequiredDepsForTest()
+func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) {
+ RegisterAARBuildComponents(ctx)
+ RegisterAppBuildComponents(ctx)
+ RegisterAppImportBuildComponents(ctx)
+ RegisterAppSetBuildComponents(ctx)
+ RegisterDexpreoptBootJarsComponents(ctx)
+ RegisterDocsBuildComponents(ctx)
+ RegisterGenRuleBuildComponents(ctx)
+ RegisterJavaBuildComponents(ctx)
+ RegisterPrebuiltApisBuildComponents(ctx)
+ RegisterRuntimeResourceOverlayBuildComponents(ctx)
+ RegisterSdkLibraryBuildComponents(ctx)
+ RegisterStubsBuildComponents(ctx)
+ RegisterSystemModulesBuildComponents(ctx)
+}
+
+// Gather the module definitions needed by tests that depend upon code from this package.
+//
+// Returns an `Android.bp` snippet that defines the modules that are needed by this package.
func GatherRequiredDepsForTest() string {
var bp string
@@ -181,6 +204,13 @@
`, extra)
}
+ // Make sure that the dex_bootjars singleton module is instantiated for the tests.
+ bp += `
+ dex_bootjars {
+ name: "dex_bootjars",
+ }
+`
+
return bp
}
diff --git a/rust/builder.go b/rust/builder.go
index e5f0ab5..baeab69 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -188,7 +188,7 @@
implicits = append(implicits, rustLibsToPaths(deps.DyLibs)...)
implicits = append(implicits, rustLibsToPaths(deps.ProcMacros)...)
implicits = append(implicits, deps.StaticLibs...)
- implicits = append(implicits, deps.SharedLibs...)
+ implicits = append(implicits, deps.SharedLibDeps...)
implicits = append(implicits, deps.srcProviderFiles...)
if deps.CrtBegin.Valid() {
diff --git a/rust/rust.go b/rust/rust.go
index 1fa97af..83add87 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -267,14 +267,15 @@
}
type PathDeps struct {
- DyLibs RustLibraries
- RLibs RustLibraries
- SharedLibs android.Paths
- StaticLibs android.Paths
- ProcMacros RustLibraries
- linkDirs []string
- depFlags []string
- linkObjects []string
+ DyLibs RustLibraries
+ RLibs RustLibraries
+ SharedLibs android.Paths
+ SharedLibDeps android.Paths
+ StaticLibs android.Paths
+ ProcMacros RustLibraries
+ linkDirs []string
+ depFlags []string
+ linkObjects []string
//ReexportedDeps android.Paths
// Used by bindgen modules which call clang
@@ -952,9 +953,15 @@
staticLibDepFiles = append(staticLibDepFiles, dep.OutputFile().Path())
}
+ var sharedLibFiles android.Paths
var sharedLibDepFiles android.Paths
for _, dep := range directSharedLibDeps {
- sharedLibDepFiles = append(sharedLibDepFiles, dep.OutputFile().Path())
+ sharedLibFiles = append(sharedLibFiles, dep.OutputFile().Path())
+ if dep.Toc().Valid() {
+ sharedLibDepFiles = append(sharedLibDepFiles, dep.Toc().Path())
+ } else {
+ sharedLibDepFiles = append(sharedLibDepFiles, dep.OutputFile().Path())
+ }
}
var srcProviderDepFiles android.Paths
@@ -970,12 +977,14 @@
depPaths.RLibs = append(depPaths.RLibs, rlibDepFiles...)
depPaths.DyLibs = append(depPaths.DyLibs, dylibDepFiles...)
depPaths.SharedLibs = append(depPaths.SharedLibs, sharedLibDepFiles...)
+ depPaths.SharedLibDeps = append(depPaths.SharedLibDeps, sharedLibDepFiles...)
depPaths.StaticLibs = append(depPaths.StaticLibs, staticLibDepFiles...)
depPaths.ProcMacros = append(depPaths.ProcMacros, procMacroDepFiles...)
depPaths.SrcDeps = append(depPaths.SrcDeps, srcProviderDepFiles...)
// Dedup exported flags from dependencies
depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs)
+ depPaths.linkObjects = android.FirstUniqueStrings(depPaths.linkObjects)
depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags)
depPaths.depClangFlags = android.FirstUniqueStrings(depPaths.depClangFlags)
depPaths.depIncludePaths = android.FirstUniquePaths(depPaths.depIncludePaths)
diff --git a/sdk/testing.go b/sdk/testing.go
index 38755a9..1ac873b 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -107,12 +107,7 @@
ctx.PostDepsMutators(android.RegisterVisibilityRuleEnforcer)
// from java package
- java.RegisterJavaBuildComponents(ctx)
- java.RegisterAppBuildComponents(ctx)
- java.RegisterSdkLibraryBuildComponents(ctx)
- java.RegisterPrebuiltApisBuildComponents(ctx)
- java.RegisterStubsBuildComponents(ctx)
- java.RegisterSystemModulesBuildComponents(ctx)
+ java.RegisterRequiredBuildComponentsForTest(ctx)
// from cc package
cc.RegisterRequiredBuildComponentsForTest(ctx)
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index b8b93f6..5cb9e64 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -58,9 +58,7 @@
func testContext(config android.Config) *android.TestContext {
ctx := android.NewTestArchContext(config)
- java.RegisterJavaBuildComponents(ctx)
- java.RegisterAppBuildComponents(ctx)
- java.RegisterSystemModulesBuildComponents(ctx)
+ java.RegisterRequiredBuildComponentsForTest(ctx)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index a5986b2..b1f8551 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -125,7 +125,6 @@
productOut("ramdisk"),
productOut("debug_ramdisk"),
productOut("vendor-ramdisk"),
- productOut("vendor-ramdisk-debug.cpio.gz"),
productOut("vendor_debug_ramdisk"),
productOut("test_harness_ramdisk"),
productOut("recovery"),