xref: /aosp_15_r20/external/perfetto/bazel/rules.bzl (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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