Gen a header library when genrules export includes

Embedding multiple includes from a genrule may be difficult to read,
instead we generate a header library that contains the headers and all
include dirs that Soong generates.

Test: go test bp2build tests
Change-Id: I590c74c133f015f27cccf5a2fd916153ad9c125e
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 6306c27..69ba1e9 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -994,6 +994,7 @@
 
 	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
 
+	bazelName := m.Name()
 	if ctx.ModuleType() == "gensrcs" {
 		props := bazel.BazelTargetModuleProperties{
 			Rule_class:        "gensrcs",
@@ -1021,7 +1022,6 @@
 				break
 			}
 		}
-		bazelName := m.Name()
 		for _, out := range outs {
 			if out == bazelName {
 				// This is a workaround to circumvent a Bazel warning where a genrule's
@@ -1046,6 +1046,54 @@
 			Tags: tags,
 		}, attrs)
 	}
+
+	if m.needsCcLibraryHeadersBp2build() {
+		includeDirs := make([]string, len(m.properties.Export_include_dirs)*2)
+		for i, dir := range m.properties.Export_include_dirs {
+			includeDirs[i*2] = dir
+			includeDirs[i*2+1] = filepath.Clean(filepath.Join(ctx.ModuleDir(), dir))
+		}
+		attrs := &ccHeaderLibraryAttrs{
+			Hdrs:            []string{":" + bazelName},
+			Export_includes: includeDirs,
+		}
+		props := bazel.BazelTargetModuleProperties{
+			Rule_class:        "cc_library_headers",
+			Bzl_load_location: "//build/bazel/rules/cc:cc_library_headers.bzl",
+		}
+		ctx.CreateBazelTargetModule(props, android.CommonAttributes{
+			Name: m.Name() + genruleHeaderLibrarySuffix,
+			Tags: tags,
+		}, attrs)
+
+	}
+}
+
+const genruleHeaderLibrarySuffix = "__header_library"
+
+func (m *Module) needsCcLibraryHeadersBp2build() bool {
+	return len(m.properties.Export_include_dirs) > 0
+}
+
+// GenruleCcHeaderMapper is a bazel.LabelMapper function to map genrules to a cc_library_headers
+// target when they export multiple include directories.
+func GenruleCcHeaderLabelMapper(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
+	mod, exists := ctx.ModuleFromName(label.OriginalModuleName)
+	if !exists {
+		return label.Label, false
+	}
+	if m, ok := mod.(*Module); ok {
+		if m.needsCcLibraryHeadersBp2build() {
+			return label.Label + genruleHeaderLibrarySuffix, true
+		}
+	}
+	return label.Label, false
+}
+
+type ccHeaderLibraryAttrs struct {
+	Hdrs []string
+
+	Export_includes []string
 }
 
 var Bool = proptools.Bool
@@ -1099,6 +1147,7 @@
 		}
 	}).(*sandboxingAllowlistSets)
 }
+
 func getSandboxedRuleBuilder(ctx android.ModuleContext, r *android.RuleBuilder) *android.RuleBuilder {
 	if !ctx.DeviceConfig().GenruleSandboxing() {
 		return r.SandboxTools()