diff --git a/bp2build/java_proto_conversion_test.go b/bp2build/java_proto_conversion_test.go index 5d6b08814..dfef6973c 100644 --- a/bp2build/java_proto_conversion_test.go +++ b/bp2build/java_proto_conversion_test.go @@ -137,3 +137,50 @@ func TestJavaProtoDefault(t *testing.T) { }, }) } + +func TestJavaLibsAndOnlyProtoSrcs(t *testing.T) { + runJavaProtoTestCase(t, Bp2buildTestCase{ + Description: "java_library that has only proto srcs", + Blueprint: `java_library_static { + name: "java-protos", + srcs: ["a.proto"], + libs: ["java-lib"], + java_version: "7", + sdk_version: "current", +} + +java_library_static { + name: "java-lib", + bazel_module: { bp2build_available: false }, +} +`, + ExpectedBazelTargets: []string{ + MakeBazelTarget("proto_library", "java-protos_proto", AttrNameToString{ + "srcs": `["a.proto"]`, + }), + MakeBazelTarget( + "java_lite_proto_library", + "java-protos_java_proto_lite", + AttrNameToString{ + "deps": `[":java-protos_proto"]`, + "java_version": `"7"`, + "sdk_version": `"current"`, + }), + MakeBazelTarget("java_library", "java-protos", AttrNameToString{ + "exports": `[ + ":java-protos_java_proto_lite", + ":java-lib-neverlink", + ]`, + "java_version": `"7"`, + "sdk_version": `"current"`, + }), + MakeNeverlinkDuplicateTargetWithAttrs( + "java_library", + "java-protos", + AttrNameToString{ + "java_version": `"7"`, + "sdk_version": `"current"`, + }), + }, + }) +} diff --git a/java/java.go b/java/java.go index 99bb1b3ee..a81abe61c 100644 --- a/java/java.go +++ b/java/java.go @@ -2885,8 +2885,9 @@ type javaAidlLibraryAttributes struct { // depending on the module type. type bp2BuildJavaInfo struct { // separates dependencies into dynamic dependencies and static dependencies. - DepLabels *javaDependencyLabels - hasKotlin bool + DepLabels *javaDependencyLabels + hasKotlin bool + onlyProtoInSrcs bool } func javaXsdTargetName(xsd android.XsdConfigBp2buildTargets) string { @@ -2949,6 +2950,9 @@ func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) staticDeps.Append(srcPartitions[xsdSrcPartition]) + _, protoInSrcs := srcPartitions[protoSrcPartition] + onlyProtoInSrcs := protoInSrcs && len(srcPartitions) == 1 + if !srcPartitions[logtagSrcPartition].IsEmpty() { logtagsLibName := m.Name() + "_logtags" ctx.CreateBazelTargetModule( @@ -3086,8 +3090,9 @@ func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) } bp2BuildInfo := &bp2BuildJavaInfo{ - DepLabels: depLabels, - hasKotlin: hasKotlin, + DepLabels: depLabels, + hasKotlin: hasKotlin, + onlyProtoInSrcs: onlyProtoInSrcs, } return commonAttrs, bp2BuildInfo, true @@ -3127,16 +3132,29 @@ func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) { depLabels := bp2BuildInfo.DepLabels deps := depLabels.Deps + exports := depLabels.StaticDeps if !commonAttrs.Srcs.IsEmpty() { - deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them + deps.Append(exports) // we should only append these if there are sources to use them } else if !deps.IsEmpty() { - ctx.ModuleErrorf("Module has direct dependencies but no sources. Bazel will not allow this.") + if bp2BuildInfo.onlyProtoInSrcs { + // java_library does not accept deps when there are no srcs because + // there is no compilation happening, but it accepts exports. + // bp2build converts this module to 2 java_libraries + java_xx_proto_library + proto_library + // the non-empty deps here are not necessary for compiling the protos, in which case + // they're unnecessary as deps on the java_library as well since they aren't + // being propagated to any dependencies. + // so we can put the deps to exports and drop deps here. + exports.Append(deps) + deps = bazel.LabelListAttribute{} + } else { + ctx.ModuleErrorf("Module has direct dependencies but no sources. Bazel will not allow this.") + } } var props bazel.BazelTargetModuleProperties attrs := &javaLibraryAttributes{ javaCommonAttributes: commonAttrs, Deps: deps, - Exports: depLabels.StaticDeps, + Exports: exports, } name := m.Name()