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 proto_paths = [ 30 f 31 for dep in ctx.attr.deps 32 for f in dep[ProtoInfo].transitive_proto_path.to_list() 33 ] 34 35 proto_path = "." 36 37 out_dir = ctx.bin_dir.path 38 strip_base_path = "" 39 if ctx.attr.root != "//": 40 # This path is hit in Google internal builds, where root is typically 41 # //third_party/perfetto. 42 proto_path = "." 43 44 # The below will likely be //third_party/perfetto/ but may also be any 45 # subdir under //third_party/perfetto. 46 strip_base_path = ctx.label.package + "/" 47 elif ctx.label.workspace_root: 48 # This path is hit when proto targets are built as @perfetto//:xxx 49 # instead of //:xxx. This happens in embedder builds. 50 proto_path = ctx.label.workspace_root 51 52 # We could be using the sibling repository layout, in which case we do nothing. 53 if not ctx.label.workspace_root.startswith("../"): 54 # workspace_root == "external/perfetto" and we need to rebase the paths 55 # passed to protoc. 56 out_dir += "/" + ctx.label.workspace_root 57 strip_base_path = ctx.label.workspace_root + "/" 58 59 60 out_files = [] 61 suffix = ctx.attr.suffix 62 for src in proto_src: 63 base_path = src.path[:-len(".proto")] 64 if base_path.startswith(strip_base_path): 65 base_path = base_path[len(strip_base_path):] 66 out_files += [ctx.actions.declare_file(base_path + ".%s.h" % suffix)] 67 out_files += [ctx.actions.declare_file(base_path + ".%s.cc" % suffix)] 68 69 arguments = [ 70 "--proto_path=" + proto_path 71 for proto_path in proto_paths 72 ] 73 74 plugin_deps = [] 75 if ctx.attr.plugin: 76 wrap_arg = ctx.attr.wrapper_namespace 77 arguments += [ 78 "--plugin=protoc-gen-plugin=" + ctx.executable.plugin.path, 79 "--plugin_out=wrapper_namespace=" + wrap_arg + ":" + out_dir, 80 ] 81 plugin_deps += [ctx.executable.plugin] 82 else: 83 arguments += [ 84 "--cpp_out=lite=true:" + out_dir, 85 ] 86 87 arguments += [src.path for src in proto_src] 88 ctx.actions.run( 89 inputs = proto_src + includes + plugin_deps, 90 tools = plugin_deps, 91 outputs = out_files, 92 executable = ctx.executable.protoc, 93 arguments = arguments, 94 ) 95 cc_files = depset([f for f in out_files if f.path.endswith(".cc")]) 96 h_files = depset([f for f in out_files if f.path.endswith(".h")]) 97 return [ 98 DefaultInfo(files = cc_files), 99 OutputGroupInfo( 100 cc = cc_files, 101 h = h_files, 102 ), 103 ] 104 105 106proto_gen = rule( 107 attrs = { 108 "deps": attr.label_list( 109 mandatory = True, 110 allow_empty = False, 111 providers = [ProtoInfo], 112 ), 113 "plugin": attr.label( 114 executable = True, 115 mandatory = False, 116 cfg = "host", 117 ), 118 "wrapper_namespace": attr.string( 119 mandatory = False, 120 default = "" 121 ), 122 "suffix": attr.string( 123 mandatory = True, 124 ), 125 "protoc": attr.label( 126 executable = True, 127 cfg = "host", 128 ), 129 "root": attr.string( 130 mandatory = False, 131 default = "//", 132 ), 133 }, 134 implementation = _proto_gen_impl, 135) 136 137 138def _proto_descriptor_gen_impl(ctx): 139 descriptors = [ 140 f 141 for dep in ctx.attr.deps 142 for f in dep[ProtoInfo].transitive_descriptor_sets.to_list() 143 ] 144 ctx.actions.run_shell( 145 inputs=descriptors, 146 outputs=ctx.outputs.outs, 147 command='cat %s > %s' % ( 148 ' '.join([f.path for f in descriptors]), ctx.outputs.outs[0].path) 149 ) 150 151 152proto_descriptor_gen = rule( 153 implementation=_proto_descriptor_gen_impl, 154 attrs = { 155 "deps": attr.label_list( 156 mandatory = True, 157 allow_empty = False, 158 providers = [ProtoInfo], 159 ), 160 "outs": attr.output_list(mandatory=True), 161 } 162) 163