7dc6bcbd58
Protos in another directory were using import prefix, which was prepending the repository-relative path with the value, instead, we want to strip the prefix of the directory of the module the protos were used in such that they can be referenced at the appropriate relative path. Reference on import_prefix: https://bazel.build/reference/be/protocol-buffer#proto_library.import_prefix Test: b build //packages/modules/adb:libfastdeploy_host Change-Id: If050b0f5fc5103bd9cc5a99703bd604325aa4204
307 lines
10 KiB
Go
307 lines
10 KiB
Go
// Copyright 2017 Google Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package android
|
|
|
|
import (
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"android/soong/bazel"
|
|
|
|
"github.com/google/blueprint"
|
|
"github.com/google/blueprint/proptools"
|
|
)
|
|
|
|
const (
|
|
canonicalPathFromRootDefault = true
|
|
)
|
|
|
|
// TODO(ccross): protos are often used to communicate between multiple modules. If the only
|
|
// way to convert a proto to source is to reference it as a source file, and external modules cannot
|
|
// reference source files in other modules, then every module that owns a proto file will need to
|
|
// export a library for every type of external user (lite vs. full, c vs. c++ vs. java). It would
|
|
// be better to support a proto module type that exported a proto file along with some include dirs,
|
|
// and then external modules could depend on the proto module but use their own settings to
|
|
// generate the source.
|
|
|
|
type ProtoFlags struct {
|
|
Flags []string
|
|
CanonicalPathFromRoot bool
|
|
Dir ModuleGenPath
|
|
SubDir ModuleGenPath
|
|
OutTypeFlag string
|
|
OutParams []string
|
|
Deps Paths
|
|
}
|
|
|
|
type protoDependencyTag struct {
|
|
blueprint.BaseDependencyTag
|
|
name string
|
|
}
|
|
|
|
var ProtoPluginDepTag = protoDependencyTag{name: "plugin"}
|
|
|
|
func ProtoDeps(ctx BottomUpMutatorContext, p *ProtoProperties) {
|
|
if String(p.Proto.Plugin) != "" && String(p.Proto.Type) != "" {
|
|
ctx.ModuleErrorf("only one of proto.type and proto.plugin can be specified.")
|
|
}
|
|
|
|
if plugin := String(p.Proto.Plugin); plugin != "" {
|
|
ctx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(),
|
|
ProtoPluginDepTag, "protoc-gen-"+plugin)
|
|
}
|
|
}
|
|
|
|
func GetProtoFlags(ctx ModuleContext, p *ProtoProperties) ProtoFlags {
|
|
var flags []string
|
|
var deps Paths
|
|
|
|
if len(p.Proto.Local_include_dirs) > 0 {
|
|
localProtoIncludeDirs := PathsForModuleSrc(ctx, p.Proto.Local_include_dirs)
|
|
flags = append(flags, JoinWithPrefix(localProtoIncludeDirs.Strings(), "-I"))
|
|
}
|
|
if len(p.Proto.Include_dirs) > 0 {
|
|
rootProtoIncludeDirs := PathsForSource(ctx, p.Proto.Include_dirs)
|
|
flags = append(flags, JoinWithPrefix(rootProtoIncludeDirs.Strings(), "-I"))
|
|
}
|
|
|
|
ctx.VisitDirectDepsWithTag(ProtoPluginDepTag, func(dep Module) {
|
|
if hostTool, ok := dep.(HostToolProvider); !ok || !hostTool.HostToolPath().Valid() {
|
|
ctx.PropertyErrorf("proto.plugin", "module %q is not a host tool provider",
|
|
ctx.OtherModuleName(dep))
|
|
} else {
|
|
plugin := String(p.Proto.Plugin)
|
|
deps = append(deps, hostTool.HostToolPath().Path())
|
|
flags = append(flags, "--plugin=protoc-gen-"+plugin+"="+hostTool.HostToolPath().String())
|
|
}
|
|
})
|
|
|
|
var protoOutFlag string
|
|
if plugin := String(p.Proto.Plugin); plugin != "" {
|
|
protoOutFlag = "--" + plugin + "_out"
|
|
}
|
|
|
|
return ProtoFlags{
|
|
Flags: flags,
|
|
Deps: deps,
|
|
OutTypeFlag: protoOutFlag,
|
|
CanonicalPathFromRoot: proptools.BoolDefault(p.Proto.Canonical_path_from_root, canonicalPathFromRootDefault),
|
|
Dir: PathForModuleGen(ctx, "proto"),
|
|
SubDir: PathForModuleGen(ctx, "proto", ctx.ModuleDir()),
|
|
}
|
|
}
|
|
|
|
type ProtoProperties struct {
|
|
Proto struct {
|
|
// Proto generator type. C++: full or lite. Java: micro, nano, stream, or lite.
|
|
Type *string `android:"arch_variant"`
|
|
|
|
// Proto plugin to use as the generator. Must be a cc_binary_host module.
|
|
Plugin *string `android:"arch_variant"`
|
|
|
|
// list of directories that will be added to the protoc include paths.
|
|
Include_dirs []string
|
|
|
|
// list of directories relative to the bp file that will
|
|
// be added to the protoc include paths.
|
|
Local_include_dirs []string
|
|
|
|
// whether to identify the proto files from the root of the
|
|
// source tree (the original method in Android, useful for
|
|
// android-specific protos), or relative from where they were
|
|
// specified (useful for external/third party protos).
|
|
//
|
|
// This defaults to true today, but is expected to default to
|
|
// false in the future.
|
|
Canonical_path_from_root *bool
|
|
} `android:"arch_variant"`
|
|
}
|
|
|
|
func ProtoRule(rule *RuleBuilder, protoFile Path, flags ProtoFlags, deps Paths,
|
|
outDir WritablePath, depFile WritablePath, outputs WritablePaths) {
|
|
|
|
var protoBase string
|
|
if flags.CanonicalPathFromRoot {
|
|
protoBase = "."
|
|
} else {
|
|
rel := protoFile.Rel()
|
|
protoBase = strings.TrimSuffix(protoFile.String(), rel)
|
|
}
|
|
|
|
rule.Command().
|
|
BuiltTool("aprotoc").
|
|
FlagWithArg(flags.OutTypeFlag+"=", strings.Join(flags.OutParams, ",")+":"+outDir.String()).
|
|
FlagWithDepFile("--dependency_out=", depFile).
|
|
FlagWithArg("-I ", protoBase).
|
|
Flags(flags.Flags).
|
|
Input(protoFile).
|
|
Implicits(deps).
|
|
ImplicitOutputs(outputs)
|
|
|
|
rule.Command().
|
|
BuiltTool("dep_fixer").Flag(depFile.String())
|
|
}
|
|
|
|
// Bp2buildProtoInfo contains information necessary to pass on to language specific conversion.
|
|
type Bp2buildProtoInfo struct {
|
|
Type *string
|
|
Proto_libs bazel.LabelList
|
|
}
|
|
|
|
type ProtoAttrs struct {
|
|
Srcs bazel.LabelListAttribute
|
|
Import_prefix *string
|
|
Strip_import_prefix *string
|
|
Deps bazel.LabelListAttribute
|
|
}
|
|
|
|
// For each package in the include_dirs property a proto_library target should
|
|
// be added to the BUILD file in that package and a mapping should be added here
|
|
var includeDirsToProtoDeps = map[string]string{
|
|
"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
|
|
// information necessary for language-specific handling.
|
|
func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs bazel.LabelListAttribute) (Bp2buildProtoInfo, bool) {
|
|
var info Bp2buildProtoInfo
|
|
if srcs.IsEmpty() {
|
|
return info, false
|
|
}
|
|
|
|
var protoLibraries bazel.LabelList
|
|
var directProtoSrcs bazel.LabelList
|
|
|
|
// For filegroups that should be converted to proto_library just collect the
|
|
// labels of converted proto_library targets.
|
|
for _, protoSrc := range srcs.Value.Includes {
|
|
src := protoSrc.OriginalModuleName
|
|
if fg, ok := ToFileGroupAsLibrary(ctx, src); ok &&
|
|
fg.ShouldConvertToProtoLibrary(ctx) {
|
|
protoLibraries.Add(&bazel.Label{
|
|
Label: fg.GetProtoLibraryLabel(ctx),
|
|
})
|
|
} else {
|
|
directProtoSrcs.Add(&protoSrc)
|
|
}
|
|
}
|
|
|
|
name := m.Name() + "_proto"
|
|
|
|
depsFromFilegroup := protoLibraries
|
|
var canonicalPathFromRoot bool
|
|
|
|
if len(directProtoSrcs.Includes) > 0 {
|
|
pkgToSrcs := partitionSrcsByPackage(ctx.ModuleDir(), directProtoSrcs)
|
|
for _, pkg := range SortedStringKeys(pkgToSrcs) {
|
|
srcs := pkgToSrcs[pkg]
|
|
attrs := ProtoAttrs{
|
|
Srcs: bazel.MakeLabelListAttribute(srcs),
|
|
}
|
|
attrs.Deps.Append(bazel.MakeLabelListAttribute(depsFromFilegroup))
|
|
|
|
for axis, configToProps := range m.GetArchVariantProperties(ctx, &ProtoProperties{}) {
|
|
for _, rawProps := range configToProps {
|
|
var props *ProtoProperties
|
|
var ok bool
|
|
if props, ok = rawProps.(*ProtoProperties); !ok {
|
|
ctx.ModuleErrorf("Could not cast ProtoProperties to expected type")
|
|
}
|
|
if axis == bazel.NoConfigAxis {
|
|
info.Type = props.Proto.Type
|
|
|
|
canonicalPathFromRoot = proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault)
|
|
if !canonicalPathFromRoot {
|
|
// an empty string indicates to strips the package path
|
|
path := ""
|
|
attrs.Strip_import_prefix = &path
|
|
}
|
|
|
|
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.")
|
|
}
|
|
}
|
|
}
|
|
|
|
tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module())
|
|
|
|
moduleDir := ctx.ModuleDir()
|
|
if !canonicalPathFromRoot {
|
|
// Since we are creating the proto_library in a subpackage, set the import_prefix relative to the current package
|
|
if rel, err := filepath.Rel(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 == moduleDir { // same package that the original module lives in
|
|
l = ":" + name
|
|
} else {
|
|
l = "//" + pkg + ":" + name
|
|
}
|
|
protoLibraries.Add(&bazel.Label{
|
|
Label: l,
|
|
})
|
|
}
|
|
}
|
|
|
|
info.Proto_libs = protoLibraries
|
|
|
|
return info, true
|
|
}
|