1# Copyright (C) 2017 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 15import("perfetto.gni") 16import("perfetto_component.gni") 17 18# This gni file defines rules for proto generation. There are various types of 19# proto targets that can be defined in our codebase: 20# "lite" targets: these use the standard libprotobuf library. They are used 21# mainly for tests and readback. 22# "zero" targets: these use the protozero library and its protoc plugin. They 23# are used pretty much everywhere. 24# "descriptor" targets: they are used to generate a proto-encoded reflection 25# descriptor that describes the schema of the proto using protobuf itself. 26# All these targets can be generated using the perfetto_proto_library rule. It 27# wraps the instantiation of several proto targets using a convenience template. 28# 29# For instance: 30# perfetto_proto_library("xxx_@TYPE@") { 31# proto_generators = [ "lite", "zero" ] # lite+zero+cpp is the default value. 32# sources = [ "one.proto", "two.proto" ] 33# deps = [ "dep:@TYPE@" ] 34# } 35# 36# Is the equivalent of: 37# proto_library("xxx_lite") { sources = [...], deps = [ "dep:lite"] } 38# protozero_library("xxx_zero") { sources = [...], deps = [ "dep:zero"] } 39 40# Load the protobuf's proto_library() definition. 41if (!defined(perfetto_protobuf_target_prefix)) { 42 if (perfetto_root_path == "//") { 43 perfetto_protobuf_target_prefix = "//buildtools" 44 } else { 45 perfetto_protobuf_target_prefix = "//third_party/protobuf" 46 } 47} 48if (!defined(perfetto_protobuf_gni)) { 49 if (perfetto_root_path == "//") { 50 perfetto_protobuf_gni = "//gn/standalone/proto_library.gni" 51 } else { 52 perfetto_protobuf_gni = "//third_party/protobuf/proto_library.gni" 53 } 54} 55if (!defined(perfetto_protobuf_src_dir)) { 56 if (perfetto_root_path == "//") { 57 perfetto_protobuf_src_dir = "//buildtools/protobuf/src" 58 } else { 59 perfetto_protobuf_src_dir = "//third_party/protobuf/src" 60 } 61} 62import(perfetto_protobuf_gni) 63 64# Equivalent to proto_library (generation of .h/.cc from .proto files) but 65# enables also generation using the protozero plugin. 66# The generated files will have the .pbzero.{cc,h} suffix, as opposed to the 67# .pb.{cc,h} of the official proto library. 68# DO NOT use this target directly, use perfetto_proto_library() below. 69template("protozero_library") { 70 proto_library(target_name) { 71 perfetto_root_path = invoker.perfetto_root_path 72 73 generate_cc = false 74 generate_python = false 75 generator_plugin_label = 76 perfetto_root_path + "src/protozero/protoc_plugin:protozero_plugin" 77 generator_plugin_suffix = ".pbzero" 78 if (build_with_chromium) { 79 component_build_force_source_set = true 80 } 81 82 if (defined(invoker.deps)) { 83 deps = invoker.deps 84 } else { 85 deps = [] 86 } 87 88 deps += [ perfetto_root_path + "src/protozero" ] 89 90 forward_variables_from(invoker, 91 [ 92 "defines", 93 "generator_plugin_options", 94 "include_dirs", 95 "proto_in_dir", 96 "proto_out_dir", 97 "sources", 98 "testonly", 99 "visibility", 100 "generate_descriptor", 101 "propagate_imports_configs", 102 "import_dirs", 103 ]) 104 } 105} 106 107# This template generates .gen.cc/h files from .proto files. The generated 108# sources are actual C++ classes that can be moved and copied around, very 109# similar to the libprotobuf generated ones API-wise, but use protozero under 110# the hoods, without any zero-copy benefit though. 111# They are mainly used for the perfetto IPC layer and tests. 112template("protozero_cpp_library") { 113 proto_library(target_name) { 114 perfetto_root_path = invoker.perfetto_root_path 115 116 generate_cc = false 117 generate_python = false 118 generator_plugin_label = 119 perfetto_root_path + "src/protozero/protoc_plugin:cppgen_plugin" 120 generator_plugin_suffix = ".gen" 121 if (build_with_chromium) { 122 component_build_force_source_set = true 123 } 124 125 deps = [ 126 "$perfetto_root_path/gn:default_deps", 127 "$perfetto_root_path/include/perfetto/base", 128 "$perfetto_root_path/src/protozero", 129 ] 130 131 if (defined(invoker.deps)) { 132 deps += invoker.deps 133 } 134 135 forward_variables_from(invoker, 136 [ 137 "defines", 138 "generator_plugin_options", 139 "include_dirs", 140 "proto_in_dir", 141 "proto_out_dir", 142 "sources", 143 "testonly", 144 "visibility", 145 "generate_descriptor", 146 "propagate_imports_configs", 147 "import_dirs", 148 ]) 149 } 150} 151 152# Generates .ipc.{h,cc} stubs for IPC services defined in .proto files. 153template("ipc_library") { 154 proto_library(target_name) { 155 perfetto_root_path = invoker.perfetto_root_path 156 generate_cc = false 157 generate_python = false 158 generator_plugin_label = 159 "$perfetto_root_path/src/ipc/protoc_plugin:ipc_plugin" 160 generator_plugin_suffix = ".ipc" 161 deps = [ "$perfetto_root_path/gn:default_deps" ] 162 if (perfetto_component_type == "static_library") { 163 deps += [ "$perfetto_root_path/src/ipc:perfetto_ipc" ] 164 } else { 165 deps += [ "$perfetto_root_path/src/ipc:common" ] 166 } 167 if (defined(invoker.deps)) { 168 deps += invoker.deps 169 } 170 forward_variables_from(invoker, 171 [ 172 "defines", 173 "extra_configs", 174 "include_dirs", 175 "proto_in_dir", 176 "proto_out_dir", 177 "generator_plugin_options", 178 "sources", 179 "testonly", 180 "visibility", 181 "propagate_imports_configs", 182 "import_dirs", 183 ]) 184 } 185} 186 187# The template used everywhere in the codebase. 188template("perfetto_proto_library") { 189 if (defined(invoker.proto_generators)) { 190 proto_generators = invoker.proto_generators 191 } else { 192 proto_generators = [ 193 "zero", 194 "lite", 195 "cpp", 196 "source_set", 197 ] 198 } 199 200 # proto imports and C++ #includes are relative to this path. 201 if (defined(invoker.proto_path)) { 202 proto_path = invoker.proto_path 203 } else { 204 proto_path = perfetto_root_path 205 } 206 207 if (defined(invoker.import_dirs)) { 208 import_dirs_ = invoker.import_dirs 209 } else { 210 import_dirs_ = [] 211 } 212 213 vars_to_forward = [ 214 "sources", 215 "visibility", 216 "testonly", 217 ] 218 expansion_token = "@TYPE@" 219 220 # gn:public_config propagates the gen dir as include directory. We 221 # disable the proto_library's public_config to avoid duplicate include 222 # directory command line flags (crbug.com/1043279, crbug.com/gn/142). 223 propagate_imports_configs_ = false 224 225 foreach(gen_type, proto_generators) { 226 target_name_ = string_replace(target_name, expansion_token, gen_type) 227 228 # Translate deps from xxx:@TYPE@ to xxx:lite/zero. 229 deps_ = [] 230 if (defined(invoker.deps)) { 231 foreach(dep, invoker.deps) { 232 deps_ += [ string_replace(dep, expansion_token, gen_type) ] 233 } 234 } 235 236 if (gen_type == "zero") { 237 protozero_library(target_name_) { 238 proto_in_dir = proto_path 239 proto_out_dir = proto_path 240 generator_plugin_options = "wrapper_namespace=pbzero" 241 deps = deps_ 242 propagate_imports_configs = propagate_imports_configs_ 243 import_dirs = import_dirs_ 244 forward_variables_from(invoker, vars_to_forward) 245 } 246 } else if (gen_type == "cpp") { 247 protozero_cpp_library(target_name_) { 248 proto_in_dir = proto_path 249 proto_out_dir = proto_path 250 generator_plugin_options = "wrapper_namespace=gen" 251 deps = deps_ 252 propagate_imports_configs = propagate_imports_configs_ 253 import_dirs = import_dirs_ 254 forward_variables_from(invoker, vars_to_forward) 255 } 256 } else if (gen_type == "ipc") { 257 cpp_target_name_ = string_replace(target_name, expansion_token, "cpp") 258 ipc_library(target_name_) { 259 proto_in_dir = proto_path 260 proto_out_dir = proto_path 261 generator_plugin_options = "wrapper_namespace=gen" 262 deps = deps_ + [ ":$cpp_target_name_" ] 263 propagate_imports_configs = propagate_imports_configs_ 264 import_dirs = import_dirs_ 265 forward_variables_from(invoker, vars_to_forward) 266 } 267 } else if (gen_type == "lite") { 268 proto_library(target_name_) { 269 proto_in_dir = proto_path 270 proto_out_dir = proto_path 271 generate_python = false 272 deps = deps_ 273 cc_generator_options = "lite=true:" 274 propagate_imports_configs = propagate_imports_configs_ 275 import_dirs = import_dirs_ 276 forward_variables_from(invoker, vars_to_forward) 277 } 278 } else if (gen_type == "descriptor") { 279 proto_library(target_name_) { 280 proto_in_dir = proto_path 281 proto_out_dir = proto_path 282 generate_python = false 283 generate_cc = false 284 generate_descriptor = 285 rebase_path(invoker.generate_descriptor, proto_path) 286 deps = deps_ 287 import_dirs = import_dirs_ 288 forward_variables_from(invoker, vars_to_forward) 289 } 290 291 # Not needed for descriptor proto_library target. 292 not_needed([ "propagate_imports_configs_" ]) 293 } else if (gen_type == "source_set") { 294 action(target_name_) { 295 out_path = "$target_gen_dir/" + target_name_ 296 rebased_out_path = 297 rebase_path(target_gen_dir, root_build_dir) + "/" + target_name_ 298 299 script = "$perfetto_root_path/tools/touch_file.py" 300 args = [ 301 "--output", 302 rebased_out_path, 303 ] 304 outputs = [ out_path ] 305 deps = deps_ 306 307 metadata = { 308 proto_library_sources = invoker.sources 309 import_dirs = import_dirs_ 310 } 311 forward_variables_from(invoker, vars_to_forward) 312 } 313 314 # Not needed for source_set proto_library target. 315 not_needed([ 316 "propagate_imports_configs_", 317 "proto_path", 318 ]) 319 } else { 320 assert(false, "Invalid 'proto_generators' value.") 321 } 322 } 323} 324