• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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//bazel:proto_gen.bzl", "proto_descriptor_gen", "proto_gen")
16load("@perfetto//bazel:run_ait_with_adb.bzl", "android_instrumentation_test")
17load("@perfetto_cfg//:perfetto_cfg.bzl", "PERFETTO_CONFIG")
18load("@rules_android//android:rules.bzl", "android_binary", "android_library")
19
20# +----------------------------------------------------------------------------+
21# | Base C++ rules.                                                            |
22# +----------------------------------------------------------------------------+
23
24def default_cc_args():
25    return {
26        "deps": PERFETTO_CONFIG.deps.build_config,
27        "copts": PERFETTO_CONFIG.default_copts + [
28            "-Wno-pragma-system-header-outside-header",
29        ],
30        "includes": ["include"],
31        "linkopts": select({
32            "@perfetto//bazel:os_linux": ["-ldl", "-lrt", "-lpthread"],
33            "@perfetto//bazel:os_osx": [],
34            "@perfetto//bazel:os_windows": ["ws2_32.lib"],
35            "//conditions:default": ["-ldl"],
36        }),
37    }
38
39def perfetto_build_config_cc_library(**kwargs):
40    if not _rule_override("cc_library", **kwargs):
41        native.cc_library(**kwargs)
42
43def perfetto_filegroup(**kwargs):
44    if not _rule_override("filegroup", **kwargs):
45        native.filegroup(**kwargs)
46
47def perfetto_genrule(**kwargs):
48    if not _rule_override("genrule", **kwargs):
49        native.genrule(**kwargs)
50
51def perfetto_cc_library(**kwargs):
52    args = _merge_dicts(default_cc_args(), kwargs)
53    if not _rule_override("cc_library", **args):
54        native.cc_library(**args)
55
56def perfetto_cc_binary(**kwargs):
57    args = _merge_dicts(default_cc_args(), kwargs)
58    if not _rule_override("cc_binary", **args):
59        native.cc_binary(**args)
60
61def perfetto_py_binary(**kwargs):
62    if not _rule_override("py_binary", **kwargs):
63        native.py_binary(**kwargs)
64
65def perfetto_py_library(**kwargs):
66    if not _rule_override("py_library", **kwargs):
67        native.py_library(**kwargs)
68
69# +----------------------------------------------------------------------------+
70# | Proto-related rules                                                        |
71# +----------------------------------------------------------------------------+
72
73def perfetto_proto_library(**kwargs):
74    if not _rule_override("proto_library", **kwargs):
75        native.proto_library(**kwargs)
76
77def perfetto_cc_proto_library(**kwargs):
78    if not _rule_override("cc_proto_library", **kwargs):
79        native.cc_proto_library(**kwargs)
80
81def perfetto_java_proto_library(**kwargs):
82    if not _rule_override("java_proto_library", **kwargs):
83        native.java_proto_library(**kwargs)
84
85def perfetto_java_lite_proto_library(**kwargs):
86    if not _rule_override("java_lite_proto_library", **kwargs):
87        native.java_lite_proto_library(**kwargs)
88
89# Unlike the other rules, this is an noop by default because Bazel does not
90# support Go proto libraries.
91def perfetto_go_proto_library(**kwargs):
92    _rule_override("go_proto_library", **kwargs)
93
94# Unlike the other rules, this is an noop by default because Bazel does not
95# support Python proto libraries.
96def perfetto_py_proto_library(**kwargs):
97    _rule_override("py_proto_library", **kwargs)
98
99# Unlike the other rules, this is an noop by default because Bazel does not
100# support Javascript/Typescript proto libraries.
101def perfetto_jspb_proto_library(**kwargs):
102    _rule_override("jspb_proto_library", **kwargs)
103
104# +----------------------------------------------------------------------------+
105# | Android-related rules                                                      |
106# +----------------------------------------------------------------------------+
107def perfetto_android_binary(**kwargs):
108    if not _rule_override("android_binary", **kwargs):
109        android_binary(**kwargs)
110
111def perfetto_android_library(**kwargs):
112    if not _rule_override("android_library", **kwargs):
113        android_library(**kwargs)
114
115def perfetto_android_jni_library(**kwargs):
116    if not _rule_override("android_jni_library", **kwargs):
117        _perfetto_android_jni_library(**kwargs)
118
119def _perfetto_android_jni_library(
120        name,
121        binary_name,
122        **input_cc_library_kwargs):
123    # By default 'android_binary' rule merges all native libraries into one,
124    # named '"lib%s.so" % android_binary_target_name'.
125    # This is unsuitable for us: we want our native library to have a
126    # predictable name to be able to load it from Java using
127    # 'System.loadLibrary'.
128    # To workaround this behaviour we wrap the 'cc_library'
129    # target into 'cc_binary' that gives a name to the resulting library.
130    # The same trick is done in 'android_jni_library' macro in google3.
131    # See https://yaqs.corp.google.com/eng/q/1025522191808069632.
132    #
133    # 'binary_name' argument should be of pattern 'lib%s.so',
134    # for this macro to be consistent with android_jni_library from google3.
135    if not binary_name:
136        fail("'binary_name' shouldn't be None")
137    if not (binary_name.startswith("lib") and binary_name.endswith(".so")):
138        fail("'binary_name' should sharts with 'lib' and ends with '.so'" +
139             ", got %s instead" % binary_name)
140    # We strip the name, since `native.cc_binary` adds prefix and suffix
141    # to the generated library name.
142    binary_target_name = binary_name.removeprefix("lib").removesuffix(".so")
143    input_cc_library_name = name + "_input"
144    # We add 'target_compatible_with = ' to all the cc_library targets to
145    # exclude them from being build when invoke `bazel build :all`,
146    # since these targets won't be able to compile anyway, see
147    # https://bazel.build/docs/android-ndk#cclibrary-android.
148    native.cc_library(
149        name = input_cc_library_name,
150        target_compatible_with = ["@platforms//os:android"],
151        **input_cc_library_kwargs
152    )
153    native.cc_binary(
154        name = binary_target_name,
155        linkshared = True,
156        deps = [input_cc_library_name],
157        target_compatible_with = ["@platforms//os:android"],
158    )
159    native.cc_library(
160        name = name,
161        srcs = [binary_target_name],
162        target_compatible_with = ["@platforms//os:android"],
163    )
164
165def perfetto_android_instrumentation_test(**kwargs):
166    if not _rule_override("android_instrumentation_test", **kwargs):
167        android_instrumentation_test(**kwargs)
168
169# +----------------------------------------------------------------------------+
170# | Misc rules.                                                                |
171# +----------------------------------------------------------------------------+
172
173# Generates .pbzero.{cc,h} from .proto(s). We deliberately do NOT generate
174# conventional .pb.{cc,h} from here as protozero gen sources do not have any
175# dependency on libprotobuf.
176def perfetto_cc_protozero_library(name, deps, **kwargs):
177    if _rule_override(
178        "cc_protozero_library",
179        name = name,
180        deps = deps,
181        **kwargs
182    ):
183        return
184
185    # A perfetto_cc_protozero_library has two types of dependencies:
186    # 1. Exactly one dependency on a proto_library target. This defines the
187    #    .proto sources for the target
188    # 2. Zero or more deps on other perfetto_cc_protozero_library targets. This
189    #    to deal with the case of foo.proto including common.proto from another
190    #    target.
191    _proto_deps = [d for d in deps if d.endswith("_protos")]
192    _cc_deps = [d for d in deps if d not in _proto_deps]
193    if len(_proto_deps) != 1:
194        fail("Too many proto deps for target %s" % name)
195
196    args = {
197        "name": name + "_src",
198        "deps": _proto_deps,
199        "suffix": "pbzero",
200        "plugin": PERFETTO_CONFIG.root + ":protozero_plugin",
201        "wrapper_namespace": "pbzero",
202        "protoc": PERFETTO_CONFIG.deps.protoc[0],
203        "root": PERFETTO_CONFIG.root,
204    }
205    if not _rule_override("proto_gen", **args):
206        proto_gen(**args)
207
208    perfetto_filegroup(
209        name = name + "_h",
210        srcs = [":" + name + "_src"],
211        output_group = "h",
212    )
213
214    perfetto_cc_library(
215        name = name,
216        srcs = [":" + name + "_src"],
217        hdrs = [":" + name + "_h"],
218        deps = [PERFETTO_CONFIG.root + ":protozero"] + _cc_deps,
219        **kwargs
220    )
221
222# Generates .ipc.{cc,h} and .pb.{cc.h} from .proto(s). The IPC sources depend
223# on .pb.h so we need to generate also the standard protobuf sources here.
224def perfetto_cc_ipc_library(name, deps, **kwargs):
225    if _rule_override("cc_ipc_library", name = name, deps = deps, **kwargs):
226        return
227
228    # A perfetto_cc_ipc_library has two types of dependencies:
229    # 1. Exactly one dependency on a proto_library target. This defines the
230    #    .proto sources for the target
231    # 2. Zero or more deps on other perfetto_cc_protocpp_library targets. This
232    #    to deal with the case of foo.proto including common.proto from another
233    #    target.
234    _proto_deps = [d for d in deps if d.endswith("_protos")]
235    _cc_deps = [d for d in deps if d not in _proto_deps]
236    if len(_proto_deps) != 1:
237        fail("Too many proto deps for target %s" % name)
238
239    # Generates .ipc.{cc,h}.
240    args = {
241        "name": name + "_src",
242        "deps": _proto_deps,
243        "suffix": "ipc",
244        "plugin": PERFETTO_CONFIG.root + ":ipc_plugin",
245        "wrapper_namespace": "gen",
246        "protoc": PERFETTO_CONFIG.deps.protoc[0],
247        "root": PERFETTO_CONFIG.root,
248    }
249    if not _rule_override("proto_gen", **args):
250        proto_gen(**args)
251
252    perfetto_filegroup(
253        name = name + "_h",
254        srcs = [":" + name + "_src"],
255        output_group = "h",
256    )
257
258    perfetto_cc_library(
259        name = name,
260        srcs = [":" + name + "_src"],
261        hdrs = [":" + name + "_h"],
262        deps = [
263            # Generated .ipc.{cc,h} depend on this and protozero.
264            PERFETTO_CONFIG.root + ":perfetto_ipc",
265            PERFETTO_CONFIG.root + ":protozero",
266        ] + _cc_deps,
267        **kwargs
268    )
269
270# Generates .gen.{cc,h} from .proto(s).
271def perfetto_cc_protocpp_library(name, deps, **kwargs):
272    if _rule_override(
273        "cc_protocpp_library",
274        name = name,
275        deps = deps,
276        **kwargs
277    ):
278        return
279
280    # A perfetto_cc_protocpp_library has two types of dependencies:
281    # 1. Exactly one dependency on a proto_library target. This defines the
282    #    .proto sources for the target
283    # 2. Zero or more deps on other perfetto_cc_protocpp_library targets. This
284    #    to deal with the case of foo.proto including common.proto from another
285    #    target.
286    _proto_deps = [d for d in deps if d.endswith("_protos")]
287    _cc_deps = [d for d in deps if d not in _proto_deps]
288    if len(_proto_deps) != 1:
289        fail("Too many proto deps for target %s" % name)
290
291    args = {
292        "name": name + "_gen",
293        "deps": _proto_deps,
294        "suffix": "gen",
295        "plugin": PERFETTO_CONFIG.root + ":cppgen_plugin",
296        "wrapper_namespace": "gen",
297        "protoc": PERFETTO_CONFIG.deps.protoc[0],
298        "root": PERFETTO_CONFIG.root,
299    }
300    if not _rule_override("proto_gen", **args):
301        proto_gen(**args)
302
303    perfetto_filegroup(
304        name = name + "_gen_h",
305        srcs = [":" + name + "_gen"],
306        output_group = "h",
307    )
308
309    # The headers from the gen plugin have implicit dependencies
310    # on each other so will fail when compiled independently. Use
311    # textual_hdrs to indicate this to Bazel.
312    perfetto_cc_library(
313        name = name,
314        srcs = [":" + name + "_gen"],
315        textual_hdrs = [":" + name + "_gen_h"],
316        deps = [
317            PERFETTO_CONFIG.root + ":protozero",
318        ] + _cc_deps,
319        **kwargs
320    )
321
322def perfetto_proto_descriptor(name, deps, outs, **kwargs):
323    args = {
324        "name": name,
325        "deps": deps,
326        "outs": outs,
327    }
328    if not _rule_override("proto_descriptor_gen", **args):
329        proto_descriptor_gen(**args)
330
331# Generator .descriptor.h from protos
332def perfetto_cc_proto_descriptor(name, deps, outs, **kwargs):
333    cmd = [
334        "$(location gen_cc_proto_descriptor_py)",
335        "--cpp_out=$@",
336        "--gen_dir=$(GENDIR)",
337        "$<",
338    ]
339    perfetto_genrule(
340        name = name + "_gen",
341        cmd = " ".join(cmd),
342        tools = [
343            ":gen_cc_proto_descriptor_py",
344        ],
345        srcs = deps,
346        outs = outs,
347    )
348
349    perfetto_cc_library(
350        name = name,
351        hdrs = [":" + name + "_gen"],
352        **kwargs
353    )
354
355def perfetto_cc_amalgamated_sql(name, deps, outs, namespace, **kwargs):
356    if PERFETTO_CONFIG.root[:2] != "//":
357        fail("Expected PERFETTO_CONFIG.root to start with //")
358
359    genrule_tool = kwargs.pop("genrule_tool", ":gen_amalgamated_sql_py")
360    cmd = [
361        "$(location " + genrule_tool + ")",
362        "--namespace",
363        namespace,
364        "--cpp-out=$@",
365        "$(SRCS)",
366    ]
367
368    root_dir = kwargs.pop("root_dir", None)
369    if root_dir:
370        cmd += [
371            "--root-dir",
372            root_dir,
373        ]
374
375    perfetto_genrule(
376        name = name + "_gen",
377        cmd = " ".join(cmd),
378        tools = [
379            genrule_tool,
380        ],
381        srcs = deps,
382        outs = outs,
383    )
384    perfetto_cc_library(
385        name = name,
386        hdrs = [":" + name + "_gen"],
387        **kwargs
388    )
389
390def perfetto_cc_tp_tables(name, srcs, outs, deps = [], **kwargs):
391    if PERFETTO_CONFIG.root[:2] != "//":
392        fail("Expected PERFETTO_CONFIG.root to start with //")
393
394    if PERFETTO_CONFIG.root == "//":
395        python_path = PERFETTO_CONFIG.root + "python"
396    else:
397        python_path = PERFETTO_CONFIG.root + "/python"
398
399    perfetto_py_library(
400        name = name + "_lib",
401        deps = [
402            python_path + ":trace_processor_table_generator",
403        ],
404        srcs = srcs,
405    )
406
407    perfetto_py_binary(
408        name = name + "_tool",
409        deps = [
410            ":" + name + "_lib",
411            python_path + ":trace_processor_table_generator",
412        ] + [d + "_lib" for d in deps],
413        srcs = [
414            "tools/gen_tp_table_headers.py",
415        ],
416        main = "tools/gen_tp_table_headers.py",
417        python_version = "PY3",
418    )
419
420    cmd = ["$(location " + name + "_tool)"]
421    cmd += ["--gen-dir", "$(RULEDIR)"]
422    cmd += ["--inputs", "$(SRCS)"]
423    if PERFETTO_CONFIG.root != "//":
424        cmd += ["--import-prefix", PERFETTO_CONFIG.root[2:]]
425        cmd += ["--relative-input-dir", PERFETTO_CONFIG.root[2:]]
426
427    perfetto_genrule(
428        name = name + "_gen",
429        cmd = " ".join(cmd),
430        tools = [
431            ":" + name + "_tool",
432        ],
433        srcs = srcs,
434        outs = outs,
435    )
436
437    perfetto_filegroup(
438        name = name,
439        srcs = [":" + name + "_gen"],
440        **kwargs
441    )
442
443# +----------------------------------------------------------------------------+
444# | Misc utility functions                                                     |
445# +----------------------------------------------------------------------------+
446
447def _rule_override(rule_name, **kwargs):
448    overrides = getattr(PERFETTO_CONFIG, "rule_overrides", struct())
449    overridden_rule = getattr(overrides, rule_name, None)
450    if overridden_rule:
451        overridden_rule(**kwargs)
452        return True
453    return False
454
455def _merge_dicts(*args):
456    res = {}
457    for arg in args:
458        for k, v in arg.items():
459            if type(v) == "string" or type(v) == "bool":
460                res[k] = v
461            elif type(v) == "list" or type(v) == "select":
462                res[k] = res.get(k, []) + v
463            else:
464                fail("key type not supported: " + type(v))
465    return res
466