1# Copyright (C) 2019 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15# This file defines the proto_gen() rule that is used for generating protos 16# with custom plugins (ipc and protozero). 17 18def _proto_gen_impl(ctx): 19 proto_src = [ 20 f 21 for dep in ctx.attr.deps 22 for f in dep[ProtoInfo].direct_sources 23 ] 24 includes = [ 25 f 26 for dep in ctx.attr.deps 27 for f in dep[ProtoInfo].transitive_imports.to_list() 28 ] 29 30 proto_path = "." 31 32 out_dir = str(ctx.genfiles_dir.path) 33 strip_base_path = "" 34 if ctx.attr.root != "//": 35 # This path is hit in Google internal builds, where root is typically 36 # //third_party/perfetto. 37 proto_path = "." 38 39 # The below will likely be //third_party/perfetto/ but may also be any 40 # subdir under //third_party/perfetto. 41 last_slash_idx = ctx.build_file_path.rfind("/") 42 strip_base_path = ctx.build_file_path[:last_slash_idx + 1] 43 elif ctx.label.workspace_root: 44 # This path is hit when proto targets are built as @perfetto//:xxx 45 # instead of //:xxx. This happens in embedder builds. In this case, 46 # workspace_root == "external/perfetto" and we need to rebase the paths 47 # passed to protoc. 48 proto_path = ctx.label.workspace_root 49 out_dir += "/" + ctx.label.workspace_root 50 strip_base_path = ctx.label.workspace_root + "/" 51 52 out_files = [] 53 suffix = ctx.attr.suffix 54 for src in proto_src: 55 base_path = src.path[:-len(".proto")] 56 if base_path.startswith(strip_base_path): 57 base_path = base_path[len(strip_base_path):] 58 out_files += [ctx.actions.declare_file(base_path + ".%s.h" % suffix)] 59 out_files += [ctx.actions.declare_file(base_path + ".%s.cc" % suffix)] 60 61 arguments = [ 62 "--proto_path=" + proto_path, 63 ] 64 plugin_deps = [] 65 if ctx.attr.plugin: 66 wrap_arg = ctx.attr.wrapper_namespace 67 arguments += [ 68 "--plugin=protoc-gen-plugin=" + ctx.executable.plugin.path, 69 "--plugin_out=wrapper_namespace=" + wrap_arg + ":" + out_dir, 70 ] 71 plugin_deps += [ctx.executable.plugin] 72 else: 73 arguments += [ 74 "--cpp_out=lite=true:" + out_dir, 75 ] 76 77 arguments += [src.path for src in proto_src] 78 ctx.actions.run( 79 inputs = proto_src + includes + plugin_deps, 80 tools = plugin_deps, 81 outputs = out_files, 82 executable = ctx.executable.protoc, 83 arguments = arguments, 84 ) 85 return [ 86 DefaultInfo(files = depset(out_files)), 87 OutputGroupInfo( 88 cc = depset([f for f in out_files if f.path.endswith(".cc")]), 89 h = depset([f for f in out_files if f.path.endswith(".h")]), 90 ), 91 ] 92 93proto_gen = rule( 94 attrs = { 95 "deps": attr.label_list( 96 mandatory = True, 97 allow_empty = False, 98 providers = [ProtoInfo], 99 ), 100 "plugin": attr.label( 101 executable = True, 102 mandatory = False, 103 cfg = "host", 104 ), 105 "wrapper_namespace": attr.string( 106 mandatory = False, 107 default = "" 108 ), 109 "suffix": attr.string( 110 mandatory = True, 111 ), 112 "protoc": attr.label( 113 executable = True, 114 cfg = "host", 115 ), 116 "root": attr.string( 117 mandatory = False, 118 default = "//", 119 ), 120 }, 121 output_to_genfiles = True, 122 implementation = _proto_gen_impl, 123) 124