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 cc_files = depset([f for f in out_files if f.path.endswith(".cc")]) 86 h_files = depset([f for f in out_files if f.path.endswith(".h")]) 87 return [ 88 DefaultInfo(files = cc_files), 89 OutputGroupInfo( 90 cc = cc_files, 91 h = h_files, 92 ), 93 ] 94 95 96proto_gen = rule( 97 attrs = { 98 "deps": attr.label_list( 99 mandatory = True, 100 allow_empty = False, 101 providers = [ProtoInfo], 102 ), 103 "plugin": attr.label( 104 executable = True, 105 mandatory = False, 106 cfg = "host", 107 ), 108 "wrapper_namespace": attr.string( 109 mandatory = False, 110 default = "" 111 ), 112 "suffix": attr.string( 113 mandatory = True, 114 ), 115 "protoc": attr.label( 116 executable = True, 117 cfg = "host", 118 ), 119 "root": attr.string( 120 mandatory = False, 121 default = "//", 122 ), 123 }, 124 output_to_genfiles = True, 125 implementation = _proto_gen_impl, 126) 127 128 129def _proto_descriptor_gen_impl(ctx): 130 descriptors = [ 131 f 132 for dep in ctx.attr.deps 133 for f in dep[ProtoInfo].transitive_descriptor_sets.to_list() 134 ] 135 ctx.actions.run_shell( 136 inputs=descriptors, 137 outputs=ctx.outputs.outs, 138 command='cat %s > %s' % ( 139 ' '.join([f.path for f in descriptors]), ctx.outputs.outs[0].path) 140 ) 141 142 143proto_descriptor_gen = rule( 144 implementation=_proto_descriptor_gen_impl, 145 attrs = { 146 "deps": attr.label_list( 147 mandatory = True, 148 allow_empty = False, 149 providers = [ProtoInfo], 150 ), 151 "outs": attr.output_list(mandatory=True), 152 } 153) 154