Generate .bzl rule definitions for every module type in Soong, and
surface module properties as attributes.
This CL maps int, bool, string and string_list module props from Soong
modules into their respective Bazel targets.
With this CL, you can now query modules based on their properties. For
example:
$ bazel query 'attr(nocrt, 1, //...)'
$ bazel query 'attr(apex_available, //apex_available:platform, //...)'
$ bazel query //art/dalvikvm:dalvikvm--linux_glibc_x86_64 --output=build | grep compile_multilib
Test: m bazel_overlay && cd out/soong/bazel_overlay && bazel cquery 'attr(apex_available, com.android.runtime, //...)'
Test: soong_build tests
Fixes: 162720644
Fixes: 164320355
Change-Id: Iea8e594b952feccac3281f36dd6bdee8e7d62c3a
diff --git a/cmd/soong_build/bazel_overlay_test.go b/cmd/soong_build/bazel_overlay_test.go
index 8db784d..f0c8515 100644
--- a/cmd/soong_build/bazel_overlay_test.go
+++ b/cmd/soong_build/bazel_overlay_test.go
@@ -18,7 +18,10 @@
"android/soong/android"
"io/ioutil"
"os"
+ "strings"
"testing"
+
+ "github.com/google/blueprint/bootstrap/bpdoc"
)
var buildDir string
@@ -253,3 +256,209 @@
}
}
}
+
+func createPackageFixtures() []*bpdoc.Package {
+ properties := []bpdoc.Property{
+ bpdoc.Property{
+ Name: "int64_prop",
+ Type: "int64",
+ },
+ bpdoc.Property{
+ Name: "int_prop",
+ Type: "int",
+ },
+ bpdoc.Property{
+ Name: "bool_prop",
+ Type: "bool",
+ },
+ bpdoc.Property{
+ Name: "string_prop",
+ Type: "string",
+ },
+ bpdoc.Property{
+ Name: "string_list_prop",
+ Type: "list of strings",
+ },
+ bpdoc.Property{
+ Name: "nested_prop",
+ Type: "",
+ Properties: []bpdoc.Property{
+ bpdoc.Property{
+ Name: "int_prop",
+ Type: "int",
+ },
+ bpdoc.Property{
+ Name: "bool_prop",
+ Type: "bool",
+ },
+ bpdoc.Property{
+ Name: "string_prop",
+ Type: "string",
+ },
+ },
+ },
+ bpdoc.Property{
+ Name: "unknown_type",
+ Type: "unknown",
+ },
+ }
+
+ fooPropertyStruct := &bpdoc.PropertyStruct{
+ Name: "FooProperties",
+ Properties: properties,
+ }
+
+ moduleTypes := []*bpdoc.ModuleType{
+ &bpdoc.ModuleType{
+ Name: "foo_library",
+ PropertyStructs: []*bpdoc.PropertyStruct{
+ fooPropertyStruct,
+ },
+ },
+
+ &bpdoc.ModuleType{
+ Name: "foo_binary",
+ PropertyStructs: []*bpdoc.PropertyStruct{
+ fooPropertyStruct,
+ },
+ },
+ &bpdoc.ModuleType{
+ Name: "foo_test",
+ PropertyStructs: []*bpdoc.PropertyStruct{
+ fooPropertyStruct,
+ },
+ },
+ }
+
+ return [](*bpdoc.Package){
+ &bpdoc.Package{
+ Name: "foo_language",
+ Path: "android/soong/foo",
+ ModuleTypes: moduleTypes,
+ },
+ }
+}
+
+func TestGenerateModuleRuleShims(t *testing.T) {
+ ruleShims, err := createRuleShims(createPackageFixtures())
+ if err != nil {
+ panic(err)
+ }
+
+ if len(ruleShims) != 1 {
+ t.Errorf("Expected to generate 1 rule shim, but got %d", len(ruleShims))
+ }
+
+ fooRuleShim := ruleShims["foo"]
+ expectedRules := []string{"foo_binary", "foo_library", "foo_test_"}
+
+ if len(fooRuleShim.rules) != 3 {
+ t.Errorf("Expected 3 rules, but got %d", len(fooRuleShim.rules))
+ }
+
+ for i, rule := range fooRuleShim.rules {
+ if rule != expectedRules[i] {
+ t.Errorf("Expected rule shim to contain %s, but got %s", expectedRules[i], rule)
+ }
+ }
+
+ expectedBzl := `load(":providers.bzl", "SoongModuleInfo")
+
+def _foo_binary_impl(ctx):
+ return [SoongModuleInfo()]
+
+foo_binary = rule(
+ implementation = _foo_binary_impl,
+ attrs = {
+ "module_name": attr.string(mandatory = True),
+ "module_variant": attr.string(),
+ "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+ "bool_prop": attr.bool(),
+ "int64_prop": attr.int(),
+ "int_prop": attr.int(),
+# "nested_prop__int_prop": attr.int(),
+# "nested_prop__bool_prop": attr.bool(),
+# "nested_prop__string_prop": attr.string(),
+ "string_list_prop": attr.string_list(),
+ "string_prop": attr.string(),
+ },
+)
+
+def _foo_library_impl(ctx):
+ return [SoongModuleInfo()]
+
+foo_library = rule(
+ implementation = _foo_library_impl,
+ attrs = {
+ "module_name": attr.string(mandatory = True),
+ "module_variant": attr.string(),
+ "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+ "bool_prop": attr.bool(),
+ "int64_prop": attr.int(),
+ "int_prop": attr.int(),
+# "nested_prop__int_prop": attr.int(),
+# "nested_prop__bool_prop": attr.bool(),
+# "nested_prop__string_prop": attr.string(),
+ "string_list_prop": attr.string_list(),
+ "string_prop": attr.string(),
+ },
+)
+
+def _foo_test__impl(ctx):
+ return [SoongModuleInfo()]
+
+foo_test_ = rule(
+ implementation = _foo_test__impl,
+ attrs = {
+ "module_name": attr.string(mandatory = True),
+ "module_variant": attr.string(),
+ "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+ "bool_prop": attr.bool(),
+ "int64_prop": attr.int(),
+ "int_prop": attr.int(),
+# "nested_prop__int_prop": attr.int(),
+# "nested_prop__bool_prop": attr.bool(),
+# "nested_prop__string_prop": attr.string(),
+ "string_list_prop": attr.string_list(),
+ "string_prop": attr.string(),
+ },
+)
+`
+
+ if fooRuleShim.content != expectedBzl {
+ t.Errorf(
+ "Expected the generated rule shim bzl to be:\n%s\nbut got:\n%s",
+ expectedBzl,
+ fooRuleShim.content)
+ }
+}
+
+func TestGenerateSoongModuleBzl(t *testing.T) {
+ ruleShims, err := createRuleShims(createPackageFixtures())
+ if err != nil {
+ panic(err)
+ }
+ actualSoongModuleBzl := generateSoongModuleBzl(ruleShims)
+
+ expectedLoad := "load(\"//:foo.bzl\", \"foo_binary\", \"foo_library\", \"foo_test_\")"
+ expectedRuleMap := `soong_module_rule_map = {
+ "foo_binary": foo_binary,
+ "foo_library": foo_library,
+ "foo_test_": foo_test_,
+}`
+ if !strings.Contains(actualSoongModuleBzl, expectedLoad) {
+ t.Errorf(
+ "Generated soong_module.bzl:\n\n%s\n\n"+
+ "Could not find the load statement in the generated soong_module.bzl:\n%s",
+ actualSoongModuleBzl,
+ expectedLoad)
+ }
+
+ if !strings.Contains(actualSoongModuleBzl, expectedRuleMap) {
+ t.Errorf(
+ "Generated soong_module.bzl:\n\n%s\n\n"+
+ "Could not find the module -> rule map in the generated soong_module.bzl:\n%s",
+ actualSoongModuleBzl,
+ expectedRuleMap)
+ }
+}