bp2build: Add support for export_.*headers props

Soong supports export_.*_headers properties, the libraries contained in
this list must also be within a shared/static/whole_static/header libs
property. For bp2build, we eliminate this duplication. The libraries
not listed in an export_.*_headers property will migrate to an attribute
prepended with implementation_, those in export_.*_headers will not have
a prefix.

Test: build/bazel/ci/bp2build.sh
Test: build/bazel/ci/mixed_libc.sh
Bug: 198241472
Change-Id: I3eb84c983ec5d241c8a568e411dfd5619d3184a7
diff --git a/cc/bp2build.go b/cc/bp2build.go
index e48f757..1b38a75 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -20,6 +20,7 @@
 
 	"android/soong/android"
 	"android/soong/bazel"
+
 	"github.com/google/blueprint"
 
 	"github.com/google/blueprint/proptools"
@@ -33,9 +34,11 @@
 	Srcs_as bazel.LabelListAttribute
 	Copts   bazel.StringListAttribute
 
-	Static_deps        bazel.LabelListAttribute
-	Dynamic_deps       bazel.LabelListAttribute
-	Whole_archive_deps bazel.LabelListAttribute
+	Deps                        bazel.LabelListAttribute
+	Implementation_deps         bazel.LabelListAttribute
+	Dynamic_deps                bazel.LabelListAttribute
+	Implementation_dynamic_deps bazel.LabelListAttribute
+	Whole_archive_deps          bazel.LabelListAttribute
 
 	System_dynamic_deps bazel.LabelListAttribute
 }
@@ -131,16 +134,50 @@
 	return bp2BuildParseLibProps(ctx, module, true)
 }
 
+type depsPartition struct {
+	export         bazel.LabelList
+	implementation bazel.LabelList
+}
+
+type bazelLabelForDepsFn func(android.TopDownMutatorContext, []string) bazel.LabelList
+
+func partitionExportedAndImplementationsDeps(ctx android.TopDownMutatorContext, allDeps, exportedDeps []string, fn bazelLabelForDepsFn) depsPartition {
+	implementation, export := android.FilterList(allDeps, exportedDeps)
+
+	return depsPartition{
+		export:         fn(ctx, export),
+		implementation: fn(ctx, implementation),
+	}
+}
+
+type bazelLabelForDepsExcludesFn func(android.TopDownMutatorContext, []string, []string) bazel.LabelList
+
+func partitionExportedAndImplementationsDepsExcludes(ctx android.TopDownMutatorContext, allDeps, excludes, exportedDeps []string, fn bazelLabelForDepsExcludesFn) depsPartition {
+	implementation, export := android.FilterList(allDeps, exportedDeps)
+
+	return depsPartition{
+		export:         fn(ctx, export, excludes),
+		implementation: fn(ctx, implementation, excludes),
+	}
+}
+
 func bp2buildParseStaticOrSharedProps(ctx android.TopDownMutatorContext, module *Module, lib *libraryDecorator, isStatic bool) staticOrSharedAttributes {
 	attrs := staticOrSharedAttributes{}
 
 	setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) {
 		attrs.Copts.SetSelectValue(axis, config, props.Cflags)
 		attrs.Srcs.SetSelectValue(axis, config, android.BazelLabelForModuleSrc(ctx, props.Srcs))
-		attrs.Static_deps.SetSelectValue(axis, config, bazelLabelForStaticDeps(ctx, props.Static_libs))
-		attrs.Dynamic_deps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, props.Shared_libs))
-		attrs.Whole_archive_deps.SetSelectValue(axis, config, bazelLabelForWholeDeps(ctx, props.Whole_static_libs))
 		attrs.System_dynamic_deps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, props.System_shared_libs))
+
+		staticDeps := partitionExportedAndImplementationsDeps(ctx, props.Static_libs, props.Export_static_lib_headers, bazelLabelForStaticDeps)
+		attrs.Deps.SetSelectValue(axis, config, staticDeps.export)
+		attrs.Implementation_deps.SetSelectValue(axis, config, staticDeps.implementation)
+
+		sharedDeps := partitionExportedAndImplementationsDeps(ctx, props.Shared_libs, props.Export_shared_lib_headers, bazelLabelForSharedDeps)
+		attrs.Dynamic_deps.SetSelectValue(axis, config, sharedDeps.export)
+		attrs.Implementation_dynamic_deps.SetSelectValue(axis, config, sharedDeps.implementation)
+
+		attrs.Whole_archive_deps.SetSelectValue(axis, config, bazelLabelForWholeDeps(ctx, props.Whole_static_libs))
 	}
 	// system_dynamic_deps distinguishes between nil/empty list behavior:
 	//    nil -> use default values
@@ -328,11 +365,13 @@
 
 // Convenience struct to hold all attributes parsed from linker properties.
 type linkerAttributes struct {
-	deps                          bazel.LabelListAttribute
-	dynamicDeps                   bazel.LabelListAttribute
-	systemDynamicDeps             bazel.LabelListAttribute
-	wholeArchiveDeps              bazel.LabelListAttribute
-	exportedDeps                  bazel.LabelListAttribute
+	deps                      bazel.LabelListAttribute
+	implementationDeps        bazel.LabelListAttribute
+	dynamicDeps               bazel.LabelListAttribute
+	implementationDynamicDeps bazel.LabelListAttribute
+	wholeArchiveDeps          bazel.LabelListAttribute
+	systemDynamicDeps         bazel.LabelListAttribute
+
 	useLibcrt                     bazel.BoolAttribute
 	linkopts                      bazel.StringListAttribute
 	versionScript                 bazel.LabelAttribute
@@ -355,12 +394,16 @@
 // bp2BuildParseLinkerProps parses the linker properties of a module, including
 // configurable attribute values.
 func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) linkerAttributes {
+
 	var headerDeps bazel.LabelListAttribute
-	var staticDeps bazel.LabelListAttribute
-	var exportedDeps bazel.LabelListAttribute
+	var implementationHeaderDeps bazel.LabelListAttribute
+	var deps bazel.LabelListAttribute
+	var implementationDeps bazel.LabelListAttribute
 	var dynamicDeps bazel.LabelListAttribute
+	var implementationDynamicDeps bazel.LabelListAttribute
 	var wholeArchiveDeps bazel.LabelListAttribute
 	systemSharedDeps := bazel.LabelListAttribute{ForceSpecifyEmptyList: true}
+
 	var linkopts bazel.StringListAttribute
 	var versionScript bazel.LabelAttribute
 	var useLibcrt bazel.BoolAttribute
@@ -386,12 +429,16 @@
 	for axis, configToProps := range module.GetArchVariantProperties(ctx, &BaseLinkerProperties{}) {
 		for config, props := range configToProps {
 			if baseLinkerProps, ok := props.(*BaseLinkerProperties); ok {
+
 				// Excludes to parallel Soong:
 				// https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=247-249;drc=088b53577dde6e40085ffd737a1ae96ad82fc4b0
 				staticLibs := android.FirstUniqueStrings(baseLinkerProps.Static_libs)
-				staticDeps.SetSelectValue(axis, config, bazelLabelForStaticDepsExcludes(ctx, staticLibs, baseLinkerProps.Exclude_static_libs))
-				wholeArchiveLibs := android.FirstUniqueStrings(baseLinkerProps.Whole_static_libs)
-				wholeArchiveDeps.SetSelectValue(axis, config, bazelLabelForWholeDepsExcludes(ctx, wholeArchiveLibs, baseLinkerProps.Exclude_static_libs))
+				staticDeps := partitionExportedAndImplementationsDepsExcludes(ctx, staticLibs, baseLinkerProps.Exclude_static_libs, baseLinkerProps.Export_static_lib_headers, bazelLabelForStaticDepsExcludes)
+				deps.SetSelectValue(axis, config, staticDeps.export)
+				implementationDeps.SetSelectValue(axis, config, staticDeps.implementation)
+
+				wholeStaticLibs := android.FirstUniqueStrings(baseLinkerProps.Whole_static_libs)
+				wholeArchiveDeps.SetSelectValue(axis, config, bazelLabelForWholeDepsExcludes(ctx, wholeStaticLibs, baseLinkerProps.Exclude_static_libs))
 
 				systemSharedLibs := baseLinkerProps.System_shared_libs
 				// systemSharedLibs distinguishes between nil/empty list behavior:
@@ -403,12 +450,15 @@
 				systemSharedDeps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, systemSharedLibs))
 
 				sharedLibs := android.FirstUniqueStrings(baseLinkerProps.Shared_libs)
-				dynamicDeps.SetSelectValue(axis, config, bazelLabelForSharedDepsExcludes(ctx, sharedLibs, baseLinkerProps.Exclude_shared_libs))
+				sharedDeps := partitionExportedAndImplementationsDepsExcludes(ctx, sharedLibs, baseLinkerProps.Exclude_shared_libs, baseLinkerProps.Export_shared_lib_headers, bazelLabelForSharedDepsExcludes)
+				dynamicDeps.SetSelectValue(axis, config, sharedDeps.export)
+				implementationDynamicDeps.SetSelectValue(axis, config, sharedDeps.implementation)
 
 				headerLibs := android.FirstUniqueStrings(baseLinkerProps.Header_libs)
-				headerDeps.SetSelectValue(axis, config, bazelLabelForHeaderDeps(ctx, headerLibs))
-				exportedLibs := android.FirstUniqueStrings(baseLinkerProps.Export_header_lib_headers)
-				exportedDeps.SetSelectValue(axis, config, bazelLabelForHeaderDeps(ctx, exportedLibs))
+				hDeps := partitionExportedAndImplementationsDeps(ctx, headerLibs, baseLinkerProps.Export_header_lib_headers, bazelLabelForHeaderDeps)
+
+				headerDeps.SetSelectValue(axis, config, hDeps.export)
+				implementationHeaderDeps.SetSelectValue(axis, config, hDeps.implementation)
 
 				linkopts.SetSelectValue(axis, config, getBp2BuildLinkerFlags(baseLinkerProps))
 				if baseLinkerProps.Version_script != nil {
@@ -430,8 +480,8 @@
 
 	productVarToDepFields := map[string]productVarDep{
 		// product variables do not support exclude_shared_libs
-		"Shared_libs":       productVarDep{attribute: &dynamicDeps, depResolutionFunc: bazelLabelForSharedDepsExcludes},
-		"Static_libs":       productVarDep{"Exclude_static_libs", &staticDeps, bazelLabelForStaticDepsExcludes},
+		"Shared_libs":       productVarDep{attribute: &implementationDynamicDeps, depResolutionFunc: bazelLabelForSharedDepsExcludes},
+		"Static_libs":       productVarDep{"Exclude_static_libs", &implementationDeps, bazelLabelForStaticDepsExcludes},
 		"Whole_static_libs": productVarDep{"Exclude_static_libs", &wholeArchiveDeps, bazelLabelForWholeDepsExcludes},
 	}
 
@@ -471,21 +521,26 @@
 		}
 	}
 
-	staticDeps.ResolveExcludes()
+	headerDeps.Append(deps)
+	implementationHeaderDeps.Append(implementationDeps)
+
+	headerDeps.ResolveExcludes()
+	implementationHeaderDeps.ResolveExcludes()
 	dynamicDeps.ResolveExcludes()
+	implementationDynamicDeps.ResolveExcludes()
 	wholeArchiveDeps.ResolveExcludes()
 
-	headerDeps.Append(staticDeps)
-
 	return linkerAttributes{
-		deps:              headerDeps,
-		exportedDeps:      exportedDeps,
-		dynamicDeps:       dynamicDeps,
-		systemDynamicDeps: systemSharedDeps,
-		wholeArchiveDeps:  wholeArchiveDeps,
-		linkopts:          linkopts,
-		useLibcrt:         useLibcrt,
-		versionScript:     versionScript,
+		deps:                      headerDeps,
+		implementationDeps:        implementationHeaderDeps,
+		dynamicDeps:               dynamicDeps,
+		implementationDynamicDeps: implementationDynamicDeps,
+		wholeArchiveDeps:          wholeArchiveDeps,
+		systemDynamicDeps:         systemSharedDeps,
+
+		linkopts:      linkopts,
+		useLibcrt:     useLibcrt,
+		versionScript: versionScript,
 
 		// Strip properties
 		stripKeepSymbols:              stripKeepSymbols,