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 15load("@perfetto_cfg//:perfetto_cfg.bzl", "PERFETTO_CONFIG") 16load("@perfetto//bazel:proto_gen.bzl", "proto_descriptor_gen", "proto_gen") 17 18# +----------------------------------------------------------------------------+ 19# | Base C++ rules. | 20# +----------------------------------------------------------------------------+ 21 22def default_cc_args(): 23 return { 24 "deps": PERFETTO_CONFIG.deps.build_config, 25 "copts": PERFETTO_CONFIG.default_copts + [ 26 "-Wno-pragma-system-header-outside-header", 27 ], 28 "includes": ["include"], 29 "linkopts": select({ 30 "@perfetto//bazel:os_linux": ["-ldl", "-lrt", "-lpthread"], 31 "@perfetto//bazel:os_osx": [], 32 "@perfetto//bazel:os_windows": ["ws2_32.lib"], 33 "//conditions:default": ["-ldl"], 34 }), 35 } 36 37def perfetto_build_config_cc_library(**kwargs): 38 if not _rule_override("cc_library", **kwargs): 39 native.cc_library(**kwargs) 40 41def perfetto_filegroup(**kwargs): 42 if not _rule_override("filegroup", **kwargs): 43 native.filegroup(**kwargs) 44 45def perfetto_genrule(**kwargs): 46 if not _rule_override("genrule", **kwargs): 47 native.genrule(**kwargs) 48 49def perfetto_cc_library(**kwargs): 50 args = _merge_dicts(default_cc_args(), kwargs) 51 if not _rule_override("cc_library", **args): 52 native.cc_library(**args) 53 54def perfetto_cc_binary(**kwargs): 55 args = _merge_dicts(default_cc_args(), kwargs) 56 if not _rule_override("cc_binary", **args): 57 native.cc_binary(**args) 58 59def perfetto_py_binary(**kwargs): 60 if not _rule_override("py_binary", **kwargs): 61 native.py_binary(**kwargs) 62 63def perfetto_py_library(**kwargs): 64 if not _rule_override("py_library", **kwargs): 65 native.py_library(**kwargs) 66 67# +----------------------------------------------------------------------------+ 68# | Proto-related rules | 69# +----------------------------------------------------------------------------+ 70 71def perfetto_proto_library(**kwargs): 72 if not _rule_override("proto_library", **kwargs): 73 native.proto_library(**kwargs) 74 75def perfetto_cc_proto_library(**kwargs): 76 if not _rule_override("cc_proto_library", **kwargs): 77 native.cc_proto_library(**kwargs) 78 79def perfetto_java_proto_library(**kwargs): 80 if not _rule_override("java_proto_library", **kwargs): 81 native.java_proto_library(**kwargs) 82 83def perfetto_java_lite_proto_library(**kwargs): 84 if not _rule_override("java_lite_proto_library", **kwargs): 85 native.java_lite_proto_library(**kwargs) 86 87# Unlike the other rules, this is an noop by default because Bazel does not 88# support Go proto libraries. 89def perfetto_go_proto_library(**kwargs): 90 _rule_override("go_proto_library", **kwargs) 91 92# Unlike the other rules, this is an noop by default because Bazel does not 93# support Python proto libraries. 94def perfetto_py_proto_library(**kwargs): 95 _rule_override("py_proto_library", **kwargs) 96 97# Unlike the other rules, this is an noop by default because Bazel does not 98# support Javascript/Typescript proto libraries. 99def perfetto_jspb_proto_library(**kwargs): 100 _rule_override("jspb_proto_library", **kwargs) 101 102# +----------------------------------------------------------------------------+ 103# | Misc rules. | 104# +----------------------------------------------------------------------------+ 105 106# Generates .pbzero.{cc,h} from .proto(s). We deliberately do NOT generate 107# conventional .pb.{cc,h} from here as protozero gen sources do not have any 108# dependency on libprotobuf. 109def perfetto_cc_protozero_library(name, deps, **kwargs): 110 if _rule_override( 111 "cc_protozero_library", 112 name = name, 113 deps = deps, 114 **kwargs 115 ): 116 return 117 118 # A perfetto_cc_protozero_library has two types of dependencies: 119 # 1. Exactly one dependency on a proto_library target. This defines the 120 # .proto sources for the target 121 # 2. Zero or more deps on other perfetto_cc_protozero_library targets. This 122 # to deal with the case of foo.proto including common.proto from another 123 # target. 124 _proto_deps = [d for d in deps if d.endswith("_protos")] 125 _cc_deps = [d for d in deps if d not in _proto_deps] 126 if len(_proto_deps) != 1: 127 fail("Too many proto deps for target %s" % name) 128 129 args = { 130 'name': name + "_src", 131 'deps': _proto_deps, 132 'suffix': "pbzero", 133 'plugin': PERFETTO_CONFIG.root + ":protozero_plugin", 134 'wrapper_namespace': "pbzero", 135 'protoc': PERFETTO_CONFIG.deps.protoc[0], 136 'root': PERFETTO_CONFIG.root, 137 } 138 if not _rule_override("proto_gen", **args): 139 proto_gen(**args) 140 141 perfetto_filegroup( 142 name = name + "_h", 143 srcs = [":" + name + "_src"], 144 output_group = "h", 145 ) 146 147 perfetto_cc_library( 148 name = name, 149 srcs = [":" + name + "_src"], 150 hdrs = [":" + name + "_h"], 151 deps = [PERFETTO_CONFIG.root + ":protozero"] + _cc_deps, 152 **kwargs 153 ) 154 155# Generates .ipc.{cc,h} and .pb.{cc.h} from .proto(s). The IPC sources depend 156# on .pb.h so we need to generate also the standard protobuf sources here. 157def perfetto_cc_ipc_library(name, deps, **kwargs): 158 if _rule_override("cc_ipc_library", name = name, deps = deps, **kwargs): 159 return 160 161 # A perfetto_cc_ipc_library has two types of dependencies: 162 # 1. Exactly one dependency on a proto_library target. This defines the 163 # .proto sources for the target 164 # 2. Zero or more deps on other perfetto_cc_protocpp_library targets. This 165 # to deal with the case of foo.proto including common.proto from another 166 # target. 167 _proto_deps = [d for d in deps if d.endswith("_protos")] 168 _cc_deps = [d for d in deps if d not in _proto_deps] 169 if len(_proto_deps) != 1: 170 fail("Too many proto deps for target %s" % name) 171 172 # Generates .ipc.{cc,h}. 173 args = { 174 'name': name + "_src", 175 'deps': _proto_deps, 176 'suffix': "ipc", 177 'plugin': PERFETTO_CONFIG.root + ":ipc_plugin", 178 'wrapper_namespace': "gen", 179 'protoc': PERFETTO_CONFIG.deps.protoc[0], 180 'root': PERFETTO_CONFIG.root, 181 } 182 if not _rule_override("proto_gen", **args): 183 proto_gen(**args) 184 185 perfetto_filegroup( 186 name = name + "_h", 187 srcs = [":" + name + "_src"], 188 output_group = "h", 189 ) 190 191 perfetto_cc_library( 192 name = name, 193 srcs = [":" + name + "_src"], 194 hdrs = [":" + name + "_h"], 195 deps = [ 196 # Generated .ipc.{cc,h} depend on this and protozero. 197 PERFETTO_CONFIG.root + ":perfetto_ipc", 198 PERFETTO_CONFIG.root + ":protozero", 199 ] + _cc_deps, 200 **kwargs 201 ) 202 203# Generates .gen.{cc,h} from .proto(s). 204def perfetto_cc_protocpp_library(name, deps, **kwargs): 205 if _rule_override( 206 "cc_protocpp_library", 207 name = name, 208 deps = deps, 209 **kwargs 210 ): 211 return 212 213 # A perfetto_cc_protocpp_library has two types of dependencies: 214 # 1. Exactly one dependency on a proto_library target. This defines the 215 # .proto sources for the target 216 # 2. Zero or more deps on other perfetto_cc_protocpp_library targets. This 217 # to deal with the case of foo.proto including common.proto from another 218 # target. 219 _proto_deps = [d for d in deps if d.endswith("_protos")] 220 _cc_deps = [d for d in deps if d not in _proto_deps] 221 if len(_proto_deps) != 1: 222 fail("Too many proto deps for target %s" % name) 223 224 args = { 225 'name': name + "_gen", 226 'deps': _proto_deps, 227 'suffix': "gen", 228 'plugin': PERFETTO_CONFIG.root + ":cppgen_plugin", 229 'wrapper_namespace': "gen", 230 'protoc': PERFETTO_CONFIG.deps.protoc[0], 231 'root': PERFETTO_CONFIG.root, 232 } 233 if not _rule_override("proto_gen", **args): 234 proto_gen(**args) 235 236 perfetto_filegroup( 237 name = name + "_gen_h", 238 srcs = [":" + name + "_gen"], 239 output_group = "h", 240 ) 241 242 # The headers from the gen plugin have implicit dependencies 243 # on each other so will fail when compiled independently. Use 244 # textual_hdrs to indicate this to Bazel. 245 perfetto_cc_library( 246 name = name, 247 srcs = [":" + name + "_gen"], 248 textual_hdrs = [":" + name + "_gen_h"], 249 deps = [ 250 PERFETTO_CONFIG.root + ":protozero", 251 ] + _cc_deps, 252 **kwargs 253 ) 254 255def perfetto_proto_descriptor(name, deps, outs, **kwargs): 256 args = { 257 'name': name, 258 'deps': deps, 259 'outs': outs, 260 } 261 if not _rule_override("proto_descriptor_gen", **args): 262 proto_descriptor_gen(**args) 263 264# Generator .descriptor.h from protos 265def perfetto_cc_proto_descriptor(name, deps, outs, **kwargs): 266 cmd = [ 267 "$(location gen_cc_proto_descriptor_py)", 268 "--cpp_out=$@", 269 "--gen_dir=$(GENDIR)", 270 "$<" 271 ] 272 perfetto_genrule( 273 name = name + "_gen", 274 cmd = " ".join(cmd), 275 tools = [ 276 ":gen_cc_proto_descriptor_py", 277 ], 278 srcs = deps, 279 outs = outs, 280 ) 281 282 perfetto_cc_library( 283 name = name, 284 hdrs = [":" + name + "_gen"], 285 **kwargs 286 ) 287 288def perfetto_cc_amalgamated_sql(name, deps, outs, namespace, **kwargs): 289 if PERFETTO_CONFIG.root[:2] != "//": 290 fail("Expected PERFETTO_CONFIG.root to start with //") 291 292 genrule_tool = kwargs.pop("genrule_tool", ":gen_amalgamated_sql_py") 293 cmd = [ 294 "$(location " + genrule_tool + ")", 295 "--namespace", 296 namespace, 297 "--cpp-out=$@", 298 "$(SRCS)", 299 ] 300 301 root_dir = kwargs.pop("root_dir", None) 302 if root_dir: 303 cmd += [ 304 "--root-dir", 305 root_dir, 306 ] 307 308 perfetto_genrule( 309 name = name + "_gen", 310 cmd = " ".join(cmd), 311 tools = [ 312 genrule_tool, 313 ], 314 srcs = deps, 315 outs = outs, 316 ) 317 perfetto_cc_library( 318 name = name, 319 hdrs = [":" + name + "_gen"], 320 **kwargs 321 ) 322 323def perfetto_cc_tp_tables(name, srcs, outs, deps = [], **kwargs): 324 if PERFETTO_CONFIG.root[:2] != "//": 325 fail("Expected PERFETTO_CONFIG.root to start with //") 326 327 if PERFETTO_CONFIG.root == "//": 328 python_path = PERFETTO_CONFIG.root + "python" 329 else: 330 python_path = PERFETTO_CONFIG.root + "/python" 331 332 perfetto_py_library( 333 name = name + "_lib", 334 deps = [ 335 python_path + ":trace_processor_table_generator", 336 ], 337 srcs = srcs, 338 ) 339 340 perfetto_py_binary( 341 name = name + "_tool", 342 deps = [ 343 ":" + name + "_lib", 344 python_path + ":trace_processor_table_generator", 345 ] + [d + "_lib" for d in deps], 346 srcs = [ 347 "tools/gen_tp_table_headers.py", 348 ], 349 main = "tools/gen_tp_table_headers.py", 350 python_version = "PY3", 351 ) 352 353 cmd = ["$(location " + name + "_tool)"] 354 cmd += ["--gen-dir", "$(RULEDIR)"] 355 cmd += ["--inputs", "$(SRCS)"] 356 if PERFETTO_CONFIG.root != "//": 357 cmd += ["--import-prefix", PERFETTO_CONFIG.root[2:]] 358 cmd += ["--relative-input-dir", PERFETTO_CONFIG.root[2:]] 359 360 perfetto_genrule( 361 name = name + "_gen", 362 cmd = " ".join(cmd), 363 tools = [ 364 ":" + name + "_tool", 365 ], 366 srcs = srcs, 367 outs = outs, 368 ) 369 370 perfetto_filegroup( 371 name = name, 372 srcs = [":" + name + "_gen"], 373 **kwargs, 374 ) 375 376# +----------------------------------------------------------------------------+ 377# | Misc utility functions | 378# +----------------------------------------------------------------------------+ 379 380def _rule_override(rule_name, **kwargs): 381 overrides = getattr(PERFETTO_CONFIG, "rule_overrides", struct()) 382 overridden_rule = getattr(overrides, rule_name, None) 383 if overridden_rule: 384 overridden_rule(**kwargs) 385 return True 386 return False 387 388def _merge_dicts(*args): 389 res = {} 390 for arg in args: 391 for k, v in arg.items(): 392 if type(v) == "string" or type(v) == "bool": 393 res[k] = v 394 elif type(v) == "list" or type(v) == "select": 395 res[k] = res.get(k, []) + v 396 else: 397 fail("key type not supported: " + type(v)) 398 return res 399