bp2build: Add support for cc_binary.

Bug: 197920036
Test: build/bazel/ci/bp2build.sh
Change-Id: I2c4200967653af15a330ab8cbaf796b70d43f32d
diff --git a/cc/binary.go b/cc/binary.go
index b423c50..4d1301b 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -20,6 +20,7 @@
 	"github.com/google/blueprint"
 
 	"android/soong/android"
+	"android/soong/bazel"
 )
 
 type BinaryLinkerProperties struct {
@@ -62,7 +63,7 @@
 
 func RegisterBinaryBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("cc_binary", BinaryFactory)
-	ctx.RegisterModuleType("cc_binary_host", binaryHostFactory)
+	ctx.RegisterModuleType("cc_binary_host", BinaryHostFactory)
 }
 
 // cc_binary produces a binary that is runnable on a device.
@@ -72,7 +73,7 @@
 }
 
 // cc_binary_host produces a binary that is runnable on a host.
-func binaryHostFactory() android.Module {
+func BinaryHostFactory() android.Module {
 	module, _ := NewBinary(android.HostSupported)
 	return module.Init()
 }
@@ -541,3 +542,125 @@
 		},
 	})
 }
+
+func init() {
+	android.RegisterBp2BuildMutator("cc_binary", BinaryBp2build)
+	android.RegisterBp2BuildMutator("cc_binary_host", BinaryHostBp2build)
+}
+
+func BinaryBp2build(ctx android.TopDownMutatorContext) {
+	binaryBp2build(ctx, "cc_binary")
+}
+
+func BinaryHostBp2build(ctx android.TopDownMutatorContext) {
+	binaryBp2build(ctx, "cc_binary_host")
+}
+
+func binaryBp2build(ctx android.TopDownMutatorContext, typ string) {
+	m, ok := ctx.Module().(*Module)
+	if !ok {
+		// Not a cc module
+		return
+	}
+	if !m.ConvertWithBp2build(ctx) {
+		return
+	}
+
+	if ctx.ModuleType() != typ {
+		return
+	}
+
+	var compatibleWith bazel.StringListAttribute
+	if typ == "cc_binary_host" {
+		//incompatible with android OS
+		compatibleWith.SetSelectValue(bazel.OsConfigurationAxis, android.Android.Name, []string{"@platforms//:incompatible"})
+		compatibleWith.SetSelectValue(bazel.OsConfigurationAxis, bazel.ConditionsDefaultConfigKey, []string{})
+	}
+
+	compilerAttrs := bp2BuildParseCompilerProps(ctx, m)
+	linkerAttrs := bp2BuildParseLinkerProps(ctx, m)
+
+	attrs := &binaryAttributes{
+		binaryLinkerAttrs: bp2buildBinaryLinkerProps(ctx, m),
+
+		Srcs:    compilerAttrs.srcs,
+		Srcs_c:  compilerAttrs.cSrcs,
+		Srcs_as: compilerAttrs.asSrcs,
+
+		Copts:      compilerAttrs.copts,
+		Cppflags:   compilerAttrs.cppFlags,
+		Conlyflags: compilerAttrs.conlyFlags,
+		Asflags:    compilerAttrs.asFlags,
+
+		Deps:               linkerAttrs.implementationDeps,
+		Dynamic_deps:       linkerAttrs.implementationDynamicDeps,
+		Whole_archive_deps: linkerAttrs.wholeArchiveDeps,
+		System_deps:        linkerAttrs.systemDynamicDeps,
+
+		Local_includes:    compilerAttrs.localIncludes,
+		Absolute_includes: compilerAttrs.absoluteIncludes,
+		Linkopts:          linkerAttrs.linkopts,
+		Link_crt:          linkerAttrs.linkCrt,
+		Use_libcrt:        linkerAttrs.useLibcrt,
+		Rtti:              compilerAttrs.rtti,
+		Stl:               compilerAttrs.stl,
+		Cpp_std:           compilerAttrs.cppStd,
+
+		Additional_linker_inputs: linkerAttrs.additionalLinkerInputs,
+
+		Strip: stripAttributes{
+			Keep_symbols:                 linkerAttrs.stripKeepSymbols,
+			Keep_symbols_and_debug_frame: linkerAttrs.stripKeepSymbolsAndDebugFrame,
+			Keep_symbols_list:            linkerAttrs.stripKeepSymbolsList,
+			All:                          linkerAttrs.stripAll,
+			None:                         linkerAttrs.stripNone,
+		},
+
+		Target_compatible_with: compatibleWith,
+		Features:               linkerAttrs.features,
+	}
+
+	ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{
+		Rule_class:        "cc_binary",
+		Bzl_load_location: "//build/bazel/rules:cc_binary.bzl",
+	},
+		android.CommonAttributes{Name: m.Name()},
+		attrs)
+}
+
+// binaryAttributes contains Bazel attributes corresponding to a cc binary
+type binaryAttributes struct {
+	binaryLinkerAttrs
+	Srcs    bazel.LabelListAttribute
+	Srcs_c  bazel.LabelListAttribute
+	Srcs_as bazel.LabelListAttribute
+
+	Copts      bazel.StringListAttribute
+	Cppflags   bazel.StringListAttribute
+	Conlyflags bazel.StringListAttribute
+	Asflags    bazel.StringListAttribute
+
+	Deps               bazel.LabelListAttribute
+	Dynamic_deps       bazel.LabelListAttribute
+	Whole_archive_deps bazel.LabelListAttribute
+	System_deps        bazel.LabelListAttribute
+
+	Local_includes    bazel.StringListAttribute
+	Absolute_includes bazel.StringListAttribute
+
+	Linkopts                 bazel.StringListAttribute
+	Additional_linker_inputs bazel.LabelListAttribute
+
+	Link_crt   bazel.BoolAttribute
+	Use_libcrt bazel.BoolAttribute
+
+	Rtti    bazel.BoolAttribute
+	Stl     *string
+	Cpp_std *string
+
+	Strip stripAttributes
+
+	Features bazel.StringListAttribute
+
+	Target_compatible_with bazel.StringListAttribute
+}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index a7cabcc..3c238b5 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -117,7 +117,13 @@
 
 type bazelLabelForDepsFn func(android.TopDownMutatorContext, []string) bazel.LabelList
 
-func partitionExportedAndImplementationsDeps(ctx android.TopDownMutatorContext, allDeps, exportedDeps []string, fn bazelLabelForDepsFn) depsPartition {
+func maybePartitionExportedAndImplementationsDeps(ctx android.TopDownMutatorContext, exportsDeps bool, allDeps, exportedDeps []string, fn bazelLabelForDepsFn) depsPartition {
+	if !exportsDeps {
+		return depsPartition{
+			implementation: fn(ctx, allDeps),
+		}
+	}
+
 	implementation, export := android.FilterList(allDeps, exportedDeps)
 
 	return depsPartition{
@@ -128,7 +134,12 @@
 
 type bazelLabelForDepsExcludesFn func(android.TopDownMutatorContext, []string, []string) bazel.LabelList
 
-func partitionExportedAndImplementationsDepsExcludes(ctx android.TopDownMutatorContext, allDeps, excludes, exportedDeps []string, fn bazelLabelForDepsExcludesFn) depsPartition {
+func maybePartitionExportedAndImplementationsDepsExcludes(ctx android.TopDownMutatorContext, exportsDeps bool, allDeps, excludes, exportedDeps []string, fn bazelLabelForDepsExcludesFn) depsPartition {
+	if !exportsDeps {
+		return depsPartition{
+			implementation: fn(ctx, allDeps, excludes),
+		}
+	}
 	implementation, export := android.FilterList(allDeps, exportedDeps)
 
 	return depsPartition{
@@ -145,11 +156,11 @@
 		attrs.Srcs.SetSelectValue(axis, config, android.BazelLabelForModuleSrc(ctx, props.Srcs))
 		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)
+		staticDeps := maybePartitionExportedAndImplementationsDeps(ctx, true, 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)
+		sharedDeps := maybePartitionExportedAndImplementationsDeps(ctx, true, 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)
 
@@ -465,6 +476,7 @@
 
 	// Use a single variable to capture usage of nocrt in arch variants, so there's only 1 error message for this module
 	var disallowedArchVariantCrt bool
+	isBinary := module.Binary()
 
 	for axis, configToProps := range module.GetArchVariantProperties(ctx, &BaseLinkerProperties{}) {
 		for config, props := range configToProps {
@@ -474,7 +486,7 @@
 				// 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 := partitionExportedAndImplementationsDepsExcludes(ctx, staticLibs, baseLinkerProps.Exclude_static_libs, baseLinkerProps.Export_static_lib_headers, bazelLabelForStaticDepsExcludes)
+				staticDeps := maybePartitionExportedAndImplementationsDepsExcludes(ctx, !isBinary, staticLibs, baseLinkerProps.Exclude_static_libs, baseLinkerProps.Export_static_lib_headers, bazelLabelForStaticDepsExcludes)
 				deps.SetSelectValue(axis, config, staticDeps.export)
 				implementationDeps.SetSelectValue(axis, config, staticDeps.implementation)
 
@@ -491,12 +503,12 @@
 				systemSharedDeps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, systemSharedLibs))
 
 				sharedLibs := android.FirstUniqueStrings(baseLinkerProps.Shared_libs)
-				sharedDeps := partitionExportedAndImplementationsDepsExcludes(ctx, sharedLibs, baseLinkerProps.Exclude_shared_libs, baseLinkerProps.Export_shared_lib_headers, bazelLabelForSharedDepsExcludes)
+				sharedDeps := maybePartitionExportedAndImplementationsDepsExcludes(ctx, !isBinary, 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)
-				hDeps := partitionExportedAndImplementationsDeps(ctx, headerLibs, baseLinkerProps.Export_header_lib_headers, bazelLabelForHeaderDeps)
+				hDeps := maybePartitionExportedAndImplementationsDeps(ctx, !isBinary, headerLibs, baseLinkerProps.Export_header_lib_headers, bazelLabelForHeaderDeps)
 
 				headerDeps.SetSelectValue(axis, config, hDeps.export)
 				implementationHeaderDeps.SetSelectValue(axis, config, hDeps.implementation)
@@ -512,6 +524,10 @@
 				var linkerFlags []string
 				if len(baseLinkerProps.Ldflags) > 0 {
 					linkerFlags = append(linkerFlags, baseLinkerProps.Ldflags...)
+					// binaries remove static flag if -shared is in the linker flags
+					if module.Binary() && android.InList("-shared", linkerFlags) {
+						axisFeatures = append(axisFeatures, "-static_flag")
+					}
 				}
 				if baseLinkerProps.Version_script != nil {
 					label := android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script)
@@ -746,3 +762,29 @@
 func bazelLabelForSharedDepsExcludes(ctx android.TopDownMutatorContext, modules, excludes []string) bazel.LabelList {
 	return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForSharedModule)
 }
+
+type binaryLinkerAttrs struct {
+	Linkshared *bool
+}
+
+func bp2buildBinaryLinkerProps(ctx android.TopDownMutatorContext, m *Module) binaryLinkerAttrs {
+	attrs := binaryLinkerAttrs{}
+	archVariantProps := m.GetArchVariantProperties(ctx, &BinaryLinkerProperties{})
+	for axis, configToProps := range archVariantProps {
+		for _, p := range configToProps {
+			props := p.(*BinaryLinkerProperties)
+			staticExecutable := props.Static_executable
+			if axis == bazel.NoConfigAxis {
+				if linkBinaryShared := !proptools.Bool(staticExecutable); !linkBinaryShared {
+					attrs.Linkshared = &linkBinaryShared
+				}
+			} else if staticExecutable != nil {
+				// TODO(b/202876379): Static_executable is arch-variant; however, linkshared is a
+				// nonconfigurable attribute. Only 4 AOSP modules use this feature, defer handling
+				ctx.ModuleErrorf("bp2build cannot migrate a module with arch/target-specific static_executable values")
+			}
+		}
+	}
+
+	return attrs
+}