Handle .proto files that end up in a different package
Bazel poses a strict requirement that .proto files and proto_library must be in the same package. This CL handles this automatically by creating the proto_library in a separate dir/package if necessary Implementation details - Partition the `srcs` by package. `srcs` has been computed using `transformSubpackagePath`, so the information about packages is available at this point - Create a proto_library in each package by using `CommonAttributes.Dir`. Collect all these additional libraries and put them in `info.Proto_libraries` so that they get added as deps of (cc|python|...)_proto_library - Add an import_prefix to the proto_library in subpackages relative to the current directory. This relies on the assumption that every src is beneath the current directory (Soong will complain if a path in Android.bp contains ../) filegroup module type uses a separate code-path to create proto_library. This will be handled in the next CL in stack. Test: bp2build unit tests Test: TH Test: Built the failing internal module mentioned in b/292583584#comment1 Bug: 292583584 Change-Id: I437fc89092321b26c5f0511387cde9e84084d6f9
This commit is contained in:
127
android/proto.go
127
android/proto.go
@@ -15,6 +15,7 @@
|
|||||||
package android
|
package android
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"android/soong/bazel"
|
"android/soong/bazel"
|
||||||
@@ -156,12 +157,12 @@ func ProtoRule(rule *RuleBuilder, protoFile Path, flags ProtoFlags, deps Paths,
|
|||||||
// Bp2buildProtoInfo contains information necessary to pass on to language specific conversion.
|
// Bp2buildProtoInfo contains information necessary to pass on to language specific conversion.
|
||||||
type Bp2buildProtoInfo struct {
|
type Bp2buildProtoInfo struct {
|
||||||
Type *string
|
Type *string
|
||||||
Name string
|
|
||||||
Proto_libs bazel.LabelList
|
Proto_libs bazel.LabelList
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProtoAttrs struct {
|
type ProtoAttrs struct {
|
||||||
Srcs bazel.LabelListAttribute
|
Srcs bazel.LabelListAttribute
|
||||||
|
Import_prefix *string
|
||||||
Strip_import_prefix *string
|
Strip_import_prefix *string
|
||||||
Deps bazel.LabelListAttribute
|
Deps bazel.LabelListAttribute
|
||||||
}
|
}
|
||||||
@@ -172,6 +173,35 @@ var includeDirsToProtoDeps = map[string]string{
|
|||||||
"external/protobuf/src": "//external/protobuf:libprotobuf-proto",
|
"external/protobuf/src": "//external/protobuf:libprotobuf-proto",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Partitions srcs by the pkg it is in
|
||||||
|
// srcs has been created using `TransformSubpackagePaths`
|
||||||
|
// This function uses existence of Android.bp/BUILD files to create a label that is compatible with the package structure of bp2build workspace
|
||||||
|
func partitionSrcsByPackage(currentDir string, srcs bazel.LabelList) map[string]bazel.LabelList {
|
||||||
|
getPackageFromLabel := func(label string) string {
|
||||||
|
// Remove any preceding //
|
||||||
|
label = strings.TrimPrefix(label, "//")
|
||||||
|
split := strings.Split(label, ":")
|
||||||
|
if len(split) == 1 {
|
||||||
|
// e.g. foo.proto
|
||||||
|
return currentDir
|
||||||
|
} else if split[0] == "" {
|
||||||
|
// e.g. :foo.proto
|
||||||
|
return currentDir
|
||||||
|
} else {
|
||||||
|
return split[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgToSrcs := map[string]bazel.LabelList{}
|
||||||
|
for _, src := range srcs.Includes {
|
||||||
|
pkg := getPackageFromLabel(src.Label)
|
||||||
|
list := pkgToSrcs[pkg]
|
||||||
|
list.Add(&src)
|
||||||
|
pkgToSrcs[pkg] = list
|
||||||
|
}
|
||||||
|
return pkgToSrcs
|
||||||
|
}
|
||||||
|
|
||||||
// Bp2buildProtoProperties converts proto properties, creating a proto_library and returning the
|
// Bp2buildProtoProperties converts proto properties, creating a proto_library and returning the
|
||||||
// information necessary for language-specific handling.
|
// information necessary for language-specific handling.
|
||||||
func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs bazel.LabelListAttribute) (Bp2buildProtoInfo, bool) {
|
func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs bazel.LabelListAttribute) (Bp2buildProtoInfo, bool) {
|
||||||
@@ -197,54 +227,73 @@ func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs baz
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info.Name = m.Name() + "_proto"
|
name := m.Name() + "_proto"
|
||||||
|
|
||||||
|
depsFromFilegroup := protoLibraries
|
||||||
|
|
||||||
if len(directProtoSrcs.Includes) > 0 {
|
if len(directProtoSrcs.Includes) > 0 {
|
||||||
attrs := ProtoAttrs{
|
pkgToSrcs := partitionSrcsByPackage(ctx.ModuleDir(), directProtoSrcs)
|
||||||
Srcs: bazel.MakeLabelListAttribute(directProtoSrcs),
|
for _, pkg := range SortedStringKeys(pkgToSrcs) {
|
||||||
}
|
srcs := pkgToSrcs[pkg]
|
||||||
attrs.Deps.Append(bazel.MakeLabelListAttribute(protoLibraries))
|
attrs := ProtoAttrs{
|
||||||
|
Srcs: bazel.MakeLabelListAttribute(srcs),
|
||||||
|
}
|
||||||
|
attrs.Deps.Append(bazel.MakeLabelListAttribute(depsFromFilegroup))
|
||||||
|
|
||||||
for axis, configToProps := range m.GetArchVariantProperties(ctx, &ProtoProperties{}) {
|
for axis, configToProps := range m.GetArchVariantProperties(ctx, &ProtoProperties{}) {
|
||||||
for _, rawProps := range configToProps {
|
for _, rawProps := range configToProps {
|
||||||
var props *ProtoProperties
|
var props *ProtoProperties
|
||||||
var ok bool
|
var ok bool
|
||||||
if props, ok = rawProps.(*ProtoProperties); !ok {
|
if props, ok = rawProps.(*ProtoProperties); !ok {
|
||||||
ctx.ModuleErrorf("Could not cast ProtoProperties to expected type")
|
ctx.ModuleErrorf("Could not cast ProtoProperties to expected type")
|
||||||
}
|
|
||||||
if axis == bazel.NoConfigAxis {
|
|
||||||
info.Type = props.Proto.Type
|
|
||||||
|
|
||||||
if !proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault) {
|
|
||||||
// an empty string indicates to strips the package path
|
|
||||||
path := ""
|
|
||||||
attrs.Strip_import_prefix = &path
|
|
||||||
}
|
}
|
||||||
|
if axis == bazel.NoConfigAxis {
|
||||||
|
info.Type = props.Proto.Type
|
||||||
|
|
||||||
for _, dir := range props.Proto.Include_dirs {
|
if !proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault) {
|
||||||
if dep, ok := includeDirsToProtoDeps[dir]; ok {
|
// an empty string indicates to strips the package path
|
||||||
attrs.Deps.Add(bazel.MakeLabelAttribute(dep))
|
path := ""
|
||||||
} else {
|
attrs.Strip_import_prefix = &path
|
||||||
ctx.PropertyErrorf("Could not find the proto_library target for include dir", dir)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, dir := range props.Proto.Include_dirs {
|
||||||
|
if dep, ok := includeDirsToProtoDeps[dir]; ok {
|
||||||
|
attrs.Deps.Add(bazel.MakeLabelAttribute(dep))
|
||||||
|
} else {
|
||||||
|
ctx.PropertyErrorf("Could not find the proto_library target for include dir", dir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if props.Proto.Type != info.Type && props.Proto.Type != nil {
|
||||||
|
ctx.ModuleErrorf("Cannot handle arch-variant types for protos at this time.")
|
||||||
}
|
}
|
||||||
} else if props.Proto.Type != info.Type && props.Proto.Type != nil {
|
|
||||||
ctx.ModuleErrorf("Cannot handle arch-variant types for protos at this time.")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module())
|
||||||
|
|
||||||
|
// Since we are creating the proto_library in a subpackage, create an import_prefix relative to the current package
|
||||||
|
if rel, err := filepath.Rel(ctx.ModuleDir(), pkg); err != nil {
|
||||||
|
ctx.ModuleErrorf("Could not get relative path for %v %v", pkg, err)
|
||||||
|
} else if rel != "." {
|
||||||
|
attrs.Import_prefix = &rel
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.CreateBazelTargetModule(
|
||||||
|
bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
|
||||||
|
CommonAttributes{Name: name, Dir: proptools.StringPtr(pkg), Tags: tags},
|
||||||
|
&attrs,
|
||||||
|
)
|
||||||
|
|
||||||
|
l := ""
|
||||||
|
if pkg == ctx.ModuleDir() { // same package that the original module lives in
|
||||||
|
l = ":" + name
|
||||||
|
} else {
|
||||||
|
l = "//" + pkg + ":" + name
|
||||||
|
}
|
||||||
|
protoLibraries.Add(&bazel.Label{
|
||||||
|
Label: l,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module())
|
|
||||||
|
|
||||||
ctx.CreateBazelTargetModule(
|
|
||||||
bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
|
|
||||||
CommonAttributes{Name: info.Name, Tags: tags},
|
|
||||||
&attrs,
|
|
||||||
)
|
|
||||||
|
|
||||||
protoLibraries.Add(&bazel.Label{
|
|
||||||
Label: ":" + info.Name,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info.Proto_libs = protoLibraries
|
info.Proto_libs = protoLibraries
|
||||||
|
@@ -4903,3 +4903,67 @@ cc_library_shared {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bazel enforces that proto_library and the .proto file are in the same bazel package
|
||||||
|
func TestGenerateProtoLibraryInSamePackage(t *testing.T) {
|
||||||
|
tc := Bp2buildTestCase{
|
||||||
|
Description: "cc_library depends on .proto files from multiple packages",
|
||||||
|
ModuleTypeUnderTest: "cc_library",
|
||||||
|
ModuleTypeUnderTestFactory: cc.LibraryFactory,
|
||||||
|
Blueprint: `
|
||||||
|
cc_library_static {
|
||||||
|
name: "foo",
|
||||||
|
srcs: [
|
||||||
|
"foo.proto",
|
||||||
|
"bar/bar.proto", // Different package because there is a bar/Android.bp
|
||||||
|
"baz/subbaz/baz.proto", // Different package because there is baz/subbaz/Android.bp
|
||||||
|
],
|
||||||
|
}
|
||||||
|
` + simpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"),
|
||||||
|
Filesystem: map[string]string{
|
||||||
|
"bar/Android.bp": "",
|
||||||
|
"baz/subbaz/Android.bp": "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will run the test 3 times and check in the root, bar and baz/subbaz directories
|
||||||
|
// Root dir
|
||||||
|
tc.ExpectedBazelTargets = []string{
|
||||||
|
MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
|
||||||
|
"local_includes": `["."]`,
|
||||||
|
"deps": `[":libprotobuf-cpp-lite"]`,
|
||||||
|
"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
|
||||||
|
}),
|
||||||
|
MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
|
||||||
|
"srcs": `["foo.proto"]`,
|
||||||
|
}),
|
||||||
|
MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
|
||||||
|
"deps": `[
|
||||||
|
":foo_proto",
|
||||||
|
"//bar:foo_proto",
|
||||||
|
"//baz/subbaz:foo_proto",
|
||||||
|
]`,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
runCcLibraryTestCase(t, tc)
|
||||||
|
|
||||||
|
// bar dir
|
||||||
|
tc.Dir = "bar"
|
||||||
|
tc.ExpectedBazelTargets = []string{
|
||||||
|
MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
|
||||||
|
"srcs": `["//bar:bar.proto"]`,
|
||||||
|
"import_prefix": `"bar"`,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
runCcLibraryTestCase(t, tc)
|
||||||
|
|
||||||
|
// baz/subbaz dir
|
||||||
|
tc.Dir = "baz/subbaz"
|
||||||
|
tc.ExpectedBazelTargets = []string{
|
||||||
|
MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
|
||||||
|
"srcs": `["//baz/subbaz:baz.proto"]`,
|
||||||
|
"import_prefix": `"baz/subbaz"`,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
runCcLibraryTestCase(t, tc)
|
||||||
|
}
|
||||||
|
@@ -73,7 +73,6 @@ func (m *PythonLibraryModule) makeArchVariantBaseAttributes(ctx android.TopDownM
|
|||||||
|
|
||||||
if !partitionedSrcs["proto"].IsEmpty() {
|
if !partitionedSrcs["proto"].IsEmpty() {
|
||||||
protoInfo, _ := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, partitionedSrcs["proto"])
|
protoInfo, _ := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, partitionedSrcs["proto"])
|
||||||
protoLabel := bazel.Label{Label: ":" + protoInfo.Name}
|
|
||||||
|
|
||||||
pyProtoLibraryName := m.Name() + "_py_proto"
|
pyProtoLibraryName := m.Name() + "_py_proto"
|
||||||
ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{
|
ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{
|
||||||
@@ -82,7 +81,7 @@ func (m *PythonLibraryModule) makeArchVariantBaseAttributes(ctx android.TopDownM
|
|||||||
}, android.CommonAttributes{
|
}, android.CommonAttributes{
|
||||||
Name: pyProtoLibraryName,
|
Name: pyProtoLibraryName,
|
||||||
}, &bazelPythonProtoLibraryAttributes{
|
}, &bazelPythonProtoLibraryAttributes{
|
||||||
Deps: bazel.MakeSingleLabelListAttribute(protoLabel),
|
Deps: bazel.MakeLabelListAttribute(protoInfo.Proto_libs),
|
||||||
})
|
})
|
||||||
|
|
||||||
attrs.Deps.Add(bazel.MakeLabelAttribute(":" + pyProtoLibraryName))
|
attrs.Deps.Add(bazel.MakeLabelAttribute(":" + pyProtoLibraryName))
|
||||||
|
Reference in New Issue
Block a user