blob: e847e1759e8152b2b368a8f5baa2e58e9261fc54 [file] [log] [blame]
Primiano Tucci34bc5592021-02-19 17:53:36 +01001#!/usr/bin/env python3
Lalit Maganti279ecde2019-04-01 16:57:12 +01002# Copyright (C) 2018 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16# This tool translates a collection of BUILD.gn files into a mostly equivalent
17# BUILD file for the Bazel build system. The input to the tool is a
18# JSON description of the GN build definition generated with the following
19# command:
20#
21# gn desc out --format=json --all-toolchains "//*" > desc.json
22#
23# The tool is then given a list of GN labels for which to generate Bazel
24# build rules.
25
26from __future__ import print_function
27import argparse
Lalit Maganti279ecde2019-04-01 16:57:12 +010028import json
29import os
30import re
Lalit Maganti279ecde2019-04-01 16:57:12 +010031import sys
Lalit Maganti279ecde2019-04-01 16:57:12 +010032
Sami Kyostila3c88a1d2019-05-22 18:29:42 +010033import gn_utils
34
Matthew Clarkson9a5dfa52019-10-03 09:54:04 +010035from compat import itervalues, iteritems, basestring
36
Primiano Tucci1d409982019-09-19 10:15:18 +010037# Arguments for the GN output directory.
38# host_os="linux" is to generate the right build files from Mac OS.
39gn_args = ' '.join([
40 'host_os="linux"',
41 'is_debug=false',
42 'is_perfetto_build_generator=true',
43 'enable_perfetto_watchdog=true',
44 'monolithic_binaries=true',
45 'target_os="linux"',
46])
47
48# Default targets to translate to the blueprint file.
49
50# These targets will be exported with public visibility in the generated BUILD.
51public_targets = [
Pascal Muetschardb4966c52019-09-24 13:38:09 -070052 '//:libperfetto_client_experimental',
Primiano Tucci1d409982019-09-19 10:15:18 +010053 '//src/perfetto_cmd:perfetto',
54 '//src/traced/probes:traced_probes',
55 '//src/traced/service:traced',
56 '//src/trace_processor:trace_processor_shell',
57 '//src/trace_processor:trace_processor',
Lalit Maganti65600342019-09-19 21:35:35 +010058 '//tools/trace_to_text:trace_to_text',
Primiano Tucci1d409982019-09-19 10:15:18 +010059 '//tools/trace_to_text:libpprofbuilder',
60]
61
62# These targets are required by internal build rules but don't need to be
63# exported publicly.
64default_targets = [
Lalit Maganti01deefa2019-12-19 14:20:12 +000065 '//test:client_api_example',
Primiano Tucci1d409982019-09-19 10:15:18 +010066 '//src/ipc:perfetto_ipc',
67 '//src/ipc/protoc_plugin:ipc_plugin',
Primiano Tucci916f4e52020-10-16 20:40:33 +020068 '//src/protozero:protozero',
Primiano Tucci1d409982019-09-19 10:15:18 +010069 '//src/protozero/protoc_plugin:protozero_plugin',
Primiano Tucci57dd66b2019-10-15 23:09:04 +010070 '//src/protozero/protoc_plugin:cppgen_plugin',
Primiano Tucci1d409982019-09-19 10:15:18 +010071] + public_targets
72
73# Root proto targets (to force discovery of intermediate proto targets).
Pascal Muetschardb7cdea02019-09-23 15:25:20 -070074# These targets are marked public.
Primiano Tucci1d409982019-09-19 10:15:18 +010075proto_targets = [
Lalit Magantic3187f82019-09-20 14:51:11 +010076 '//protos/perfetto/trace:merged_trace',
Lalit Magantid78606d2019-11-21 17:45:55 +000077 '//protos/perfetto/trace:non_minimal_lite',
Pascal Muetschardb7cdea02019-09-23 15:25:20 -070078 '//protos/perfetto/config:merged_config',
Primiano Tucci1d409982019-09-19 10:15:18 +010079 '//protos/perfetto/metrics:lite',
Lalit Maganti613f97b2019-11-21 14:44:18 +000080 '//protos/perfetto/metrics/android:lite',
Primiano Tucci1d409982019-09-19 10:15:18 +010081 '//protos/perfetto/trace:lite',
82 '//protos/perfetto/config:lite',
83]
84
Lalit Maganti3b09a3f2020-09-14 13:28:44 +010085# Path for the protobuf sources in the standalone build.
86buildtools_protobuf_src = '//buildtools/protobuf/src'
87
Primiano Tucci1d409982019-09-19 10:15:18 +010088# The directory where the generated perfetto_build_flags.h will be copied into.
89buildflags_dir = 'include/perfetto/base/build_configs/bazel'
90
91# Internal equivalents for third-party libraries that the upstream project
92# depends on.
93external_deps = {
94 '//gn:default_deps': [],
95 '//gn:jsoncpp': ['PERFETTO_CONFIG.deps.jsoncpp'],
96 '//gn:linenoise': ['PERFETTO_CONFIG.deps.linenoise'],
97 '//gn:protobuf_full': ['PERFETTO_CONFIG.deps.protobuf_full'],
98 '//gn:protobuf_lite': ['PERFETTO_CONFIG.deps.protobuf_lite'],
99 '//gn:protoc_lib': ['PERFETTO_CONFIG.deps.protoc_lib'],
100 '//gn:protoc': ['PERFETTO_CONFIG.deps.protoc'],
101 '//gn:sqlite': [
102 'PERFETTO_CONFIG.deps.sqlite',
103 'PERFETTO_CONFIG.deps.sqlite_ext_percentile'
104 ],
105 '//gn:zlib': ['PERFETTO_CONFIG.deps.zlib'],
Matthew Clarkson63028d62019-10-10 15:48:23 +0100106 '//src/trace_processor/metrics:gen_merged_sql_metrics': [[
Lalit Maganti117272f2020-09-11 14:01:18 +0100107 ':cc_merged_sql_metrics'
Primiano Tucciec590132020-11-16 14:16:44 +0100108 ]],
109 gn_utils.GEN_VERSION_TARGET: ['PERFETTO_CONFIG.deps.version_header'],
Primiano Tucci1d409982019-09-19 10:15:18 +0100110}
111
112
113def gen_sql_metrics(target):
114 label = BazelLabel(get_bazel_label_name(target.name), 'genrule')
Matthew Clarkson9a5dfa52019-10-03 09:54:04 +0100115 label.srcs += [re.sub('^//', '', x) for x in sorted(target.inputs)]
Primiano Tucci1d409982019-09-19 10:15:18 +0100116 label.outs += target.outputs
117 label.cmd = r'$(location gen_merged_sql_metrics_py) --cpp_out=$@ $(SRCS)'
Lalit Maganti9d9e56b2020-08-13 17:38:15 +0100118 label.exec_tools += [':gen_merged_sql_metrics_py']
Primiano Tucci1d409982019-09-19 10:15:18 +0100119 return [label]
120
121
Primiano Tucciec590132020-11-16 14:16:44 +0100122def gen_version_header(target):
123 label = BazelLabel(get_bazel_label_name(target.name), 'genrule')
124 label.srcs += [re.sub('^//', '', x) for x in sorted(target.inputs)]
125 label.outs += target.outputs
Primiano Tuccif0ed1d42020-11-18 16:30:18 +0100126 label.cmd = r'$(location gen_version_header_py)'
Joshua Gilpatrick042931b2020-12-04 08:55:59 -0800127 label.cmd += r' --cpp_out=$@ --changelog=$(location CHANGELOG)'
Primiano Tucciec590132020-11-16 14:16:44 +0100128 label.exec_tools += [':gen_version_header_py']
129 return [label]
130
131
Lalit Maganti117272f2020-09-11 14:01:18 +0100132def gen_cc_metrics_descriptor(target):
133 label = BazelLabel(
134 get_bazel_label_name(target.name), 'perfetto_cc_proto_descriptor')
135 label.deps += [':' + get_bazel_label_name(x) for x in target.proto_deps]
136 label.outs += target.outputs
137 return [label]
138
139
Primiano Tucci1d409982019-09-19 10:15:18 +0100140custom_actions = {
Primiano Tucciec590132020-11-16 14:16:44 +0100141 gn_utils.GEN_VERSION_TARGET: gen_version_header,
Primiano Tucci1d409982019-09-19 10:15:18 +0100142 '//src/trace_processor/metrics:gen_merged_sql_metrics': gen_sql_metrics,
143}
144
145# ------------------------------------------------------------------------------
146# End of configuration.
147# ------------------------------------------------------------------------------
148
149
150class Error(Exception):
151 pass
152
153
154class BazelLabel(object):
155
156 def __init__(self, name, type):
157 self.comment = None
158 self.name = name
159 self.type = type
160 self.visibility = []
161 self.srcs = []
162 self.hdrs = []
163 self.deps = []
164 self.external_deps = []
165 self.tools = []
Lalit Maganti9d9e56b2020-08-13 17:38:15 +0100166 self.exec_tools = []
Primiano Tucci1d409982019-09-19 10:15:18 +0100167 self.outs = []
168
Matthew Clarkson9a5dfa52019-10-03 09:54:04 +0100169 def __lt__(self, other):
170 if isinstance(other, self.__class__):
171 return self.name < other.name
Primiano Tucci57dd66b2019-10-15 23:09:04 +0100172 raise TypeError('\'<\' not supported between instances of \'%s\' and \'%s\''
173 % (type(self).__name__, type(other).__name__))
Matthew Clarkson9a5dfa52019-10-03 09:54:04 +0100174
Primiano Tucci1d409982019-09-19 10:15:18 +0100175 def __str__(self):
176 """Converts the object into a Bazel Starlark label."""
177 res = ''
178 res += ('# GN target: %s\n' % self.comment) if self.comment else ''
179 res += '%s(\n' % self.type
180 any_deps = len(self.deps) + len(self.external_deps) > 0
Lalit Maganti9d9e56b2020-08-13 17:38:15 +0100181 ORD = [
182 'name','srcs', 'hdrs', 'visibility', 'deps', 'outs', 'cmd', 'tools',
183 'exec_tools'
184 ]
Matthew Clarkson9a5dfa52019-10-03 09:54:04 +0100185 hasher = lambda x: sum((99,) + tuple(ord(c) for c in x))
186 key_sorter = lambda kv: ORD.index(kv[0]) if kv[0] in ORD else hasher(kv[0])
187 for k, v in sorted(iteritems(self.__dict__), key=key_sorter):
Primiano Tucci1d409982019-09-19 10:15:18 +0100188 if k in ('type', 'comment',
189 'external_deps') or v is None or (v == [] and
190 (k != 'deps' or not any_deps)):
191 continue
192 res += ' %s = ' % k
193 if isinstance(v, basestring):
Lalit Magantie5aad3b2020-01-20 18:43:05 +0000194 if v.startswith('PERFETTO_CONFIG.'):
195 res += '%s,\n' % v
196 else:
197 res += '"%s",\n' % v
Lalit Magantif9c004d2020-01-06 14:44:34 +0000198 elif isinstance(v, bool):
199 res += '%s,\n' % v
Primiano Tucci1d409982019-09-19 10:15:18 +0100200 elif isinstance(v, list):
201 res += '[\n'
Lalit Maganti65600342019-09-19 21:35:35 +0100202 if k == 'deps' and len(self.external_deps) > 1:
203 indent = ' '
204 else:
205 indent = ' '
Primiano Tucci34bc5592021-02-19 17:53:36 +0100206 for entry in sorted(v):
Primiano Tuccie88d9392019-11-19 17:42:41 +0000207 if entry.startswith('PERFETTO_CONFIG.'):
208 res += '%s %s,\n' % (indent, entry)
209 else:
210 res += '%s "%s",\n' % (indent, entry)
Lalit Maganti65600342019-09-19 21:35:35 +0100211 res += '%s]' % indent
212 if k == 'deps' and self.external_deps:
213 res += ' + %s' % self.external_deps[0]
214 for edep in self.external_deps[1:]:
215 if isinstance(edep, list):
216 res += ' + [\n'
217 for inner_dep in edep:
Lalit Magantia4244e42019-09-20 12:03:32 +0100218 res += ' "%s",\n' % inner_dep
Lalit Maganti65600342019-09-19 21:35:35 +0100219 res += ' ]'
220 else:
221 res += ' +\n%s%s' % (indent, edep)
Primiano Tucci1d409982019-09-19 10:15:18 +0100222 res += ',\n'
223 else:
224 raise Error('Unsupported value %s', type(v))
225 res += ')\n\n'
226 return res
227
228
Lalit Maganti613f97b2019-11-21 14:44:18 +0000229# Public visibility for targets in Bazel.
Lalit Magantie5aad3b2020-01-20 18:43:05 +0000230PUBLIC_VISIBILITY = 'PERFETTO_CONFIG.public_visibility'
Lalit Maganti613f97b2019-11-21 14:44:18 +0000231
232
Primiano Tucci1d409982019-09-19 10:15:18 +0100233def get_bazel_label_name(gn_name):
234 """Converts a GN target name into a Bazel label name.
235
Primiano Tucci66b08c32020-07-23 12:37:48 +0200236 If target is in the public target list, returns only the GN target name,
Primiano Tucci1d409982019-09-19 10:15:18 +0100237 e.g.: //src/ipc:perfetto_ipc -> perfetto_ipc
238
Primiano Tucci66b08c32020-07-23 12:37:48 +0200239 Otherwise, in the case of an intermediate target, returns a mangled path.
Primiano Tucci1d409982019-09-19 10:15:18 +0100240 e.g.: //include/perfetto/base:base -> include_perfetto_base_base.
241 """
242 if gn_name in default_targets:
243 return gn_utils.label_without_toolchain(gn_name).split(':')[1]
244 return gn_utils.label_to_target_name_with_path(gn_name)
245
246
247def gen_proto_labels(target):
248 """ Generates the xx_proto_library label for proto targets.
249
250 Bazel requires that each protobuf-related target is modeled with two labels:
Lalit Maganti117272f2020-09-11 14:01:18 +0100251 1. A plugin-agnostic target that defines only the .proto sources and their
Primiano Tucci1d409982019-09-19 10:15:18 +0100252 dependencies.
Lalit Maganti117272f2020-09-11 14:01:18 +0100253 2. A plugin-dependent target (e.g. cc_library, cc_protozero_library) that has
254 only a dependency on 1 and does NOT refer to any .proto sources.
Primiano Tucci1d409982019-09-19 10:15:18 +0100255 """
256 assert (target.type == 'proto_library')
257
258 def get_sources_label(target_name):
Lalit Maganti64cd1f62020-09-14 17:44:52 +0100259 return re.sub('_(lite|zero|cpp|ipc|source_set|descriptor)$', '',
Primiano Tucci1d409982019-09-19 10:15:18 +0100260 get_bazel_label_name(target_name)) + '_protos'
261
262 sources_label_name = get_sources_label(target.name)
263
264 # Generates 1.
Primiano Tucci1d409982019-09-19 10:15:18 +0100265 sources_label = BazelLabel(sources_label_name, 'perfetto_proto_library')
266 sources_label.comment = target.name
267 assert (all(x.startswith('//') for x in target.sources))
268 assert (all(x.endswith('.proto') for x in target.sources))
269 sources_label.srcs = sorted([x[2:] for x in target.sources]) # Strip //.
Primiano Tuccif0d63af2019-11-19 17:07:37 +0000270
Primiano Tuccif0d63af2019-11-19 17:07:37 +0000271 deps = [
272 ':' + get_sources_label(x)
273 for x in target.proto_deps
Primiano Tuccie8020f92019-11-26 13:24:01 +0000274
275 # This is to avoid a dependency-on-self in the case where
276 # protos/perfetto/ipc:ipc depends on protos/perfetto/ipc:cpp and both
277 # targets resolve to "protos_perfetto_ipc_protos".
278 if get_sources_label(x) != sources_label_name
Primiano Tuccif0d63af2019-11-19 17:07:37 +0000279 ]
Primiano Tucci1d409982019-09-19 10:15:18 +0100280 sources_label.deps = sorted(deps)
281
Lalit Maganti3b09a3f2020-09-14 13:28:44 +0100282 # In Bazel, proto_paths are not a supported concept becauase strong dependency
283 # checking is enabled. Instead, we need to depend on the target which includes
284 # the proto we want to depend on.
285 # For example, we include the proto_path |buildtools_protobuf_src| because we
286 # want to depend on the "google/protobuf/descriptor.proto" proto file. This
287 # will be exposed by the |protobuf_descriptor_proto| dep.
288 if buildtools_protobuf_src in target.proto_paths:
289 sources_label.external_deps = [
290 'PERFETTO_CONFIG.deps.protobuf_descriptor_proto'
291 ]
292
Pascal Muetschardb7cdea02019-09-23 15:25:20 -0700293 if target.name in proto_targets:
Lalit Maganti613f97b2019-11-21 14:44:18 +0000294 sources_label.visibility = PUBLIC_VISIBILITY
Primiano Tuccie88d9392019-11-19 17:42:41 +0000295 else:
296 sources_label.visibility = ['PERFETTO_CONFIG.proto_library_visibility']
Pascal Muetschardb7cdea02019-09-23 15:25:20 -0700297
Lalit Maganti117272f2020-09-11 14:01:18 +0100298 # For 'source_set' plugins, we don't want to generate any plugin-dependent
299 # targets so just return the label of the proto sources only.
300 if target.proto_plugin == 'source_set':
301 return [sources_label]
302
303 # Generates 2.
304 if target.proto_plugin == 'proto':
305 plugin_label_type = 'perfetto_cc_proto_library'
306 elif target.proto_plugin == 'protozero':
307 plugin_label_type = 'perfetto_cc_protozero_library'
308 elif target.proto_plugin == 'cppgen':
309 plugin_label_type = 'perfetto_cc_protocpp_library'
310 elif target.proto_plugin == 'ipc':
311 plugin_label_type = 'perfetto_cc_ipc_library'
312 elif target.proto_plugin == 'descriptor':
313 plugin_label_type = 'perfetto_proto_descriptor'
314 else:
315 raise Error('Unknown proto plugin: %s' % target.proto_plugin)
316 plugin_label_name = get_bazel_label_name(target.name)
317 plugin_label = BazelLabel(plugin_label_name, plugin_label_type)
318 plugin_label.comment = target.name
319 plugin_label.deps += [':' + sources_label_name]
320
321 # When using the cppgen plugin we need to pass down also the transitive deps.
322 # For instance consider foo.proto including common.proto. The generated
323 # foo.cc will #include "common.gen.h". Hence the generated cc_protocpp_library
324 # rule need to pass down the dependency on the target that generates
325 # common.gen.{cc,h}. This is not needed for protozero because protozero
326 # headers are fully hermetic deps-wise and use only on forward declarations.
327 if target.proto_deps and target.proto_plugin in ('cppgen', 'ipc'):
328 plugin_label.deps += [
329 ':' + get_bazel_label_name(x) for x in target.proto_deps
330 ]
331
332 if target.proto_plugin == 'descriptor':
333 plugin_label.outs = [plugin_label_name + '.bin']
334
335 return [sources_label, plugin_label]
Primiano Tucci1d409982019-09-19 10:15:18 +0100336
337
338def gen_target(gn_target):
339 if gn_target.type == 'proto_library':
340 return gen_proto_labels(gn_target)
341 elif gn_target.type == 'action':
342 if gn_target.name in custom_actions:
343 return custom_actions[gn_target.name](gn_target)
Lalit Maganti2939c082021-03-11 17:25:44 +0000344 elif re.match('.*gen_cc_.*_descriptor$', gn_target.name):
345 return gen_cc_metrics_descriptor(gn_target)
Primiano Tucci1d409982019-09-19 10:15:18 +0100346 return []
347 elif gn_target.type == 'group':
348 return []
349 elif gn_target.type == 'executable':
350 bazel_type = 'perfetto_cc_binary'
351 elif gn_target.type == 'shared_library':
352 bazel_type = 'perfetto_cc_binary'
353 vars['linkshared'] = True
354 elif gn_target.type == 'static_library':
355 bazel_type = 'perfetto_cc_library'
356 elif gn_target.type == 'source_set':
357 bazel_type = 'filegroup'
358 else:
359 raise Error('target type not supported: %s' % gn_target.type)
360
361 label = BazelLabel(get_bazel_label_name(gn_target.name), bazel_type)
362 label.comment = gn_target.name
Lalit Maganti91d223e2019-12-20 12:28:19 +0000363
364 raw_srcs = [x[2:] for x in gn_target.sources]
365 if bazel_type == 'perfetto_cc_library':
366 label.srcs = [x for x in raw_srcs if not x.startswith('include')]
367 label.hdrs = [x for x in raw_srcs if x.startswith('include')]
Lalit Magantif9c004d2020-01-06 14:44:34 +0000368
369 # Most Perfetto libraries cannot by dynamically linked as they would
370 # cause ODR violations.
371 label.__dict__['linkstatic'] = True
Lalit Maganti91d223e2019-12-20 12:28:19 +0000372 else:
373 label.srcs = raw_srcs
Primiano Tucci1d409982019-09-19 10:15:18 +0100374
375 if gn_target.name in public_targets:
376 label.visibility = ['//visibility:public']
377
378 if gn_target.type in gn_utils.LINKER_UNIT_TYPES:
379 # |source_sets| contains the transitive set of source_set deps.
380 for trans_dep in gn_target.source_set_deps:
381 name = ':' + get_bazel_label_name(trans_dep)
382 if name.startswith(
383 ':include_perfetto_') and gn_target.type != 'executable':
384 label.hdrs += [name]
385 else:
386 label.srcs += [name]
Matthew Clarkson9a5dfa52019-10-03 09:54:04 +0100387 for dep in sorted(gn_target.deps):
Primiano Tucci1d409982019-09-19 10:15:18 +0100388 if dep.startswith('//gn:'):
389 assert (dep in external_deps), dep
390 if dep in external_deps:
391 assert (isinstance(external_deps[dep], list))
392 label.external_deps += external_deps[dep]
393 else:
394 label.deps += [':' + get_bazel_label_name(dep)]
395 label.deps += [':' + get_bazel_label_name(x) for x in gn_target.proto_deps]
396
Lalit Maganti65600342019-09-19 21:35:35 +0100397 # All items starting with : need to be sorted to the end of the list.
398 # However, Python makes specifying a comparator function hard so cheat
399 # instead and make everything start with : sort as if it started with |
400 # As | > all other normal ASCII characters, this will lead to all : targets
401 # starting with : to be sorted to the end.
402 label.srcs = sorted(label.srcs, key=lambda x: x.replace(':', '|'))
403
Primiano Tucci1d409982019-09-19 10:15:18 +0100404 label.deps = sorted(label.deps)
Primiano Tucci1d409982019-09-19 10:15:18 +0100405 label.hdrs = sorted(label.hdrs)
406 return [label]
407
408
409def gen_target_str(gn_target):
410 return ''.join(str(x) for x in gen_target(gn_target))
411
412
413def generate_build(gn_desc, targets, extras):
414 gn = gn_utils.GnParser(gn_desc)
415 res = '''
416# Copyright (C) 2019 The Android Open Source Project
Lalit Maganti279ecde2019-04-01 16:57:12 +0100417#
418# Licensed under the Apache License, Version 2.0 (the "License");
419# you may not use this file except in compliance with the License.
420# You may obtain a copy of the License at
421#
422# http://www.apache.org/licenses/LICENSE-2.0
423#
424# Unless required by applicable law or agreed to in writing, software
425# distributed under the License is distributed on an "AS IS" BASIS,
426# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
427# See the License for the specific language governing permissions and
428# limitations under the License.
429#
430# This file is automatically generated by {}. Do not edit.
Lalit Maganti279ecde2019-04-01 16:57:12 +0100431
Primiano Tucci1d409982019-09-19 10:15:18 +0100432load("@perfetto_cfg//:perfetto_cfg.bzl", "PERFETTO_CONFIG")
433load(
434 "@perfetto//bazel:rules.bzl",
435 "perfetto_cc_binary",
436 "perfetto_cc_ipc_library",
437 "perfetto_cc_library",
Lalit Maganti117272f2020-09-11 14:01:18 +0100438 "perfetto_cc_proto_descriptor",
Primiano Tucci1d409982019-09-19 10:15:18 +0100439 "perfetto_cc_proto_library",
Primiano Tucci57dd66b2019-10-15 23:09:04 +0100440 "perfetto_cc_protocpp_library",
Primiano Tucci1d409982019-09-19 10:15:18 +0100441 "perfetto_cc_protozero_library",
Lalit Maganti65600342019-09-19 21:35:35 +0100442 "perfetto_java_proto_library",
Lalit Maganti46e2bda2020-05-06 12:51:33 +0100443 "perfetto_java_lite_proto_library",
Primiano Tucci1d409982019-09-19 10:15:18 +0100444 "perfetto_proto_library",
Lalit Maganti117272f2020-09-11 14:01:18 +0100445 "perfetto_proto_descriptor",
Primiano Tucci1d409982019-09-19 10:15:18 +0100446 "perfetto_py_binary",
Anindita Ghosh237a7762020-06-30 10:46:52 +0000447 "perfetto_py_library",
Lalit Maganti65600342019-09-19 21:35:35 +0100448 "perfetto_gensignature_internal_only",
Primiano Tucci1d409982019-09-19 10:15:18 +0100449)
Lalit Maganti279ecde2019-04-01 16:57:12 +0100450
Primiano Tucci1d409982019-09-19 10:15:18 +0100451package(default_visibility = ["//visibility:private"])
Lalit Maganti65600342019-09-19 21:35:35 +0100452
Lalit Magantibb037f72019-09-24 16:22:45 +0100453licenses(["notice"])
Lalit Maganti65600342019-09-19 21:35:35 +0100454
Primiano Tucci1d409982019-09-19 10:15:18 +0100455exports_files(["NOTICE"])
Lalit Magantia48710d2019-09-24 13:10:11 +0100456
Lalit Maganti65600342019-09-19 21:35:35 +0100457'''.format(__file__).lstrip()
Lalit Maganti279ecde2019-04-01 16:57:12 +0100458
Primiano Tucci1d409982019-09-19 10:15:18 +0100459 # Public targets need to be computed at the beginning (to figure out the
460 # intermediate deps) but printed at the end (because declaration order matters
461 # in Bazel).
462 public_str = ''
463 for target_name in sorted(public_targets):
464 target = gn.get_target(target_name)
465 public_str += gen_target_str(target)
Primiano Tucci8e627442019-08-28 07:58:38 +0200466
Primiano Tucci1d409982019-09-19 10:15:18 +0100467 res += '''
468# ##############################################################################
469# Internal targets
470# ##############################################################################
Lalit Maganti279ecde2019-04-01 16:57:12 +0100471
Lalit Maganti65600342019-09-19 21:35:35 +0100472'''.lstrip()
Primiano Tucci1d409982019-09-19 10:15:18 +0100473 # Generate the other non-public targets.
474 for target_name in sorted(set(default_targets) - set(public_targets)):
475 target = gn.get_target(target_name)
476 res += gen_target_str(target)
Lalit Maganti279ecde2019-04-01 16:57:12 +0100477
Primiano Tucci1d409982019-09-19 10:15:18 +0100478 # Generate all the intermediate targets.
Matthew Clarkson9a5dfa52019-10-03 09:54:04 +0100479 for target in sorted(itervalues(gn.all_targets)):
Primiano Tucci1d409982019-09-19 10:15:18 +0100480 if target.name in default_targets or target.name in gn.proto_libs:
481 continue
482 res += gen_target_str(target)
Lalit Maganti279ecde2019-04-01 16:57:12 +0100483
Primiano Tucci1d409982019-09-19 10:15:18 +0100484 res += '''
485# ##############################################################################
486# Proto libraries
487# ##############################################################################
Lalit Maganti279ecde2019-04-01 16:57:12 +0100488
Lalit Maganti65600342019-09-19 21:35:35 +0100489'''.lstrip()
Primiano Tucci1d409982019-09-19 10:15:18 +0100490 # Force discovery of explicilty listed root proto targets.
Matthew Clarkson9a5dfa52019-10-03 09:54:04 +0100491 for target_name in sorted(proto_targets):
Primiano Tucci1d409982019-09-19 10:15:18 +0100492 gn.get_target(target_name)
Lalit Maganti279ecde2019-04-01 16:57:12 +0100493
Primiano Tucci1d409982019-09-19 10:15:18 +0100494 # Generate targets for the transitive set of proto targets.
495 # TODO explain deduping here.
496 labels = {}
Matthew Clarkson9a5dfa52019-10-03 09:54:04 +0100497 for target in sorted(itervalues(gn.proto_libs)):
Primiano Tucci1d409982019-09-19 10:15:18 +0100498 for label in gen_target(target):
Lalit Maganti613f97b2019-11-21 14:44:18 +0000499 # Ensure that if the existing target has public visibility, we preserve
500 # that in the new label; this ensures that we don't accidentaly reduce
501 # the visibility of targets which are meant to be public.
502 existing_label = labels.get(label.name)
503 if existing_label and existing_label.visibility == PUBLIC_VISIBILITY:
504 label.visibility = PUBLIC_VISIBILITY
Primiano Tucci1d409982019-09-19 10:15:18 +0100505 labels[label.name] = label
Lalit Maganti279ecde2019-04-01 16:57:12 +0100506
Matthew Clarkson9a5dfa52019-10-03 09:54:04 +0100507 res += ''.join(str(x) for x in sorted(itervalues(labels)))
Lalit Maganti279ecde2019-04-01 16:57:12 +0100508
Primiano Tucci1d409982019-09-19 10:15:18 +0100509 res += '''
510# ##############################################################################
511# Public targets
512# ##############################################################################
Lalit Maganti279ecde2019-04-01 16:57:12 +0100513
Lalit Maganti65600342019-09-19 21:35:35 +0100514'''.lstrip()
Primiano Tucci1d409982019-09-19 10:15:18 +0100515 res += public_str
516 res += '# Content from BUILD.extras\n\n'
517 res += extras
Lalit Maganti279ecde2019-04-01 16:57:12 +0100518
Primiano Tucci916f4e52020-10-16 20:40:33 +0200519 # Check for ODR violations
520 for target_name in default_targets + proto_targets:
521 checker = gn_utils.ODRChecker(gn, target_name)
522
523 return res
Lalit Maganti279ecde2019-04-01 16:57:12 +0100524
Lalit Maganti279ecde2019-04-01 16:57:12 +0100525def main():
526 parser = argparse.ArgumentParser(
527 description='Generate BUILD from a GN description.')
528 parser.add_argument(
Primiano Tucci1d409982019-09-19 10:15:18 +0100529 '--check-only',
530 help='Don\'t keep the generated files',
531 action='store_true')
Primiano Tucci9c411652019-08-27 07:13:59 +0200532 parser.add_argument(
Lalit Maganti279ecde2019-04-01 16:57:12 +0100533 '--desc',
Primiano Tucci1d409982019-09-19 10:15:18 +0100534 help='GN description ' +
535 '(e.g., gn desc out --format=json --all-toolchains "//*"')
Lalit Maganti279ecde2019-04-01 16:57:12 +0100536 parser.add_argument(
537 '--repo-root',
538 help='Standalone Perfetto repository to generate a GN description',
Sami Kyostila3c88a1d2019-05-22 18:29:42 +0100539 default=gn_utils.repo_root(),
Lalit Maganti279ecde2019-04-01 16:57:12 +0100540 )
541 parser.add_argument(
542 '--extras',
543 help='Extra targets to include at the end of the BUILD file',
Sami Kyostila3c88a1d2019-05-22 18:29:42 +0100544 default=os.path.join(gn_utils.repo_root(), 'BUILD.extras'),
Lalit Maganti279ecde2019-04-01 16:57:12 +0100545 )
546 parser.add_argument(
547 '--output',
548 help='BUILD file to create',
Sami Kyostila3c88a1d2019-05-22 18:29:42 +0100549 default=os.path.join(gn_utils.repo_root(), 'BUILD'),
Lalit Maganti279ecde2019-04-01 16:57:12 +0100550 )
551 parser.add_argument(
552 '--output-proto',
553 help='Proto BUILD file to create',
Sami Kyostila3c88a1d2019-05-22 18:29:42 +0100554 default=os.path.join(gn_utils.repo_root(), 'protos', 'BUILD'),
Lalit Maganti279ecde2019-04-01 16:57:12 +0100555 )
556 parser.add_argument(
557 'targets',
558 nargs=argparse.REMAINDER,
559 help='Targets to include in the BUILD file (e.g., "//:perfetto_tests")')
560 args = parser.parse_args()
561
562 if args.desc:
563 with open(args.desc) as f:
564 desc = json.load(f)
565 else:
Sami Kyostila3c88a1d2019-05-22 18:29:42 +0100566 desc = gn_utils.create_build_description(gn_args, args.repo_root)
Lalit Maganti279ecde2019-04-01 16:57:12 +0100567
Primiano Tucci9c411652019-08-27 07:13:59 +0200568 out_files = []
569
Primiano Tucci9c411652019-08-27 07:13:59 +0200570 # Generate the main BUILD file.
Primiano Tucci1d409982019-09-19 10:15:18 +0100571 with open(args.extras, 'r') as extra_f:
572 extras = extra_f.read()
Lalit Maganti279ecde2019-04-01 16:57:12 +0100573
Primiano Tucci1d409982019-09-19 10:15:18 +0100574 contents = generate_build(desc, args.targets or default_targets, extras)
575 out_files.append(args.output + '.swp')
576 with open(out_files[-1], 'w') as out_f:
577 out_f.write(contents)
Lalit Maganti279ecde2019-04-01 16:57:12 +0100578
Primiano Tucci8e627442019-08-28 07:58:38 +0200579 # Generate the build flags file.
580 out_files.append(os.path.join(buildflags_dir, 'perfetto_build_flags.h.swp'))
581 gn_utils.gen_buildflags(gn_args, out_files[-1])
582
Primiano Tucci9c411652019-08-27 07:13:59 +0200583 return gn_utils.check_or_commit_generated_files(out_files, args.check_only)
Lalit Maganti279ecde2019-04-01 16:57:12 +0100584
585
586if __name__ == '__main__':
587 sys.exit(main())