From af72583468e8480696e63c2aa5e50c55d379d944 Mon Sep 17 00:00:00 2001 From: Spandan Das Date: Tue, 19 Sep 2023 19:51:52 +0000 Subject: [PATCH] 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 --- bp2build/build_conversion.go | 93 ++++++++++++++----- bp2build/cc_library_conversion_test.go | 4 + .../cc_library_headers_conversion_test.go | 4 + bp2build/cc_library_shared_conversion_test.go | 8 ++ bp2build/cc_library_static_conversion_test.go | 4 + cc/bp2build.go | 20 +++- 6 files changed, 106 insertions(+), 27 deletions(-) diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go index e6941df30..ce2a95552 100644 --- a/bp2build/build_conversion.go +++ b/bp2build/build_conversion.go @@ -287,9 +287,9 @@ func (r conversionResults) BuildDirToTargets() map[string]BazelTargets { 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 -type goBazelTarget struct { +type bTarget struct { targetName string targetPackage string bazelRuleClass string @@ -297,26 +297,26 @@ type goBazelTarget struct { bazelAttributes []interface{} } -var _ bp2buildModule = (*goBazelTarget)(nil) +var _ bp2buildModule = (*bTarget)(nil) -func (g goBazelTarget) TargetName() string { - return g.targetName +func (b bTarget) TargetName() string { + return b.targetName } -func (g goBazelTarget) TargetPackage() string { - return g.targetPackage +func (b bTarget) TargetPackage() string { + return b.targetPackage } -func (g goBazelTarget) BazelRuleClass() string { - return g.bazelRuleClass +func (b bTarget) BazelRuleClass() string { + return b.bazelRuleClass } -func (g goBazelTarget) BazelRuleLoadLocation() string { - return g.bazelRuleLoadLocation +func (b bTarget) BazelRuleLoadLocation() string { + return b.bazelRuleLoadLocation } -func (g goBazelTarget) BazelAttributes() []interface{} { - return g.bazelAttributes +func (b bTarget) BazelAttributes() []interface{} { + return b.bazelAttributes } // 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(), } - libTest := goBazelTarget{ + libTest := bTarget{ targetName: gp.name, targetPackage: gp.dir, bazelRuleClass: "go_test", @@ -514,7 +514,7 @@ func generateBazelTargetsGoPackage(ctx *android.Context, g *bootstrap.GoPackage, Target_compatible_with: targetNotCompatibleWithAndroid(), } - lib := goBazelTarget{ + lib := bTarget{ targetName: g.Name(), targetPackage: ctx.ModuleDir(g), bazelRuleClass: "go_library", @@ -555,23 +555,35 @@ type goLibraryModule struct { Deps []string } +type buildConversionMetadata struct { + nameToGoLibraryModule nameToGoLibraryModule + ndkHeaders []blueprint.Module +} + 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 -func createGoLibraryModuleMap(ctx *android.Context) nameToGoLibraryModule { - ret := nameToGoLibraryModule{} +// If a module is of type `ndk_headers`, add it to a list and return the list +func createBuildConversionMetadata(ctx *android.Context) buildConversionMetadata { + goMap := nameToGoLibraryModule{} + ndkHeaders := []blueprint.Module{} ctx.VisitAllModules(func(m blueprint.Module) { moduleType := ctx.ModuleType(m) // We do not need to store information about blueprint_go_binary since it does not have any rdeps if moduleType == "bootstrap_go_package" { - ret[m.Name()] = goLibraryModule{ + goMap[m.Name()] = goLibraryModule{ Dir: ctx.ModuleDir(m), 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 @@ -620,7 +632,7 @@ func generateBazelTargetsGoBinary(ctx *android.Context, g *bootstrap.GoBinary, g Deps: goDepLabels(transitiveDeps, goModulesMap), Target_compatible_with: targetNotCompatibleWithAndroid(), } - libTestSource := goBazelTarget{ + libTestSource := bTarget{ targetName: goSource, targetPackage: ctx.ModuleDir(g), 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()) } - bin := goBazelTarget{ + bin := bTarget{ targetName: g.Name(), targetPackage: ctx.ModuleDir(g), 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 // 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.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 { return conversionResults{}, errs } diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go index 560123ea4..c2b65a1a1 100644 --- a/bp2build/cc_library_conversion_test.go +++ b/bp2build/cc_library_conversion_test.go @@ -159,6 +159,10 @@ cc_library { "min_sdk_version": `"29"`, "use_version_lib": `True`, "whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`, + "deps": `select({ + "//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"], + "//conditions:default": [], + })`, }), }) } diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go index fde4c973e..e54f05162 100644 --- a/bp2build/cc_library_headers_conversion_test.go +++ b/bp2build/cc_library_headers_conversion_test.go @@ -118,6 +118,10 @@ cc_library_headers { ]`, "sdk_version": `"current"`, "min_sdk_version": `"29"`, + "deps": `select({ + "//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"], + "//conditions:default": [], + })`, }), }, }) diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go index 6fa14e345..2c5305f72 100644 --- a/bp2build/cc_library_shared_conversion_test.go +++ b/bp2build/cc_library_shared_conversion_test.go @@ -175,6 +175,10 @@ cc_library_shared { ]`, "sdk_version": `"current"`, "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": `["."]`, "sdk_version": `"current"`, + "deps": `select({ + "//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"], + "//conditions:default": [], + })`, }), }, }) diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go index 7b97b3906..09e40edab 100644 --- a/bp2build/cc_library_static_conversion_test.go +++ b/bp2build/cc_library_static_conversion_test.go @@ -203,6 +203,10 @@ cc_library_static { ]`, "sdk_version": `"current"`, "min_sdk_version": `"29"`, + "deps": `select({ + "//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"], + "//conditions:default": [], + })`, }), }, }) diff --git a/cc/bp2build.go b/cc/bp2build.go index 5dc119ed2..7738487db 100644 --- a/cc/bp2build.go +++ b/cc/bp2build.go @@ -1378,10 +1378,10 @@ func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.Bp2buildMutator // having stubs or not, so Bazel select() statement can be used to choose // source/stub variants of them. apexAvailable := module.ApexAvailable() - SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, 0, false) - SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, 1, false) + SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, &la.deps, 0, false) + SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, &la.deps, 1, false) 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, - 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. // 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})) 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) { bp2BuildPropParseHelper(ctx, module, &StripProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { if stripProperties, ok := props.(*StripProperties); ok {