Generate a ndk_sysroot target in bp2build

This target will have a dependency edge to every bp2build equivalent of
Soong's ndk_headers. In b builds, sdk variants will compile against this
aggregated CcInfo providing target

A non monolithic alternative was discarded after conversations in
b/300504837#comment1-5

Contents of bp2build generated target: https://paste.googleplex.com/6643820291686400

Implementation details
- Since there is no equivalent Soong module for ndk_sysroot, hardcode
  bp2build/build_conversion.go to collect all ndk_headers soong modules.
  Add them to `deps` of a ndk_sysroot target
- Create `ndk_sysroot` in build/bazel/rules/cc/BUILD.bazel. This is
  expected to be a temporary location. This will use the
  cc_library_headers macro
- Update SetStubsForDynamicDeps so that sdk variant of rdeps depends on
  //build/bazel/rules/cc:ndk_sysroot. This will provide a CcInfo during
  compilation. Since ndk_sysroot is of type cc_library_headers, it will
  not get packaged into the apk.
- Refactor `goBazelTarget` to a generic `bTarget` so that it is
  representative of the expanded usage by ndk_sysroot

Test: b build //build/bazel/examples/android_app/java/com/app:app_with_sdk_variant_of_jni_deps --config=android (with aosp/2755284)

Bug: 300504837

Change-Id: Ifa427dd78115703ab251b0e1a0b71d3f19e91008
This commit is contained in:
Spandan Das 2023-09-19 19:51:52 +00:00
parent b95a8b33be
commit af72583468
6 changed files with 106 additions and 27 deletions

View file

@ -287,9 +287,9 @@ func (r conversionResults) BuildDirToTargets() map[string]BazelTargets {
return r.buildFileToTargets return r.buildFileToTargets
} }
// struct to store state of go bazel targets // struct to store state of b bazel targets (e.g. go targets which do not implement android.Module)
// this implements bp2buildModule interface and is passed to generateBazelTargets // this implements bp2buildModule interface and is passed to generateBazelTargets
type goBazelTarget struct { type bTarget struct {
targetName string targetName string
targetPackage string targetPackage string
bazelRuleClass string bazelRuleClass string
@ -297,26 +297,26 @@ type goBazelTarget struct {
bazelAttributes []interface{} bazelAttributes []interface{}
} }
var _ bp2buildModule = (*goBazelTarget)(nil) var _ bp2buildModule = (*bTarget)(nil)
func (g goBazelTarget) TargetName() string { func (b bTarget) TargetName() string {
return g.targetName return b.targetName
} }
func (g goBazelTarget) TargetPackage() string { func (b bTarget) TargetPackage() string {
return g.targetPackage return b.targetPackage
} }
func (g goBazelTarget) BazelRuleClass() string { func (b bTarget) BazelRuleClass() string {
return g.bazelRuleClass return b.bazelRuleClass
} }
func (g goBazelTarget) BazelRuleLoadLocation() string { func (b bTarget) BazelRuleLoadLocation() string {
return g.bazelRuleLoadLocation return b.bazelRuleLoadLocation
} }
func (g goBazelTarget) BazelAttributes() []interface{} { func (b bTarget) BazelAttributes() []interface{} {
return g.bazelAttributes return b.bazelAttributes
} }
// Creates a target_compatible_with entry that is *not* compatible with android // Creates a target_compatible_with entry that is *not* compatible with android
@ -421,7 +421,7 @@ func generateBazelTargetsGoTest(ctx *android.Context, goModulesMap nameToGoLibra
Target_compatible_with: targetNotCompatibleWithAndroid(), Target_compatible_with: targetNotCompatibleWithAndroid(),
} }
libTest := goBazelTarget{ libTest := bTarget{
targetName: gp.name, targetName: gp.name,
targetPackage: gp.dir, targetPackage: gp.dir,
bazelRuleClass: "go_test", bazelRuleClass: "go_test",
@ -514,7 +514,7 @@ func generateBazelTargetsGoPackage(ctx *android.Context, g *bootstrap.GoPackage,
Target_compatible_with: targetNotCompatibleWithAndroid(), Target_compatible_with: targetNotCompatibleWithAndroid(),
} }
lib := goBazelTarget{ lib := bTarget{
targetName: g.Name(), targetName: g.Name(),
targetPackage: ctx.ModuleDir(g), targetPackage: ctx.ModuleDir(g),
bazelRuleClass: "go_library", bazelRuleClass: "go_library",
@ -555,23 +555,35 @@ type goLibraryModule struct {
Deps []string Deps []string
} }
type buildConversionMetadata struct {
nameToGoLibraryModule nameToGoLibraryModule
ndkHeaders []blueprint.Module
}
type nameToGoLibraryModule map[string]goLibraryModule type nameToGoLibraryModule map[string]goLibraryModule
// Visit each module in the graph // Visit each module in the graph, and collect metadata about the build graph
// If a module is of type `bootstrap_go_package`, return a map containing metadata like its dir and deps // If a module is of type `bootstrap_go_package`, return a map containing metadata like its dir and deps
func createGoLibraryModuleMap(ctx *android.Context) nameToGoLibraryModule { // If a module is of type `ndk_headers`, add it to a list and return the list
ret := nameToGoLibraryModule{} func createBuildConversionMetadata(ctx *android.Context) buildConversionMetadata {
goMap := nameToGoLibraryModule{}
ndkHeaders := []blueprint.Module{}
ctx.VisitAllModules(func(m blueprint.Module) { ctx.VisitAllModules(func(m blueprint.Module) {
moduleType := ctx.ModuleType(m) moduleType := ctx.ModuleType(m)
// We do not need to store information about blueprint_go_binary since it does not have any rdeps // We do not need to store information about blueprint_go_binary since it does not have any rdeps
if moduleType == "bootstrap_go_package" { if moduleType == "bootstrap_go_package" {
ret[m.Name()] = goLibraryModule{ goMap[m.Name()] = goLibraryModule{
Dir: ctx.ModuleDir(m), Dir: ctx.ModuleDir(m),
Deps: m.(*bootstrap.GoPackage).Deps(), Deps: m.(*bootstrap.GoPackage).Deps(),
} }
} else if moduleType == "ndk_headers" {
ndkHeaders = append(ndkHeaders, m)
} }
}) })
return ret return buildConversionMetadata{
nameToGoLibraryModule: goMap,
ndkHeaders: ndkHeaders,
}
} }
// Returns the deps in the transitive closure of a go target // Returns the deps in the transitive closure of a go target
@ -620,7 +632,7 @@ func generateBazelTargetsGoBinary(ctx *android.Context, g *bootstrap.GoBinary, g
Deps: goDepLabels(transitiveDeps, goModulesMap), Deps: goDepLabels(transitiveDeps, goModulesMap),
Target_compatible_with: targetNotCompatibleWithAndroid(), Target_compatible_with: targetNotCompatibleWithAndroid(),
} }
libTestSource := goBazelTarget{ libTestSource := bTarget{
targetName: goSource, targetName: goSource,
targetPackage: ctx.ModuleDir(g), targetPackage: ctx.ModuleDir(g),
bazelRuleClass: "go_source", bazelRuleClass: "go_source",
@ -669,7 +681,7 @@ func generateBazelTargetsGoBinary(ctx *android.Context, g *bootstrap.GoBinary, g
ga.Srcs = goSrcLabels(ctx.Config(), ctx.ModuleDir(g), g.Srcs(), g.LinuxSrcs(), g.DarwinSrcs()) ga.Srcs = goSrcLabels(ctx.Config(), ctx.ModuleDir(g), g.Srcs(), g.LinuxSrcs(), g.DarwinSrcs())
} }
bin := goBazelTarget{ bin := bTarget{
targetName: g.Name(), targetName: g.Name(),
targetPackage: ctx.ModuleDir(g), targetPackage: ctx.ModuleDir(g),
bazelRuleClass: "go_binary", bazelRuleClass: "go_binary",
@ -700,7 +712,9 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (convers
// Visit go libraries in a pre-run and store its state in a map // Visit go libraries in a pre-run and store its state in a map
// The time complexity remains O(N), and this does not add significant wall time. // The time complexity remains O(N), and this does not add significant wall time.
nameToGoLibMap := createGoLibraryModuleMap(ctx.Context()) meta := createBuildConversionMetadata(ctx.Context())
nameToGoLibMap := meta.nameToGoLibraryModule
ndkHeaders := meta.ndkHeaders
bpCtx := ctx.Context() bpCtx := ctx.Context()
bpCtx.VisitAllModules(func(m blueprint.Module) { bpCtx.VisitAllModules(func(m blueprint.Module) {
@ -805,6 +819,39 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (convers
} }
}) })
// Create an ndk_sysroot target that has a dependency edge on every target corresponding to Soong's ndk_headers
// This root target will provide headers to sdk variants of jni libraries
if ctx.Mode() == Bp2Build {
var depLabels bazel.LabelList
for _, ndkHeader := range ndkHeaders {
depLabel := bazel.Label{
Label: "//" + bpCtx.ModuleDir(ndkHeader) + ":" + ndkHeader.Name(),
}
depLabels.Add(&depLabel)
}
a := struct {
Deps bazel.LabelListAttribute
System_dynamic_deps bazel.LabelListAttribute
}{
Deps: bazel.MakeLabelListAttribute(bazel.UniqueSortedBazelLabelList(depLabels)),
System_dynamic_deps: bazel.MakeLabelListAttribute(bazel.MakeLabelList([]bazel.Label{})),
}
ndkSysroot := bTarget{
targetName: "ndk_sysroot",
targetPackage: "build/bazel/rules/cc", // The location is subject to change, use build/bazel for now
bazelRuleClass: "cc_library_headers",
bazelRuleLoadLocation: "//build/bazel/rules/cc:cc_library_headers.bzl",
bazelAttributes: []interface{}{&a},
}
if t, err := generateBazelTarget(bpCtx, ndkSysroot); err == nil {
dir := ndkSysroot.targetPackage
buildFileToTargets[dir] = append(buildFileToTargets[dir], t)
} else {
errs = append(errs, err)
}
}
if len(errs) > 0 { if len(errs) > 0 {
return conversionResults{}, errs return conversionResults{}, errs
} }

View file

@ -159,6 +159,10 @@ cc_library {
"min_sdk_version": `"29"`, "min_sdk_version": `"29"`,
"use_version_lib": `True`, "use_version_lib": `True`,
"whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`, "whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
"deps": `select({
"//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"],
"//conditions:default": [],
})`,
}), }),
}) })
} }

View file

@ -118,6 +118,10 @@ cc_library_headers {
]`, ]`,
"sdk_version": `"current"`, "sdk_version": `"current"`,
"min_sdk_version": `"29"`, "min_sdk_version": `"29"`,
"deps": `select({
"//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"],
"//conditions:default": [],
})`,
}), }),
}, },
}) })

View file

@ -175,6 +175,10 @@ cc_library_shared {
]`, ]`,
"sdk_version": `"current"`, "sdk_version": `"current"`,
"min_sdk_version": `"29"`, "min_sdk_version": `"29"`,
"deps": `select({
"//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"],
"//conditions:default": [],
})`,
}), }),
}, },
}) })
@ -1642,6 +1646,10 @@ ndk_library {
})`, })`,
"local_includes": `["."]`, "local_includes": `["."]`,
"sdk_version": `"current"`, "sdk_version": `"current"`,
"deps": `select({
"//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"],
"//conditions:default": [],
})`,
}), }),
}, },
}) })

View file

@ -203,6 +203,10 @@ cc_library_static {
]`, ]`,
"sdk_version": `"current"`, "sdk_version": `"current"`,
"min_sdk_version": `"29"`, "min_sdk_version": `"29"`,
"deps": `select({
"//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"],
"//conditions:default": [],
})`,
}), }),
}, },
}) })

View file

@ -1378,10 +1378,10 @@ func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.Bp2buildMutator
// having stubs or not, so Bazel select() statement can be used to choose // having stubs or not, so Bazel select() statement can be used to choose
// source/stub variants of them. // source/stub variants of them.
apexAvailable := module.ApexAvailable() apexAvailable := module.ApexAvailable()
SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, 0, false) SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, &la.deps, 0, false)
SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, 1, false) SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, &la.deps, 1, false)
if len(systemSharedLibs) > 0 { if len(systemSharedLibs) > 0 {
SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, bazelLabelForSharedDeps(ctx, systemSharedLibs), &la.systemDynamicDeps, 2, true) SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, bazelLabelForSharedDeps(ctx, systemSharedLibs), &la.systemDynamicDeps, &la.deps, 2, true)
} }
} }
@ -1588,7 +1588,7 @@ func hasNdkStubs(ctx android.BazelConversionPathContext, c *Module) bool {
} }
func SetStubsForDynamicDeps(ctx android.Bp2buildMutatorContext, axis bazel.ConfigurationAxis, func SetStubsForDynamicDeps(ctx android.Bp2buildMutatorContext, axis bazel.ConfigurationAxis,
config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int, buildNonApexWithStubs bool) { config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, deps *bazel.LabelListAttribute, ind int, buildNonApexWithStubs bool) {
// Create a config_setting for each apex_available. // Create a config_setting for each apex_available.
// This will be used to select impl of a dep if dep is available to the same apex. // This will be used to select impl of a dep if dep is available to the same apex.
@ -1669,9 +1669,21 @@ func SetStubsForDynamicDeps(ctx android.Bp2buildMutatorContext, axis bazel.Confi
existingValue.Append(bazel.MakeLabelList([]bazel.Label{label})) existingValue.Append(bazel.MakeLabelList([]bazel.Label{label}))
dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, "unbundled_app", bazel.FirstUniqueBazelLabelList(existingValue)) dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, "unbundled_app", bazel.FirstUniqueBazelLabelList(existingValue))
} }
// Add ndk_sysroot to deps.
// ndk_sysroot has a dependency edge on all ndk_headers, and will provide the .h files of _every_ ndk library
existingValue := deps.SelectValue(bazel.OsAndInApexAxis, "unbundled_app")
existingValue.Append(bazel.MakeLabelList([]bazel.Label{ndkSysrootLabel}))
deps.SetSelectValue(bazel.OsAndInApexAxis, "unbundled_app", bazel.FirstUniqueBazelLabelList(existingValue))
} }
} }
var (
ndkSysrootLabel = bazel.Label{
Label: "//build/bazel/rules/cc:ndk_sysroot",
}
)
func (la *linkerAttributes) convertStripProps(ctx android.BazelConversionPathContext, module *Module) { func (la *linkerAttributes) convertStripProps(ctx android.BazelConversionPathContext, module *Module) {
bp2BuildPropParseHelper(ctx, module, &StripProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { bp2BuildPropParseHelper(ctx, module, &StripProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
if stripProperties, ok := props.(*StripProperties); ok { if stripProperties, ok := props.(*StripProperties); ok {