diff --git a/android/bazel.go b/android/bazel.go index d22034375..7a22a2ee7 100644 --- a/android/bazel.go +++ b/android/bazel.go @@ -393,8 +393,6 @@ var ( // A module can either be in this list or its directory allowlisted entirely // in bp2buildDefaultConfig, but not both at the same time. bp2buildModuleAlwaysConvertList = []string{ - "prebuilt_junit-params-assertj-core", - //external/avb "avbtool", "libavb", @@ -419,9 +417,11 @@ var ( "fec", } - // Per-module-type allowlist to always opt modules in of both bp2build and mixed builds + // Per-module-type allowlist to always opt modules in to both bp2build and mixed builds // when they have the same type as one listed. - bp2buildModuleTypeAlwaysConvertList = []string{} + bp2buildModuleTypeAlwaysConvertList = []string{ + "java_import", + } // Per-module denylist to always opt modules out of both bp2build and mixed builds. bp2buildModuleDoNotConvertList = []string{ @@ -485,18 +485,12 @@ var ( "libprotobuf-java-full", // b/210751803, we don't handle path property for filegroups "host-libprotobuf-java-full", // b/210751803, we don't handle path property for filegroups "libprotobuf-java-util-full", // b/210751803, we don't handle path property for filegroups + "apex_manifest_proto_java", // b/210751803, depends on libprotobuf-java-full + "conscrypt", // b/210751803, we don't handle path property for filegroups + "conscrypt-for-host", // b/210751803, we don't handle path property for filegroups - "conscrypt", // b/210751803, we don't handle path property for filegroups - "conscrypt-for-host", // b/210751803, we don't handle path property for filegroups - - "host-libprotobuf-java-lite", // b/217236083, java_library cannot have deps without srcs - "host-libprotobuf-java-micro", // b/217236083, java_library cannot have deps without srcs - "host-libprotobuf-java-nano", // b/217236083, java_library cannot have deps without srcs - "error_prone_core", // b/217236083, java_library cannot have deps without srcs - "bouncycastle-host", // b/217236083, java_library cannot have deps without srcs - "mockito-robolectric-prebuilt", // b/217236083, java_library cannot have deps without srcs - - "apex_manifest_proto_java", // b/215230097, we don't handle .proto files in java_library srcs attribute + "libprotobuf-java-nano", // b/220869005, depends on non-public_current SDK + "host-libprotobuf-java-nano", // b/220869005, depends on libprotobuf-java-nano "libc_musl_sysroot_bionic_arch_headers", // b/218405924, depends on soong_zip "libc_musl_sysroot_bionic_headers", // b/218405924, depends on soong_zip and generates duplicate srcs @@ -566,9 +560,23 @@ var ( "art-script", // depends on unconverted modules: dalvikvm, dex2oat "dex2oat-script", // depends on unconverted modules: dex2oat - "error_prone_checkerframework_dataflow_nullaway", // TODO(b/219908977): "Error in fail: deps not allowed without srcs; move to runtime_deps?" + // TODO(b/221082840) convert java_imports in //packages/apps/Car/libs/car-ui-lib/... + "prebuilt_car-ui-androidx-annotation", + "prebuilt_car-ui-androidx-annotation-nodeps", + "prebuilt_car-ui-androidx-collection", + "prebuilt_car-ui-androidx-collection-nodeps", + "prebuilt_car-ui-androidx-core-common", + "prebuilt_car-ui-androidx-core-common-nodeps", + "prebuilt_car-ui-androidx-lifecycle-common", + "prebuilt_car-ui-androidx-lifecycle-common-nodeps", + "prebuilt_car-ui-androidx-constraintlayout-solver", + "prebuilt_car-ui-androidx-constraintlayout-solver-nodeps", - "libprotobuf-java-nano", // b/220869005, depends on non-public_current SDK + "prebuilt_art-module-host-exports_okhttp-norepackage@current", // aosp/1999250, needs Jars (arch variant) + "prebuilt_conscrypt-unbundled", // aosp/1999250, needs Jars (arch variant) + "prebuilt_conscrypt-module-host-exports_conscrypt-unbundled@current", // aosp/1999250, needs Jars (arch variant) + "prebuilt_platform-robolectric-4.4-prebuilt", // aosp/1999250, needs .aar support in Jars + "prebuilt_platform-robolectric-4.5.1-prebuilt", // aosp/1999250, needs .aar support in Jars } // Per-module denylist of cc_library modules to only generate the static diff --git a/bazel/properties.go b/bazel/properties.go index 1300a53e2..f9560319e 100644 --- a/bazel/properties.go +++ b/bazel/properties.go @@ -65,6 +65,14 @@ type LabelList struct { Excludes []Label } +// MakeLabelList creates a LabelList from a list Label +func MakeLabelList(labels []Label) LabelList { + return LabelList{ + Includes: labels, + Excludes: nil, + } +} + func (ll *LabelList) Equals(other LabelList) bool { if len(ll.Includes) != len(other.Includes) || len(ll.Excludes) != len(other.Excludes) { return false @@ -354,6 +362,15 @@ func (la *LabelAttribute) SortedConfigurationAxes() []ConfigurationAxis { return keys } +// MakeLabelAttribute turns a string into a LabelAttribute +func MakeLabelAttribute(label string) *LabelAttribute { + return &LabelAttribute{ + Value: &Label{ + Label: label, + }, + } +} + type configToBools map[string]bool func (ctb configToBools) setValue(config string, value *bool) { diff --git a/bp2build/android_app_conversion_test.go b/bp2build/android_app_conversion_test.go index b6095b2ef..3824586c6 100644 --- a/bp2build/android_app_conversion_test.go +++ b/bp2build/android_app_conversion_test.go @@ -51,7 +51,6 @@ android_app { "srcs": `["app.java"]`, "manifest": `"AndroidManifest.xml"`, "resource_files": `["res/res.png"]`, - "deps": `["//prebuilts/sdk:public_current_android_sdk_java_import"]`, }), }}) } @@ -87,10 +86,7 @@ android_app { "resb/res.png", ]`, "custom_package": `"com.google"`, - "deps": `[ - "//prebuilts/sdk:public_current_android_sdk_java_import", - ":static_lib_dep", - ]`, + "deps": `[":static_lib_dep"]`, }), }}) } @@ -129,7 +125,6 @@ android_app { })`, "manifest": `"AndroidManifest.xml"`, "resource_files": `["res/res.png"]`, - "deps": `["//prebuilts/sdk:public_current_android_sdk_java_import"]`, }), }}) } diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go index 65136d9f1..4fc07e014 100644 --- a/bp2build/java_binary_host_conversion_test.go +++ b/bp2build/java_binary_host_conversion_test.go @@ -28,6 +28,7 @@ func runJavaBinaryHostTestCase(t *testing.T, tc bp2buildTestCase) { (&tc).moduleTypeUnderTestFactory = java.BinaryHostFactory runBp2BuildTestCase(t, func(ctx android.RegistrationContext) { ctx.RegisterModuleType("cc_library_host_shared", cc.LibraryHostSharedFactory) + ctx.RegisterModuleType("java_library", java.LibraryFactory) }, tc) } @@ -67,3 +68,33 @@ func TestJavaBinaryHost(t *testing.T) { }, }) } + +func TestJavaBinaryHostRuntimeDeps(t *testing.T) { + runJavaBinaryHostTestCase(t, bp2buildTestCase{ + description: "java_binary_host with srcs, exclude_srcs, jni_libs, javacflags, and manifest.", + filesystem: fs, + blueprint: `java_binary_host { + name: "java-binary-host-1", + static_libs: ["java-dep-1"], + manifest: "test.mf", + bazel_module: { bp2build_available: true }, +} + +java_library { + name: "java-dep-1", + srcs: ["a.java"], + bazel_module: { bp2build_available: false }, +} +`, + expectedBazelTargets: []string{ + makeBazelTarget("java_binary", "java-binary-host-1", attrNameToString{ + "main_class": `"com.android.test.MainClass"`, + "runtime_deps": `[":java-dep-1"]`, + "target_compatible_with": `select({ + "//build/bazel/platforms/os:android": ["@platforms//:incompatible"], + "//conditions:default": [], + })`, + }), + }, + }) +} diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go index 5c65ec230..cf811ed67 100644 --- a/bp2build/java_library_conversion_test.go +++ b/bp2build/java_library_conversion_test.go @@ -15,6 +15,7 @@ package bp2build import ( + "fmt" "testing" "android/soong/android" @@ -55,3 +56,76 @@ java_library { }, }) } + +func TestJavaLibraryConvertsStaticLibsToDepsAndExports(t *testing.T) { + runJavaLibraryTestCase(t, bp2buildTestCase{ + blueprint: `java_library { + name: "java-lib-1", + srcs: ["a.java"], + libs: ["java-lib-2"], + static_libs: ["java-lib-3"], + bazel_module: { bp2build_available: true }, +} + +java_library { + name: "java-lib-2", + srcs: ["b.java"], + bazel_module: { bp2build_available: false }, +} + +java_library { + name: "java-lib-3", + srcs: ["c.java"], + bazel_module: { bp2build_available: false }, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("java_library", "java-lib-1", attrNameToString{ + "srcs": `["a.java"]`, + "deps": `[ + ":java-lib-2", + ":java-lib-3", + ]`, + "exports": `[":java-lib-3"]`, + }), + }, + }) +} + +func TestJavaLibraryConvertsStaticLibsToExportsIfNoSrcs(t *testing.T) { + runJavaLibraryTestCase(t, bp2buildTestCase{ + blueprint: `java_library { + name: "java-lib-1", + static_libs: ["java-lib-2"], + bazel_module: { bp2build_available: true }, +} + +java_library { + name: "java-lib-2", + srcs: ["a.java"], + bazel_module: { bp2build_available: false }, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("java_library", "java-lib-1", attrNameToString{ + "exports": `[":java-lib-2"]`, + }), + }, + }) +} + +func TestJavaLibraryFailsToConvertLibsWithNoSrcs(t *testing.T) { + runJavaLibraryTestCase(t, bp2buildTestCase{ + expectedErr: fmt.Errorf("Module has direct dependencies but no sources. Bazel will not allow this."), + blueprint: `java_library { + name: "java-lib-1", + libs: ["java-lib-2"], + bazel_module: { bp2build_available: true }, +} + +java_library { + name: "java-lib-2", + srcs: ["a.java"], + bazel_module: { bp2build_available: false }, +}`, + expectedBazelTargets: []string{}, + }) +} diff --git a/bp2build/java_plugin_conversion_test.go b/bp2build/java_plugin_conversion_test.go index ff13bb054..c2a2182bd 100644 --- a/bp2build/java_plugin_conversion_test.go +++ b/bp2build/java_plugin_conversion_test.go @@ -70,3 +70,39 @@ java_library { }, }) } + +func TestJavaPluginNoSrcs(t *testing.T) { + runJavaPluginTestCase(t, bp2buildTestCase{ + description: "java_plugin without srcs converts (static) libs to deps", + blueprint: `java_plugin { + name: "java-plug-1", + libs: ["java-lib-1"], + static_libs: ["java-lib-2"], + bazel_module: { bp2build_available: true }, +} + +java_library { + name: "java-lib-1", + srcs: ["b.java"], + bazel_module: { bp2build_available: false }, +} + +java_library { + name: "java-lib-2", + srcs: ["c.java"], + bazel_module: { bp2build_available: false }, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("java_plugin", "java-plug-1", attrNameToString{ + "target_compatible_with": `select({ + "//build/bazel/platforms/os:android": ["@platforms//:incompatible"], + "//conditions:default": [], + })`, + "deps": `[ + ":java-lib-1", + ":java-lib-2", + ]`, + }), + }, + }) +} diff --git a/bp2build/java_proto_conversion_test.go b/bp2build/java_proto_conversion_test.go index 61a398cd9..67f80446e 100644 --- a/bp2build/java_proto_conversion_test.go +++ b/bp2build/java_proto_conversion_test.go @@ -89,7 +89,7 @@ func TestJavaProto(t *testing.T) { "deps": `[":java-protos_proto"]`, }), makeBazelTarget("java_library", "java-protos", attrNameToString{ - "deps": fmt.Sprintf(`[":%s"]`, javaLibraryName), + "exports": fmt.Sprintf(`[":%s"]`, javaLibraryName), }), }, }) @@ -98,7 +98,7 @@ func TestJavaProto(t *testing.T) { func TestJavaProtoDefault(t *testing.T) { runJavaProtoTestCase(t, bp2buildTestCase{ - description: "java_proto", + description: "java_library proto default", blueprint: `java_library_static { name: "java-protos", srcs: ["a.proto"], @@ -115,7 +115,7 @@ func TestJavaProtoDefault(t *testing.T) { "deps": `[":java-protos_proto"]`, }), makeBazelTarget("java_library", "java-protos", attrNameToString{ - "deps": `[":java-protos_java_proto_lite"]`, + "exports": `[":java-protos_java_proto_lite"]`, }), }, }) diff --git a/java/app.go b/java/app.go index cd484f557..72b922e93 100755 --- a/java/app.go +++ b/java/app.go @@ -1456,7 +1456,8 @@ func androidAppCertificateBp2Build(ctx android.TopDownMutatorContext, module *An } type bazelAndroidAppAttributes struct { - *javaLibraryAttributes + *javaCommonAttributes + Deps bazel.LabelListAttribute Manifest bazel.Label Custom_package *string Resource_files bazel.LabelListAttribute @@ -1466,7 +1467,16 @@ type bazelAndroidAppAttributes struct { // ConvertWithBp2build is used to convert android_app to Bazel. func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) { - libAttrs := a.convertLibraryAttrsBp2Build(ctx) + commonAttrs, depLabels := a.convertLibraryAttrsBp2Build(ctx) + + deps := depLabels.Deps + if !commonAttrs.Srcs.IsEmpty() { + deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them + } else if !deps.IsEmpty() || !depLabels.StaticDeps.IsEmpty() { + ctx.ModuleErrorf("android_app has dynamic or static dependencies but no sources." + + " Bazel does not allow direct dependencies without sources nor exported" + + " dependencies on android_binary rule.") + } manifest := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml") @@ -1489,7 +1499,8 @@ func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) { } attrs := &bazelAndroidAppAttributes{ - libAttrs, + commonAttrs, + deps, android.BazelLabelForModuleSrcSingle(ctx, manifest), // TODO(b/209576404): handle package name override by product variable PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES a.overridableAppProperties.Package_name, diff --git a/java/java.go b/java/java.go index ddef34d2c..8ae14803f 100644 --- a/java/java.go +++ b/java/java.go @@ -2023,13 +2023,23 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.Module, } } -type javaLibraryAttributes struct { +type javaCommonAttributes struct { Srcs bazel.LabelListAttribute - Deps bazel.LabelListAttribute Javacopts bazel.StringListAttribute } -func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) *javaLibraryAttributes { +type javaDependencyLabels struct { + // Dependencies which DO NOT contribute to the API visible to upstream dependencies. + Deps bazel.LabelListAttribute + // Dependencies which DO contribute to the API visible to upstream dependencies. + StaticDeps bazel.LabelListAttribute +} + +// convertLibraryAttrsBp2Build converts a few shared attributes from java_* modules +// and also separates dependencies into dynamic dependencies and static dependencies. +// Each corresponding Bazel target type, can have a different method for handling +// dynamic vs. static dependencies, and so these are returned to the calling function. +func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) (*javaCommonAttributes, *javaDependencyLabels) { var srcs bazel.LabelListAttribute archVariantProps := m.GetArchVariantProperties(ctx, &CommonProperties{}) for axis, configToProps := range archVariantProps { @@ -2048,40 +2058,68 @@ func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) protoSrcPartition: android.ProtoSrcLabelPartition, }) - attrs := &javaLibraryAttributes{ + commonAttrs := &javaCommonAttributes{ Srcs: srcPartitions[javaSrcPartition], } if m.properties.Javacflags != nil { - attrs.Javacopts = bazel.MakeStringListAttribute(m.properties.Javacflags) + commonAttrs.Javacopts = bazel.MakeStringListAttribute(m.properties.Javacflags) } + depLabels := &javaDependencyLabels{} + var deps bazel.LabelList - sdkVersion := m.SdkVersion(ctx) - if sdkVersion.Kind == android.SdkPublic && sdkVersion.ApiLevel == android.FutureApiLevel { - // TODO(b/220869005) remove forced dependency on current public android.jar - deps.Add(&bazel.Label{Label: "//prebuilts/sdk:public_current_android_sdk_java_import"}) - } if m.properties.Libs != nil { deps.Append(android.BazelLabelForModuleDeps(ctx, m.properties.Libs)) } + + var staticDeps bazel.LabelList if m.properties.Static_libs != nil { - //TODO(b/217236083) handle static libs similarly to Soong - deps.Append(android.BazelLabelForModuleDeps(ctx, m.properties.Static_libs)) + staticDeps.Append(android.BazelLabelForModuleDeps(ctx, m.properties.Static_libs)) } - protoDeps := bp2buildProto(ctx, &m.Module, srcPartitions[protoSrcPartition]) - if protoDeps != nil { - deps.Add(protoDeps) - } + protoDepLabel := bp2buildProto(ctx, &m.Module, srcPartitions[protoSrcPartition]) + // Soong does not differentiate between a java_library and the Bazel equivalent of + // a java_proto_library + proto_library pair. Instead, in Soong proto sources are + // listed directly in the srcs of a java_library, and the classes produced + // by protoc are included directly in the resulting JAR. Thus upstream dependencies + // that depend on a java_library with proto sources can link directly to the protobuf API, + // and so this should be a static dependency. + staticDeps.Add(protoDepLabel) - attrs.Deps = bazel.MakeLabelListAttribute(deps) + depLabels.Deps = bazel.MakeLabelListAttribute(deps) + depLabels.StaticDeps = bazel.MakeLabelListAttribute(staticDeps) - return attrs + return commonAttrs, depLabels +} + +type javaLibraryAttributes struct { + *javaCommonAttributes + Deps bazel.LabelListAttribute + Exports bazel.LabelListAttribute } func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) { - attrs := m.convertLibraryAttrsBp2Build(ctx) + commonAttrs, depLabels := m.convertLibraryAttrsBp2Build(ctx) + + deps := depLabels.Deps + if !commonAttrs.Srcs.IsEmpty() { + deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them + + sdkVersion := m.SdkVersion(ctx) + if sdkVersion.Kind == android.SdkPublic && sdkVersion.ApiLevel == android.FutureApiLevel { + // TODO(b/220869005) remove forced dependency on current public android.jar + deps.Add(bazel.MakeLabelAttribute("//prebuilts/sdk:public_current_android_sdk_java_import")) + } + } else if !depLabels.Deps.IsEmpty() { + ctx.ModuleErrorf("Module has direct dependencies but no sources. Bazel will not allow this.") + } + + attrs := &javaLibraryAttributes{ + javaCommonAttributes: commonAttrs, + Deps: deps, + Exports: depLabels.StaticDeps, + } props := bazel.BazelTargetModuleProperties{ Rule_class: "java_library", @@ -2092,15 +2130,30 @@ func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) { } type javaBinaryHostAttributes struct { - Srcs bazel.LabelListAttribute - Deps bazel.LabelListAttribute - Main_class string - Jvm_flags bazel.StringListAttribute - Javacopts bazel.StringListAttribute + *javaCommonAttributes + Deps bazel.LabelListAttribute + Runtime_deps bazel.LabelListAttribute + Main_class string + Jvm_flags bazel.StringListAttribute } // JavaBinaryHostBp2Build is for java_binary_host bp2build. func javaBinaryHostBp2Build(ctx android.TopDownMutatorContext, m *Binary) { + commonAttrs, depLabels := m.convertLibraryAttrsBp2Build(ctx) + + deps := depLabels.Deps + deps.Append(depLabels.StaticDeps) + if m.binaryProperties.Jni_libs != nil { + deps.Append(bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, m.binaryProperties.Jni_libs))) + } + + var runtimeDeps bazel.LabelListAttribute + if commonAttrs.Srcs.IsEmpty() { + // if there are no sources, then the dependencies can only be used at runtime + runtimeDeps = deps + deps = bazel.LabelListAttribute{} + } + mainClass := "" if m.binaryProperties.Main_class != nil { mainClass = *m.binaryProperties.Main_class @@ -2112,26 +2165,12 @@ func javaBinaryHostBp2Build(ctx android.TopDownMutatorContext, m *Binary) { } mainClass = mainClassInManifest } - srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)) + attrs := &javaBinaryHostAttributes{ - Srcs: srcs, - Main_class: mainClass, - } - - if m.properties.Javacflags != nil { - attrs.Javacopts = bazel.MakeStringListAttribute(m.properties.Javacflags) - } - - // Attribute deps - deps := []string{} - if m.properties.Static_libs != nil { - deps = append(deps, m.properties.Static_libs...) - } - if m.binaryProperties.Jni_libs != nil { - deps = append(deps, m.binaryProperties.Jni_libs...) - } - if len(deps) > 0 { - attrs.Deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, deps)) + javaCommonAttributes: commonAttrs, + Deps: deps, + Runtime_deps: runtimeDeps, + Main_class: mainClass, } // Attribute jvm_flags diff --git a/java/plugin.go b/java/plugin.go index 4b174b930..123dbd4c0 100644 --- a/java/plugin.go +++ b/java/plugin.go @@ -58,27 +58,32 @@ type PluginProperties struct { } type pluginAttributes struct { - *javaLibraryAttributes - Processor_class *string - Target_compatible_with bazel.LabelListAttribute + *javaCommonAttributes + Deps bazel.LabelListAttribute + Processor_class *string } // ConvertWithBp2build is used to convert android_app to Bazel. func (p *Plugin) ConvertWithBp2build(ctx android.TopDownMutatorContext) { - libAttrs := p.convertLibraryAttrsBp2Build(ctx) - attrs := &pluginAttributes{ - libAttrs, - nil, - bazel.LabelListAttribute{}, + pluginName := p.Name() + commonAttrs, depLabels := p.convertLibraryAttrsBp2Build(ctx) + + deps := depLabels.Deps + deps.Append(depLabels.StaticDeps) + + var processorClass *string + if p.pluginProperties.Processor_class != nil { + processorClass = p.pluginProperties.Processor_class } - if p.pluginProperties.Processor_class != nil { - attrs.Processor_class = p.pluginProperties.Processor_class + attrs := &pluginAttributes{ + javaCommonAttributes: commonAttrs, + Deps: deps, + Processor_class: processorClass, } props := bazel.BazelTargetModuleProperties{ Rule_class: "java_plugin", } - - ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: p.Name()}, attrs) + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: pluginName}, attrs) }