| // Copyright 2016 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 cc |
| |
| import ( |
| "github.com/google/blueprint/pathtools" |
| "github.com/google/blueprint/proptools" |
| |
| "android/soong/android" |
| "android/soong/bazel" |
| ) |
| |
| const ( |
| protoTypeDefault = "lite" |
| ) |
| |
| // genProto creates a rule to convert a .proto file to generated .pb.cc and .pb.h files and returns |
| // the paths to the generated files. |
| func genProto(ctx android.ModuleContext, protoFile android.Path, flags builderFlags) (cc, header android.WritablePath) { |
| var ccFile, headerFile android.ModuleGenPath |
| |
| srcSuffix := ".cc" |
| if flags.protoC { |
| srcSuffix = ".c" |
| } |
| |
| if flags.proto.CanonicalPathFromRoot { |
| ccFile = android.GenPathWithExt(ctx, "proto", protoFile, "pb"+srcSuffix) |
| headerFile = android.GenPathWithExt(ctx, "proto", protoFile, "pb.h") |
| } else { |
| rel := protoFile.Rel() |
| ccFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, "pb"+srcSuffix)) |
| headerFile = android.PathForModuleGen(ctx, "proto", pathtools.ReplaceExtension(rel, "pb.h")) |
| } |
| |
| protoDeps := flags.proto.Deps |
| if flags.protoOptionsFile { |
| optionsFile := pathtools.ReplaceExtension(protoFile.String(), "options") |
| optionsPath := android.PathForSource(ctx, optionsFile) |
| protoDeps = append(android.Paths{optionsPath}, protoDeps...) |
| } |
| |
| outDir := flags.proto.Dir |
| depFile := ccFile.ReplaceExtension(ctx, "d") |
| outputs := android.WritablePaths{ccFile, headerFile} |
| |
| rule := android.NewRuleBuilder(pctx, ctx) |
| |
| android.ProtoRule(rule, protoFile, flags.proto, protoDeps, outDir, depFile, outputs) |
| |
| rule.Build("protoc_"+protoFile.Rel(), "protoc "+protoFile.Rel()) |
| |
| return ccFile, headerFile |
| } |
| |
| func protoDeps(ctx DepsContext, deps Deps, p *android.ProtoProperties, static bool) Deps { |
| var lib string |
| |
| if String(p.Proto.Plugin) == "" { |
| switch proptools.StringDefault(p.Proto.Type, protoTypeDefault) { |
| case "full": |
| if ctx.useSdk() { |
| lib = "libprotobuf-cpp-full-ndk" |
| static = true |
| } else { |
| lib = "libprotobuf-cpp-full" |
| } |
| case "lite": |
| if ctx.useSdk() { |
| lib = "libprotobuf-cpp-lite-ndk" |
| static = true |
| } else { |
| lib = "libprotobuf-cpp-lite" |
| } |
| case "nanopb-c": |
| lib = "libprotobuf-c-nano" |
| static = true |
| case "nanopb-c-enable_malloc": |
| lib = "libprotobuf-c-nano-enable_malloc" |
| static = true |
| case "nanopb-c-16bit": |
| lib = "libprotobuf-c-nano-16bit" |
| static = true |
| case "nanopb-c-enable_malloc-16bit": |
| lib = "libprotobuf-c-nano-enable_malloc-16bit" |
| static = true |
| case "nanopb-c-32bit": |
| lib = "libprotobuf-c-nano-32bit" |
| static = true |
| case "nanopb-c-enable_malloc-32bit": |
| lib = "libprotobuf-c-nano-enable_malloc-32bit" |
| static = true |
| default: |
| ctx.PropertyErrorf("proto.type", "unknown proto type %q", |
| String(p.Proto.Type)) |
| } |
| |
| if static { |
| deps.StaticLibs = append(deps.StaticLibs, lib) |
| deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, lib) |
| } else { |
| deps.SharedLibs = append(deps.SharedLibs, lib) |
| deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, lib) |
| } |
| } |
| |
| return deps |
| } |
| |
| func protoFlags(ctx ModuleContext, flags Flags, p *android.ProtoProperties) Flags { |
| flags.Local.CFlags = append(flags.Local.CFlags, "-DGOOGLE_PROTOBUF_NO_RTTI") |
| |
| flags.proto = android.GetProtoFlags(ctx, p) |
| if flags.proto.CanonicalPathFromRoot { |
| flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-I"+flags.proto.SubDir.String()) |
| } |
| flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-I"+flags.proto.Dir.String()) |
| |
| if String(p.Proto.Plugin) == "" { |
| var plugin string |
| |
| switch String(p.Proto.Type) { |
| case "nanopb-c", "nanopb-c-enable_malloc", "nanopb-c-16bit", "nanopb-c-enable_malloc-16bit", "nanopb-c-32bit", "nanopb-c-enable_malloc-32bit": |
| flags.protoC = true |
| flags.protoOptionsFile = true |
| flags.proto.OutTypeFlag = "--nanopb_out" |
| // Disable nanopb timestamps to support remote caching. |
| flags.proto.OutParams = append(flags.proto.OutParams, "-T") |
| plugin = "protoc-gen-nanopb" |
| case "full": |
| flags.proto.OutTypeFlag = "--cpp_out" |
| case "lite": |
| flags.proto.OutTypeFlag = "--cpp_out" |
| flags.proto.OutParams = append(flags.proto.OutParams, "lite") |
| case "": |
| // TODO(b/119714316): this should be equivalent to "lite" in |
| // order to match protoDeps, but some modules are depending on |
| // this behavior |
| flags.proto.OutTypeFlag = "--cpp_out" |
| default: |
| ctx.PropertyErrorf("proto.type", "unknown proto type %q", |
| String(p.Proto.Type)) |
| } |
| |
| if plugin != "" { |
| path := ctx.Config().HostToolPath(ctx, plugin) |
| flags.proto.Deps = append(flags.proto.Deps, path) |
| flags.proto.Flags = append(flags.proto.Flags, "--plugin="+path.String()) |
| } |
| } |
| |
| return flags |
| } |
| |
| type protoAttributes struct { |
| Deps bazel.LabelListAttribute |
| |
| // A list of proto_library targets that that the proto_library in `deps` depends on |
| // This list is overestimation. |
| // Overestimation is necessary since Soong includes other protos via proto.include_dirs and not |
| // a specific .proto file module explicitly. |
| Transitive_deps bazel.LabelListAttribute |
| |
| // A list of cc_library_* targets that the generated cpp code depends on |
| Cc_deps bazel.LabelListAttribute |
| |
| Min_sdk_version *string |
| } |
| |
| type bp2buildProtoDeps struct { |
| wholeStaticLib *bazel.LabelAttribute |
| implementationWholeStaticLib *bazel.LabelAttribute |
| protoDep *bazel.LabelAttribute |
| } |
| |
| func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute, la linkerAttributes) bp2buildProtoDeps { |
| var ret bp2buildProtoDeps |
| |
| protoInfo, ok := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, protoSrcs) |
| if !ok || protoInfo.Proto_libs.IsEmpty() { |
| return ret |
| } |
| |
| var depName string |
| typ := proptools.StringDefault(protoInfo.Type, protoTypeDefault) |
| var rule_class string |
| suffix := "_cc_proto" |
| switch typ { |
| case "lite": |
| suffix += "_lite" |
| rule_class = "cc_lite_proto_library" |
| depName = "libprotobuf-cpp-lite" |
| case "full": |
| rule_class = "cc_proto_library" |
| depName = "libprotobuf-cpp-full" |
| default: |
| ctx.PropertyErrorf("proto.type", "cannot handle conversion at this time: %q", typ) |
| } |
| |
| dep := android.BazelLabelForModuleDepSingle(ctx, depName) |
| ret.protoDep = &bazel.LabelAttribute{Value: &dep} |
| |
| var protoAttrs protoAttributes |
| protoAttrs.Deps.SetValue(protoInfo.Proto_libs) |
| protoAttrs.Transitive_deps.SetValue(protoInfo.Transitive_proto_libs) |
| |
| // Add the implementation deps of the top-level cc_library_static |
| // This is necessary to compile the internal root of cc_proto_library. |
| // Without this, clang might not be able to find .h files that the generated cpp files depends on |
| protoAttrs.Cc_deps = *la.implementationDeps.Clone() |
| protoAttrs.Cc_deps.Append(la.implementationDynamicDeps) |
| protoAttrs.Cc_deps.Append(la.implementationWholeArchiveDeps) |
| protoAttrs.Cc_deps.Append(la.wholeArchiveDeps) |
| // Subtract myself to prevent possible circular dep |
| protoAttrs.Cc_deps = bazel.SubtractBazelLabelListAttribute( |
| protoAttrs.Cc_deps, |
| bazel.MakeLabelListAttribute( |
| bazel.MakeLabelList([]bazel.Label{ |
| bazel.Label{Label: ":" + m.Name() + suffix}, |
| }), |
| ), |
| ) |
| // Subtract the protobuf libraries since cc_proto_library implicitly adds them |
| protoAttrs.Cc_deps = bazel.SubtractBazelLabelListAttribute( |
| protoAttrs.Cc_deps, |
| bazel.MakeLabelListAttribute( |
| bazel.MakeLabelList([]bazel.Label{ |
| bazel.Label{Label: "//external/protobuf:libprotobuf-cpp-full", OriginalModuleName: "libprotobuf-cpp-full"}, |
| bazel.Label{Label: "//external/protobuf:libprotobuf-cpp-lite", OriginalModuleName: "libprotobuf-cpp-lite"}, |
| }), |
| ), |
| ) |
| |
| protoAttrs.Min_sdk_version = m.Properties.Min_sdk_version |
| |
| name := m.Name() + suffix |
| tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m) |
| ctx.CreateBazelTargetModule( |
| bazel.BazelTargetModuleProperties{ |
| Rule_class: rule_class, |
| Bzl_load_location: "//build/bazel/rules/cc:cc_proto.bzl", |
| }, |
| android.CommonAttributes{Name: name, Tags: tags}, |
| &protoAttrs) |
| |
| var privateHdrs bool |
| if lib, ok := m.linker.(*libraryDecorator); ok { |
| privateHdrs = !proptools.Bool(lib.Properties.Proto.Export_proto_headers) |
| } |
| |
| labelAttr := &bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + name}} |
| if privateHdrs { |
| ret.implementationWholeStaticLib = labelAttr |
| } else { |
| ret.wholeStaticLib = labelAttr |
| } |
| |
| return ret |
| } |