Support arch variations for export_system_include_dirs in cc_library_headers bp2build converter.

Test: Added unit test
Test: bp2build-sync.py write; bazel build //bionic/... works for more cc_library_static targets (in a parent CL)
Change-Id: Ib487216a4bcbc52958ff948722dae347b0d8b606
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 497d227..cffeb24 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -16,6 +16,7 @@
 import (
 	"android/soong/android"
 	"android/soong/bazel"
+	"strings"
 )
 
 // bp2build functions and helpers for converting cc_* modules to Bazel.
@@ -109,23 +110,78 @@
 	return ret
 }
 
+func bp2BuildListHeadersInDir(ctx android.TopDownMutatorContext, includeDir string) bazel.LabelList {
+	var globInfix string
+
+	if includeDir == "." {
+		globInfix = ""
+	} else {
+		globInfix = "/**"
+	}
+
+	var includeDirGlobs []string
+	includeDirGlobs = append(includeDirGlobs, includeDir+globInfix+"/*.h")
+	includeDirGlobs = append(includeDirGlobs, includeDir+globInfix+"/*.inc")
+	includeDirGlobs = append(includeDirGlobs, includeDir+globInfix+"/*.hpp")
+
+	return android.BazelLabelForModuleSrc(ctx, includeDirGlobs)
+}
+
+// Bazel wants include paths to be relative to the module
+func bp2BuildMakePathsRelativeToModule(ctx android.TopDownMutatorContext, paths []string) []string {
+	var relativePaths []string
+	for _, path := range paths {
+		relativePath := strings.TrimPrefix(path, ctx.ModuleDir()+"/")
+		relativePaths = append(relativePaths, relativePath)
+	}
+	return relativePaths
+}
+
 // bp2BuildParseExportedIncludes creates a label list attribute contains the
 // exported included directories of a module.
-func bp2BuildParseExportedIncludes(ctx android.TopDownMutatorContext, module *Module) (bazel.LabelListAttribute, bazel.LabelListAttribute) {
+func bp2BuildParseExportedIncludes(ctx android.TopDownMutatorContext, module *Module) (bazel.StringListAttribute, bazel.LabelListAttribute) {
 	libraryDecorator := module.linker.(*libraryDecorator)
 
 	includeDirs := libraryDecorator.flagExporter.Properties.Export_system_include_dirs
 	includeDirs = append(includeDirs, libraryDecorator.flagExporter.Properties.Export_include_dirs...)
+	includeDirs = bp2BuildMakePathsRelativeToModule(ctx, includeDirs)
+	includeDirsAttribute := bazel.MakeStringListAttribute(includeDirs)
 
-	includeDirsLabels := android.BazelLabelForModuleSrc(ctx, includeDirs)
-
-	var includeDirGlobs []string
+	var headersAttribute bazel.LabelListAttribute
+	var headers bazel.LabelList
 	for _, includeDir := range includeDirs {
-		includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.h")
-		includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.inc")
-		includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.hpp")
+		headers.Append(bp2BuildListHeadersInDir(ctx, includeDir))
+	}
+	headers = bazel.UniqueBazelLabelList(headers)
+	headersAttribute.Value = headers
+
+	for arch, props := range module.GetArchProperties(&FlagExporterProperties{}) {
+		if flagExporterProperties, ok := props.(*FlagExporterProperties); ok {
+			archIncludeDirs := flagExporterProperties.Export_system_include_dirs
+			archIncludeDirs = append(archIncludeDirs, flagExporterProperties.Export_include_dirs...)
+			archIncludeDirs = bp2BuildMakePathsRelativeToModule(ctx, archIncludeDirs)
+
+			// To avoid duplicate includes when base includes + arch includes are combined
+			archIncludeDirs = bazel.SubtractStrings(archIncludeDirs, includeDirs)
+
+			if len(archIncludeDirs) > 0 {
+				includeDirsAttribute.SetValueForArch(arch.Name, archIncludeDirs)
+			}
+
+			var archHeaders bazel.LabelList
+			for _, archIncludeDir := range archIncludeDirs {
+				archHeaders.Append(bp2BuildListHeadersInDir(ctx, archIncludeDir))
+			}
+			archHeaders = bazel.UniqueBazelLabelList(archHeaders)
+
+			// To avoid duplicate headers when base headers + arch headers are combined
+			archHeaders = bazel.SubtractBazelLabelList(archHeaders, headers)
+
+			if len(archHeaders.Includes) > 0 || len(archHeaders.Excludes) > 0 {
+				headersAttribute.SetValueForArch(arch.Name, archHeaders)
+			}
+		}
 	}
 
-	headersLabels := android.BazelLabelForModuleSrc(ctx, includeDirGlobs)
-	return bazel.MakeLabelListAttribute(includeDirsLabels), bazel.MakeLabelListAttribute(headersLabels)
+	return includeDirsAttribute, headersAttribute
 }
diff --git a/cc/library.go b/cc/library.go
index 50fff7f..97c7ba1 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -2051,7 +2051,7 @@
 	Srcs       bazel.LabelListAttribute
 	Deps       bazel.LabelListAttribute
 	Linkstatic bool
-	Includes   bazel.LabelListAttribute
+	Includes   bazel.StringListAttribute
 	Hdrs       bazel.LabelListAttribute
 }
 
@@ -2088,8 +2088,8 @@
 		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
 			copts = baseCompilerProps.Cflags
 			srcs = baseCompilerProps.Srcs
-			includeDirs = baseCompilerProps.Include_dirs
-			localIncludeDirs = baseCompilerProps.Local_include_dirs
+			includeDirs = bp2BuildMakePathsRelativeToModule(ctx, baseCompilerProps.Include_dirs)
+			localIncludeDirs = bp2BuildMakePathsRelativeToModule(ctx, baseCompilerProps.Local_include_dirs)
 			break
 		}
 	}
@@ -2111,14 +2111,13 @@
 
 	depsLabels := android.BazelLabelForModuleDeps(ctx, allDeps)
 
+	exportedIncludes, exportedIncludesHeaders := bp2BuildParseExportedIncludes(ctx, module)
+
 	// FIXME: Unify absolute vs relative paths
 	// FIXME: Use -I copts instead of setting includes= ?
-	allIncludes := includeDirs
-	allIncludes = append(allIncludes, localIncludeDirs...)
-	includesLabels := android.BazelLabelForModuleSrc(ctx, allIncludes)
-
-	exportedIncludesLabels, exportedIncludesHeadersLabels := bp2BuildParseExportedIncludes(ctx, module)
-	includesLabels.Append(exportedIncludesLabels.Value)
+	allIncludes := exportedIncludes
+	allIncludes.Value = append(allIncludes.Value, includeDirs...)
+	allIncludes.Value = append(allIncludes.Value, localIncludeDirs...)
 
 	headerLibsLabels := bp2BuildParseHeaderLibs(ctx, module)
 	depsLabels.Append(headerLibsLabels.Value)
@@ -2128,8 +2127,8 @@
 		Srcs:       srcsLabels,
 		Deps:       bazel.MakeLabelListAttribute(depsLabels),
 		Linkstatic: true,
-		Includes:   bazel.MakeLabelListAttribute(includesLabels),
-		Hdrs:       exportedIncludesHeadersLabels,
+		Includes:   allIncludes,
+		Hdrs:       exportedIncludesHeaders,
 	}
 
 	props := bazel.BazelTargetModuleProperties{
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 82af16a..d35748b 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -64,7 +64,7 @@
 type bazelCcLibraryHeadersAttributes struct {
 	Copts    bazel.StringListAttribute
 	Hdrs     bazel.LabelListAttribute
-	Includes bazel.LabelListAttribute
+	Includes bazel.StringListAttribute
 	Deps     bazel.LabelListAttribute
 }
 
@@ -95,15 +95,15 @@
 		return
 	}
 
-	exportedIncludesLabels, exportedIncludesHeadersLabels := bp2BuildParseExportedIncludes(ctx, module)
+	exportedIncludes, exportedIncludesHeaders := bp2BuildParseExportedIncludes(ctx, module)
 
-	headerLibsLabels := bp2BuildParseHeaderLibs(ctx, module)
+	headerLibs := bp2BuildParseHeaderLibs(ctx, module)
 
 	attrs := &bazelCcLibraryHeadersAttributes{
 		Copts:    bp2BuildParseCflags(ctx, module),
-		Includes: exportedIncludesLabels,
-		Hdrs:     exportedIncludesHeadersLabels,
-		Deps:     headerLibsLabels,
+		Includes: exportedIncludes,
+		Hdrs:     exportedIncludesHeaders,
+		Deps:     headerLibs,
 	}
 
 	props := bazel.BazelTargetModuleProperties{