xref: /aosp_15_r20/external/perfetto/tools/gen_android_bp (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1#!/usr/bin/env python3
2# Copyright (C) 2017 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# Android.bp file for the Android Soong 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 Android.bp
24# build rules. The dependencies for the GN labels are squashed to the generated
25# Android.bp target, except for actions which get their own genrule. Some
26# libraries are also mapped to their Android equivalents -- see |builtin_deps|.
27
28import argparse
29import json
30import os
31import re
32import sys
33from typing import Dict
34from typing import List
35from typing import Optional
36
37import gn_utils
38from gn_utils import GnParser
39
40from compat import itervalues
41
42ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
43
44# Arguments for the GN output directory.
45gn_args = ' '.join([
46    'is_debug=false',
47    'is_perfetto_build_generator=true',
48    'perfetto_build_with_android=true',
49    'target_cpu="arm"',
50    'target_os="android"',
51])
52
53# Default targets to translate to the blueprint file.
54default_targets = [
55    '//:libperfetto_client_experimental',
56    '//:libperfetto',
57    '//:perfetto_integrationtests',
58    '//:perfetto_unittests',
59    '//protos/perfetto/trace:perfetto_trace_protos',
60    '//protos/perfetto/trace/android:perfetto_winscope_extensions_zero',
61    '//src/android_internal:libperfetto_android_internal',
62    '//src/base:perfetto_base_default_platform',
63    '//src/shared_lib:libperfetto_c',
64    '//src/perfetto_cmd:perfetto',
65    '//src/perfetto_cmd:trigger_perfetto',
66    '//src/profiling/memory:heapprofd_client',
67    '//src/profiling/memory:heapprofd_client_api',
68    '//src/profiling/memory:heapprofd_api_noop',
69    '//src/profiling/memory:heapprofd',
70    '//src/profiling/memory:heapprofd_standalone_client',
71    '//src/profiling/perf:traced_perf',
72    '//src/traced/probes:traced_probes',
73    '//src/traced/service:traced',
74    '//src/traced_relay:traced_relay',
75    '//src/trace_processor:trace_processor_shell',
76    '//src/trace_redaction:trace_redactor',
77    '//test/cts:perfetto_cts_deps',
78    '//test/cts:perfetto_cts_jni_deps',
79    '//test:perfetto_gtest_logcat_printer',
80    '//test:perfetto_end_to_end_integrationtests',
81    '//test/vts:perfetto_vts_deps',
82]
83
84# Host targets
85ipc_plugin = '//src/ipc/protoc_plugin:ipc_plugin(%s)' % gn_utils.HOST_TOOLCHAIN
86protozero_plugin = '//src/protozero/protoc_plugin:protozero_plugin(%s)' % (
87    gn_utils.HOST_TOOLCHAIN)
88cppgen_plugin = '//src/protozero/protoc_plugin:cppgen_plugin(%s)' % (
89    gn_utils.HOST_TOOLCHAIN)
90
91default_targets += [
92    '//src/traceconv:traceconv(%s)' % gn_utils.HOST_TOOLCHAIN,
93    protozero_plugin,
94    ipc_plugin,
95]
96
97# Defines a custom init_rc argument to be applied to the corresponding output
98# blueprint target.
99target_initrc = {
100    '//src/traced/service:traced': {'perfetto.rc'},
101    '//src/profiling/memory:heapprofd': {'heapprofd.rc'},
102    '//src/profiling/perf:traced_perf': {'traced_perf.rc'},
103}
104
105target_host_supported = [
106    '//:libperfetto',
107    '//:libperfetto_client_experimental',
108    '//protos/perfetto/trace:perfetto_trace_protos',
109    '//protos/perfetto/trace/android:perfetto_winscope_extensions_zero',
110    '//src/shared_lib:libperfetto_c',
111    '//src/trace_processor:demangle',
112    '//src/trace_processor:trace_processor_shell',
113    '//src/traced/probes:traced_probes',
114    '//src/traced/service:traced',
115]
116
117target_vendor_available = [
118    '//:libperfetto_client_experimental',
119    '//src/shared_lib:libperfetto_c',
120]
121
122target_product_available = [
123    '//:libperfetto_client_experimental',
124]
125
126# Proto target groups which will be made public.
127proto_groups = {
128    'trace': {
129        'types': ['lite'],
130        'targets': [
131            '//protos/perfetto/trace:non_minimal_source_set',
132            '//protos/perfetto/trace:minimal_source_set',
133        ]
134    },
135    'winscope': {
136        'types': ['filegroup'],
137        'targets': [
138            '//protos/perfetto/trace:non_minimal_source_set',
139            '//protos/perfetto/trace/android:winscope_extensions_source_set',
140        ]
141    },
142    'config': {
143        'types': ['lite', 'filegroup'],
144        'targets': [
145            '//protos/perfetto/config:source_set',
146        ]
147    },
148    'metrics': {
149        'types': ['python'],
150        'targets': [
151            '//protos/perfetto/metrics:source_set',
152        ]
153    },
154}
155
156needs_libfts = [
157    '//:perfetto_unittests',
158    '//src/trace_processor:trace_processor_shell',
159    '//src/traceconv:traceconv',
160]
161
162# All module names are prefixed with this string to avoid collisions.
163module_prefix = 'perfetto_'
164
165# Shared libraries which are directly translated to Android system equivalents.
166shared_library_allowlist = [
167    'android',
168    '[email protected]',
169    '[email protected]',
170    'android.hardware.health-V2-ndk',
171    '[email protected]',
172    'android.hardware.power.stats-V1-cpp',
173    'base',
174    'binder',
175    'binder_ndk',
176    'cutils',
177    'hidlbase',
178    'hidltransport',
179    'hwbinder',
180    'incident',
181    'log',
182    'services',
183    'statssocket',
184    'tracingproxy',
185    'utils',
186    'statspull',
187]
188
189# Static libraries which are directly translated to Android system equivalents.
190static_library_allowlist = [
191    'statslog_perfetto',
192]
193
194# Name of the module which settings such as compiler flags for all other
195# modules.
196defaults_module = module_prefix + 'defaults'
197
198# Location of the project in the Android source tree.
199tree_path = 'external/perfetto'
200
201# Path for the protobuf sources in the standalone build.
202buildtools_protobuf_src = '//buildtools/protobuf/src'
203
204# Location of the protobuf src dir in the Android source tree.
205android_protobuf_src = 'external/protobuf/src'
206
207# Compiler flags which are passed through to the blueprint.
208cflag_allowlist = r'^-DPERFETTO.*$'
209
210# Compiler defines which are passed through to the blueprint.
211define_allowlist = r'^(GOOGLE_PROTO.*)|(ZLIB_.*)|(USE_MMAP)$'
212
213# The directory where the generated perfetto_build_flags.h will be copied into.
214buildflags_dir = 'include/perfetto/base/build_configs/android_tree'
215
216def enumerate_data_deps():
217  with open(os.path.join(ROOT_DIR, 'tools', 'test_data.txt')) as f:
218    lines = f.readlines()
219  for line in (line.strip() for line in lines if not line.startswith('#')):
220    assert os.path.exists(line), 'file %s should exist' % line
221    if line.startswith('test/data/'):
222      # Skip test data files that require GCS. They are only for benchmarks.
223      # We don't run benchmarks in the android tree.
224      continue
225    if line.endswith('/.'):
226      yield line[:-1] + '**/*'
227    else:
228      yield line
229
230
231# Additional arguments to apply to Android.bp rules.
232additional_args = {
233    'heapprofd_client_api': [
234        ('static_libs', {'libasync_safe'}),
235        # heapprofd_client_api MUST NOT have global constructors. Because it
236        # is loaded in an __attribute__((constructor)) of libc, we cannot
237        # guarantee that the global constructors get run before it is used.
238        ('cflags', {'-Wglobal-constructors', '-Werror=global-constructors'}),
239        ('version_script', 'src/profiling/memory/heapprofd_client_api.map.txt'),
240        ('stubs', {
241            'versions': ['S'],
242            'symbol_file': 'src/profiling/memory/heapprofd_client_api.map.txt',
243        }),
244        ('export_include_dirs', {'src/profiling/memory/include'}),
245    ],
246    'heapprofd_api_noop': [
247        ('version_script', 'src/profiling/memory/heapprofd_client_api.map.txt'),
248        ('stubs', {
249            'versions': ['S'],
250            'symbol_file': 'src/profiling/memory/heapprofd_client_api.map.txt',
251        }),
252        ('export_include_dirs', {'src/profiling/memory/include'}),
253    ],
254    'heapprofd_client': [
255        ('include_dirs', {'bionic/libc'}),
256        ('static_libs', {'libasync_safe'}),
257    ],
258    'heapprofd_standalone_client': [
259        ('static_libs', {'libasync_safe'}),
260        ('version_script', 'src/profiling/memory/heapprofd_client_api.map.txt'),
261        ('export_include_dirs', {'src/profiling/memory/include'}),
262        ('stl', 'libc++_static'),
263    ],
264    'perfetto_unittests': [
265        ('data', set(enumerate_data_deps())),
266        ('include_dirs', {'bionic/libc/kernel'}),
267    ],
268    'perfetto_integrationtests': [
269        ('test_suites', {'general-tests'}),
270        ('test_config', 'PerfettoIntegrationTests.xml'),
271    ],
272    'libperfetto_android_internal': [('static_libs', {'libhealthhalutils'}),],
273    'trace_processor_shell': [
274        ('strip', {
275            'all': True
276        }),
277        ('host', {
278            'stl': 'libc++_static',
279            'dist': {
280                'targets': ['sdk_repo']
281            },
282        }),
283    ],
284    'libperfetto_client_experimental': [
285        ('apex_available', {
286            '//apex_available:platform', '//apex_available:anyapex'
287        }),
288        ('min_sdk_version', '30'),
289        ('shared_libs', {'liblog'}),
290        ('export_include_dirs', {'include', buildflags_dir}),
291    ],
292    'libperfetto_c': [
293        ('min_sdk_version', '30'),
294        ('export_include_dirs', {'include'}),
295        ('cflags', {'-DPERFETTO_SHLIB_SDK_IMPLEMENTATION'}),
296    ],
297    'perfetto_trace_protos': [
298        ('apex_available', {
299            '//apex_available:platform', 'com.android.art',
300            'com.android.art.debug'
301        }),
302        ('min_sdk_version', 'S'),
303    ],
304    'libperfetto': [('export_include_dirs', {'include', buildflags_dir}),],
305    'perfetto': [('required', {'perfetto_persistent_cfg.pbtxt'}),],
306    'trace_redactor': [
307        ('min_sdk_version', '35'),
308        ('apex_available', {
309            '//apex_available:platform',
310            'com.android.profiling'
311        }),
312    ],
313}
314
315
316def enable_base_platform(module):
317  module.srcs.add(':perfetto_base_default_platform')
318
319
320def enable_gtest_and_gmock(module):
321  module.static_libs.add('libgmock')
322  module.static_libs.add('libgtest')
323  if module.name != 'perfetto_gtest_logcat_printer':
324    module.whole_static_libs.add('perfetto_gtest_logcat_printer')
325
326
327def enable_protobuf_full(module):
328  if module.type == 'cc_binary_host':
329    module.static_libs.add('libprotobuf-cpp-full')
330  elif module.host_supported:
331    module.host.static_libs.add('libprotobuf-cpp-full')
332    module.android.shared_libs.add('libprotobuf-cpp-full')
333  else:
334    module.shared_libs.add('libprotobuf-cpp-full')
335
336
337def enable_protobuf_lite(module):
338  module.shared_libs.add('libprotobuf-cpp-lite')
339
340
341def enable_protoc_lib(module):
342  if module.type == 'cc_binary_host':
343    module.static_libs.add('libprotoc')
344  else:
345    module.shared_libs.add('libprotoc')
346
347
348def enable_libunwindstack(module):
349  if module.name != 'heapprofd_standalone_client':
350    module.shared_libs.add('libunwindstack')
351    module.shared_libs.add('libprocinfo')
352    module.shared_libs.add('libbase')
353  else:
354    module.static_libs.add('libunwindstack')
355    module.static_libs.add('libprocinfo')
356    module.static_libs.add('libbase')
357    module.static_libs.add('liblzma')
358    module.static_libs.add('libdexfile_support')
359    module.runtime_libs.add('libdexfile')  # libdexfile_support dependency
360    module.shared_libs.add('libz') # libunwindstack dependency
361
362
363def enable_libunwind(module):
364  # libunwind is disabled on Darwin so we cannot depend on it.
365  pass
366
367
368def enable_sqlite(module):
369  if module.type == 'cc_binary_host':
370    module.static_libs.add('libsqlite_static_noicu')
371    module.static_libs.add('sqlite_ext_percentile')
372  elif module.host_supported:
373    # Copy what the sqlite3 command line tool does.
374    module.android.shared_libs.add('libsqlite')
375    module.android.shared_libs.add('libicu')
376    module.android.shared_libs.add('liblog')
377    module.android.shared_libs.add('libutils')
378    module.android.static_libs.add('sqlite_ext_percentile')
379    module.host.static_libs.add('libsqlite_static_noicu')
380    module.host.static_libs.add('sqlite_ext_percentile')
381  else:
382    module.shared_libs.add('libsqlite')
383    module.shared_libs.add('libicu')
384    module.shared_libs.add('liblog')
385    module.shared_libs.add('libutils')
386    module.static_libs.add('sqlite_ext_percentile')
387
388
389def enable_zlib(module):
390  if module.type == 'cc_binary_host':
391    module.static_libs.add('libz')
392  elif module.host_supported:
393    module.android.shared_libs.add('libz')
394    module.host.static_libs.add('libz')
395  else:
396    module.shared_libs.add('libz')
397
398
399def enable_expat(module):
400  if module.type == 'cc_binary_host':
401    module.static_libs.add('libexpat')
402  elif module.host_supported:
403    module.android.shared_libs.add('libexpat')
404    module.host.static_libs.add('libexpat')
405  else:
406    module.shared_libs.add('libexpat')
407
408
409def enable_uapi_headers(module):
410  module.include_dirs.add('bionic/libc/kernel')
411
412
413def enable_bionic_libc_platform_headers_on_android(module):
414  module.header_libs.add('bionic_libc_platform_headers')
415
416
417# Android equivalents for third-party libraries that the upstream project
418# depends on.
419builtin_deps = {
420    '//gn:default_deps':
421        lambda x: None,
422    '//gn:gtest_main':
423        lambda x: None,
424    '//gn:protoc':
425        lambda x: None,
426    '//gn:base_platform':
427        enable_base_platform,
428    '//gn:gtest_and_gmock':
429        enable_gtest_and_gmock,
430    '//gn:libunwind':
431        enable_libunwind,
432    '//gn:protobuf_full':
433        enable_protobuf_full,
434    '//gn:protobuf_lite':
435        enable_protobuf_lite,
436    '//gn:protoc_lib':
437        enable_protoc_lib,
438    '//gn:libunwindstack':
439        enable_libunwindstack,
440    '//gn:sqlite':
441        enable_sqlite,
442    '//gn:zlib':
443        enable_zlib,
444    '//gn:expat':
445        enable_expat,
446    '//gn:bionic_kernel_uapi_headers':
447        enable_uapi_headers,
448    '//src/profiling/memory:bionic_libc_platform_headers_on_android':
449        enable_bionic_libc_platform_headers_on_android,
450}
451
452# ----------------------------------------------------------------------------
453# End of configuration.
454# ----------------------------------------------------------------------------
455
456
457class Error(Exception):
458  pass
459
460
461class ThrowingArgumentParser(argparse.ArgumentParser):
462
463  def __init__(self, context):
464    super(ThrowingArgumentParser, self).__init__()
465    self.context = context
466
467  def error(self, message):
468    raise Error('%s: %s' % (self.context, message))
469
470
471def write_blueprint_key_value(output, name, value, sort=True):
472  """Writes a Blueprint key-value pair to the output"""
473
474  if isinstance(value, bool):
475    if value:
476      output.append('    %s: true,' % name)
477    else:
478      output.append('    %s: false,' % name)
479    return
480  if not value:
481    return
482  if isinstance(value, set):
483    value = sorted(value)
484  if isinstance(value, list):
485    output.append('    %s: [' % name)
486    for item in sorted(value) if sort else value:
487      output.append('        "%s",' % item)
488    output.append('    ],')
489    return
490  if isinstance(value, Target):
491    value.to_string(output)
492    return
493  if isinstance(value, dict):
494    kv_output = []
495    for k, v in value.items():
496      write_blueprint_key_value(kv_output, k, v)
497
498    output.append('    %s: {' % name)
499    for line in kv_output:
500      output.append('    %s' % line)
501    output.append('    },')
502    return
503  output.append('    %s: "%s",' % (name, value))
504
505
506class Target(object):
507  """A target-scoped part of a module"""
508
509  def __init__(self, name):
510    self.name = name
511    self.shared_libs = set()
512    self.static_libs = set()
513    self.whole_static_libs = set()
514    self.cflags = set()
515    self.dist = dict()
516    self.strip = dict()
517    self.stl = None
518
519  def to_string(self, output):
520    nested_out = []
521    self._output_field(nested_out, 'shared_libs')
522    self._output_field(nested_out, 'static_libs')
523    self._output_field(nested_out, 'whole_static_libs')
524    self._output_field(nested_out, 'cflags')
525    self._output_field(nested_out, 'stl')
526    self._output_field(nested_out, 'dist')
527    self._output_field(nested_out, 'strip')
528
529    if nested_out:
530      output.append('    %s: {' % self.name)
531      for line in nested_out:
532        output.append('    %s' % line)
533      output.append('    },')
534
535  def _output_field(self, output, name, sort=True):
536    value = getattr(self, name)
537    return write_blueprint_key_value(output, name, value, sort)
538
539
540class Module(object):
541  """A single module (e.g., cc_binary, cc_test) in a blueprint."""
542
543  def __init__(self, mod_type, name, gn_target):
544    assert (gn_target)
545    self.type = mod_type
546    self.gn_target = gn_target
547    self.name = name
548    self.srcs = set()
549    self.main: Optional[str] = None
550    self.comment = 'GN: ' + gn_utils.label_without_toolchain(gn_target)
551    self.shared_libs = set()
552    self.static_libs = set()
553    self.whole_static_libs = set()
554    self.runtime_libs = set()
555    self.tools = set()
556    self.cmd: Optional[str] = None
557    self.host_supported = False
558    self.vendor_available = False
559    self.product_available = False
560    self.init_rc = set()
561    self.out = set()
562    self.export_include_dirs = set()
563    self.generated_headers = set()
564    self.export_generated_headers = set()
565    self.defaults = set()
566    self.cflags = set()
567    self.include_dirs = set()
568    self.header_libs = set()
569    self.required = set()
570    self.user_debug_flag = False
571    self.tool_files: Optional[List[str]] = None
572    self.android = Target('android')
573    self.host = Target('host')
574    self.musl = Target('musl')
575    self.lto: Optional[bool] = None
576    self.stl = None
577    self.dist = dict()
578    self.strip = dict()
579    self.data = set()
580    self.apex_available = set()
581    self.min_sdk_version = None
582    self.proto = dict()
583    self.output_extension: Optional[str] = None
584    # The genrule_XXX below are properties that must to be propagated back
585    # on the module(s) that depend on the genrule.
586    self.genrule_headers = set()
587    self.genrule_srcs = set()
588    self.genrule_shared_libs = set()
589    self.version_script = None
590    self.test_suites = set()
591    self.test_config = None
592    self.stubs = {}
593
594  def to_string(self, output):
595    if self.comment:
596      output.append('// %s' % self.comment)
597    output.append('%s {' % self.type)
598    self._output_field(output, 'name')
599    self._output_field(output, 'srcs')
600    self._output_field(output, 'shared_libs')
601    self._output_field(output, 'static_libs')
602    self._output_field(output, 'whole_static_libs')
603    self._output_field(output, 'runtime_libs')
604    self._output_field(output, 'tools')
605    self._output_field(output, 'cmd', sort=False)
606    if self.host_supported:
607      self._output_field(output, 'host_supported')
608    if self.vendor_available:
609      self._output_field(output, 'vendor_available')
610    if self.product_available:
611      self._output_field(output, 'product_available')
612    self._output_field(output, 'init_rc')
613    self._output_field(output, 'out')
614    self._output_field(output, 'export_include_dirs')
615    self._output_field(output, 'generated_headers')
616    self._output_field(output, 'export_generated_headers')
617    self._output_field(output, 'defaults')
618    self._output_field(output, 'cflags')
619    self._output_field(output, 'include_dirs')
620    self._output_field(output, 'header_libs')
621    self._output_field(output, 'required')
622    self._output_field(output, 'dist')
623    self._output_field(output, 'strip')
624    self._output_field(output, 'tool_files')
625    self._output_field(output, 'data')
626    self._output_field(output, 'stl')
627    self._output_field(output, 'apex_available')
628    self._output_field(output, 'min_sdk_version')
629    self._output_field(output, 'version_script')
630    self._output_field(output, 'test_suites')
631    self._output_field(output, 'test_config')
632    self._output_field(output, 'stubs')
633    self._output_field(output, 'proto')
634    self._output_field(output, 'main')
635    self._output_field(output, 'output_extension')
636
637    target_out = []
638    self._output_field(target_out, 'android')
639    self._output_field(target_out, 'host')
640    self._output_field(target_out, 'musl')
641    if target_out:
642      output.append('    target: {')
643      for line in target_out:
644        output.append('    %s' % line)
645      output.append('    },')
646
647    if self.user_debug_flag:
648      output.append('    product_variables: {')
649      output.append('        debuggable: {')
650      output.append(
651          '            cflags: ["-DPERFETTO_BUILD_WITH_ANDROID_USERDEBUG"],')
652      output.append('        },')
653      output.append('    },')
654    if self.lto is not None:
655      output.append('    target: {')
656      output.append('        android: {')
657      output.append('            lto: {')
658      output.append('                thin: %s,' %
659                    'true' if self.lto else 'false')
660      output.append('            },')
661      output.append('        },')
662      output.append('    },')
663    output.append('}')
664    output.append('')
665
666  def add_android_static_lib(self, lib):
667    if self.type == 'cc_binary_host':
668      raise Exception('Adding Android static lib for host tool is unsupported')
669    elif self.host_supported:
670      self.android.static_libs.add(lib)
671    else:
672      self.static_libs.add(lib)
673
674  def add_android_shared_lib(self, lib):
675    if self.type == 'cc_binary_host':
676      raise Exception('Adding Android shared lib for host tool is unsupported')
677    elif self.host_supported:
678      self.android.shared_libs.add(lib)
679    else:
680      self.shared_libs.add(lib)
681
682  def _output_field(self, output, name, sort=True):
683    value = getattr(self, name)
684    return write_blueprint_key_value(output, name, value, sort)
685
686
687class Blueprint(object):
688  """In-memory representation of an Android.bp file."""
689
690  def __init__(self):
691    self.modules: Dict[str, Module] = {}
692    self.gn_target_to_module: Dict[str, Module] = {}
693
694  def add_module(self, module: Module):
695    """Adds a new module to the blueprint, replacing any existing module
696        with the same name.
697
698        Args:
699            module: Module instance.
700        """
701    self.modules[module.name] = module
702    self.gn_target_to_module[module.gn_target] = module
703
704  def to_string(self, output):
705    for m in sorted(itervalues(self.modules), key=lambda m: m.name):
706      m.to_string(output)
707
708
709def label_to_module_name(label: str):
710  """Turn a GN label (e.g., //:perfetto_tests) into a module name."""
711  # If the label is explicibly listed in the default target list, don't prefix
712  # its name and return just the target name. This is so tools like
713  # "traceconv" stay as such in the Android tree.
714  label_without_toolchain = gn_utils.label_without_toolchain(label)
715  if label in default_targets or label_without_toolchain in default_targets:
716    return label_without_toolchain.split(':')[-1]
717
718  module = re.sub(r'^//:?', '', label_without_toolchain)
719  module = re.sub(r'[^a-zA-Z0-9_]', '_', module)
720  if not module.startswith(module_prefix):
721    return module_prefix + module
722  return module
723
724
725def is_supported_source_file(name: str):
726  """Returns True if |name| can appear in a 'srcs' list."""
727  return os.path.splitext(name)[1] in ['.c', '.cc', '.proto']
728
729
730def create_proto_modules(blueprint: Blueprint, gn: GnParser,
731                         target: GnParser.Target):
732  """Generate genrules for a proto GN target.
733
734    GN actions are used to dynamically generate files during the build. The
735    Soong equivalent is a genrule. This function turns a specific kind of
736    genrule which turns .proto files into source and header files into a pair
737    equivalent genrules.
738
739    Args:
740        blueprint: Blueprint instance which is being generated.
741        target: gn_utils.Target object.
742
743    Returns:
744        The source_genrule module.
745    """
746  assert (target.type == 'proto_library')
747
748  # We don't generate any targets for source_set proto modules because
749  # they will be inlined into other modules if required.
750  if target.proto_plugin == 'source_set':
751    return None
752
753  tools = {'aprotoc'}
754  cpp_out_dir = '$(genDir)/%s/' % tree_path
755  target_module_name = label_to_module_name(target.name)
756
757  # In GN builds the proto path is always relative to the output directory
758  # (out/tmp.xxx).
759  cmd = ['mkdir -p %s &&' % cpp_out_dir, '$(location aprotoc)']
760  cmd += ['--proto_path=%s' % tree_path]
761
762  tool_files = set()
763  if buildtools_protobuf_src in target.proto_paths:
764    cmd += ['--proto_path=%s' % android_protobuf_src]
765    # Add `google/protobuf/descriptor.proto` to implicit deps
766    tool_files.add(':libprotobuf-internal-descriptor-proto')
767
768  # Descriptor targets only generate a single target.
769  if target.proto_plugin == 'descriptor':
770    out = '{}.bin'.format(target_module_name)
771
772    cmd += ['--descriptor_set_out=$(out)']
773    cmd += ['$(in)']
774
775    descriptor_module = Module('genrule', target_module_name, target.name)
776    descriptor_module.cmd = ' '.join(cmd)
777    descriptor_module.out.add(out)
778    descriptor_module.tools = tools
779    blueprint.add_module(descriptor_module)
780
781    # Recursively extract the .proto files of all the dependencies and
782    # add them to srcs.
783    descriptor_module.srcs.update(
784        gn_utils.label_to_path(src) for src in target.sources)
785    # Add the tool_files to srcs so that they get copied if this action is
786    # sandboxed in Soong.
787    # Add to `srcs` instead of `tool_files` (the latter will require a
788    # --proto_path that depends on Soong's sandbox implementation.)
789    descriptor_module.srcs.update(
790        src for src in tool_files)
791    for dep in target.transitive_proto_deps():
792      current_target = gn.get_target(dep.name)
793      descriptor_module.srcs.update(
794          gn_utils.label_to_path(src) for src in current_target.sources)
795
796    return descriptor_module
797
798  # We create two genrules for each proto target: one for the headers and
799  # another for the sources. This is because the module that depends on the
800  # generated files needs to declare two different types of dependencies --
801  # source files in 'srcs' and headers in 'generated_headers' -- and it's not
802  # valid to generate .h files from a source dependency and vice versa.
803  #
804  # We create an additional filegroup for .proto
805  # The .proto filegroup will be added to `tool_files` of rdeps so that the
806  # genrules can be sandboxed.
807
808  for proto_dep in target.proto_deps().union(target.transitive_proto_deps()):
809    tool_files.add(":" + label_to_module_name(proto_dep.name))
810
811  filegroup_module = Module('filegroup', target_module_name, target.name)
812  filegroup_module.srcs.update(
813      gn_utils.label_to_path(src) for src in target.sources)
814  blueprint.add_module(filegroup_module)
815
816  source_module_name = target_module_name + '_gen'
817  source_module = Module('genrule', source_module_name, target.name)
818  # Add the "root" .proto filegroup to srcs
819  source_module.srcs = set([':' + target_module_name])
820  # Add the tool_files to srcs so that they get copied if this action is
821  # sandboxed in Soong.
822  # Add to `srcs` instead of `tool_files` (the latter will require a
823  # --proto_path that depends on Soong's sandbox implementation.)
824  source_module.srcs.update(
825      src for src in tool_files)
826  blueprint.add_module(source_module)
827
828  header_module = Module('genrule', source_module_name + '_headers',
829                         target.name)
830  blueprint.add_module(header_module)
831  header_module.srcs = set(source_module.srcs)
832
833  # TODO(primiano): at some point we should remove this. This was introduced
834  # by aosp/1108421 when adding "protos/" to .proto include paths, in order to
835  # avoid doing multi-repo changes and allow old clients in the android tree
836  # to still do the old #include "perfetto/..." rather than
837  # #include "protos/perfetto/...".
838  header_module.export_include_dirs = {'.', 'protos'}
839
840  source_module.genrule_srcs.add(':' + source_module.name)
841  source_module.genrule_headers.add(header_module.name)
842
843  if target.proto_plugin == 'proto':
844    suffixes = ['pb']
845    source_module.genrule_shared_libs.add('libprotobuf-cpp-lite')
846    cmd += ['--cpp_out=lite=true:' + cpp_out_dir]
847  elif target.proto_plugin == 'protozero':
848    suffixes = ['pbzero']
849    plugin = create_modules_from_target(blueprint, gn, protozero_plugin)
850    assert (plugin)
851    tools.add(plugin.name)
852    cmd += ['--plugin=protoc-gen-plugin=$(location %s)' % plugin.name]
853    cmd += ['--plugin_out=wrapper_namespace=pbzero:' + cpp_out_dir]
854  elif target.proto_plugin == 'cppgen':
855    suffixes = ['gen']
856    plugin = create_modules_from_target(blueprint, gn, cppgen_plugin)
857    assert (plugin)
858    tools.add(plugin.name)
859    cmd += ['--plugin=protoc-gen-plugin=$(location %s)' % plugin.name]
860    cmd += ['--plugin_out=wrapper_namespace=gen:' + cpp_out_dir]
861  elif target.proto_plugin == 'ipc':
862    suffixes = ['ipc']
863    plugin = create_modules_from_target(blueprint, gn, ipc_plugin)
864    assert (plugin)
865    tools.add(plugin.name)
866    cmd += ['--plugin=protoc-gen-plugin=$(location %s)' % plugin.name]
867    cmd += ['--plugin_out=wrapper_namespace=gen:' + cpp_out_dir]
868  else:
869    raise Error('Unsupported proto plugin: %s' % target.proto_plugin)
870
871  cmd += ['$(locations :%s)' % target_module_name]
872  source_module.cmd = ' '.join(cmd)
873  header_module.cmd = source_module.cmd
874  source_module.tools = tools
875  header_module.tools = tools
876
877
878  for sfx in suffixes:
879    source_module.out.update('%s/%s' %
880                             (tree_path, src.replace('.proto', '.%s.cc' % sfx))
881                             for src in filegroup_module.srcs)
882    header_module.out.update('%s/%s' %
883                             (tree_path, src.replace('.proto', '.%s.h' % sfx))
884                             for src in filegroup_module.srcs)
885  return source_module
886
887
888def create_tp_tables_module(blueprint: Blueprint, gn: GnParser,
889                            target: GnParser.Target):
890  bp_module_name = label_to_module_name(target.name)
891  bp_binary_module_name = f'{bp_module_name}_binary'
892  srcs = [gn_utils.label_to_path(src) for src in target.sources]
893
894  binary_module = Module('python_binary_host', bp_binary_module_name,
895                         target.name)
896  for dep in target.non_proto_or_source_set_deps():
897    binary_module.srcs.update([
898        gn_utils.label_to_path(src) for src in gn.get_target(dep.name).sources
899    ])
900  binary_module.srcs.update(srcs)
901  binary_module.srcs.add('tools/gen_tp_table_headers.py')
902  binary_module.main = 'tools/gen_tp_table_headers.py'
903  blueprint.add_module(binary_module)
904
905  module = Module('genrule', bp_module_name, target.name)
906  module.tools = set([
907      bp_binary_module_name,
908  ])
909  module.cmd = ' '.join([
910      f'$(location {bp_binary_module_name})',
911      '--gen-dir=$(genDir)',
912      '--relative-input-dir=external/perfetto',
913      '--inputs',
914      '$(in)',
915  ])
916  module.out.update(target.outputs)
917  module.genrule_headers.add(module.name)
918  module.srcs.update(srcs)
919  blueprint.add_module(module)
920
921  return module
922
923
924def create_amalgamated_sql_module(blueprint: Blueprint, gn: GnParser,
925                                  target: GnParser.Target):
926  bp_module_name = label_to_module_name(target.name)
927
928  def find_arg(name):
929    for i, arg in enumerate(target.args):
930      if arg.startswith(f'--{name}'):
931        return target.args[i + 1]
932
933  namespace = find_arg('namespace')
934
935  module = Module('genrule', bp_module_name, target.name)
936  module.tool_files = [
937      'tools/gen_amalgamated_sql.py',
938  ]
939  module.cmd = ' '.join([
940      '$(location tools/gen_amalgamated_sql.py)',
941      f'--namespace={namespace}',
942      '--cpp-out=$(out)',
943      '$(in)',
944  ])
945  module.genrule_headers.add(module.name)
946  module.out.update(target.outputs)
947
948  for dep in target.transitive_deps:
949    # Use globs for the chrome stdlib so the file does not need to be
950    # regenerated in autoroll CLs.
951    if dep.name.startswith(
952          '//src/trace_processor/perfetto_sql/stdlib/chrome:chrome_sql'):
953      module.srcs.add('src/trace_processor/perfetto_sql/stdlib/chrome/**/*.sql')
954      continue
955    module.srcs.update(
956        [gn_utils.label_to_path(src) for src in gn.get_target(dep.name).inputs])
957  blueprint.add_module(module)
958  return module
959
960
961def create_cc_proto_descriptor_module(blueprint: Blueprint,
962                                      target: GnParser.Target):
963  bp_module_name = label_to_module_name(target.name)
964  module = Module('genrule', bp_module_name, target.name)
965  module.tool_files = [
966      'tools/gen_cc_proto_descriptor.py',
967  ]
968  module.cmd = ' '.join([
969      '$(location tools/gen_cc_proto_descriptor.py)', '--gen_dir=$(genDir)',
970      '--cpp_out=$(out)', '$(in)'
971  ])
972  module.genrule_headers.add(module.name)
973  module.srcs.update(
974      ':' + label_to_module_name(dep.name) for dep in target.proto_deps())
975  module.srcs.update(
976      gn_utils.label_to_path(src)
977      for src in target.inputs
978      if "tmp.gn_utils" not in src)
979  module.out.update(target.outputs)
980  blueprint.add_module(module)
981  return module
982
983
984def create_gen_version_module(blueprint: Blueprint, target: GnParser.Target,
985                              bp_module_name: str):
986  module = Module('genrule', bp_module_name, gn_utils.GEN_VERSION_TARGET)
987  script_path = gn_utils.label_to_path(target.script)
988  module.genrule_headers.add(bp_module_name)
989  module.tool_files = [script_path]
990  module.out.update(target.outputs)
991  module.srcs.update(gn_utils.label_to_path(src) for src in target.inputs)
992  module.cmd = ' '.join([
993      'python3 $(location %s)' % script_path, '--no_git',
994      '--changelog=$(location CHANGELOG)', '--cpp_out=$(out)'
995  ])
996  blueprint.add_module(module)
997  return module
998
999
1000def create_proto_group_modules(blueprint, gn: GnParser, module_name: str,
1001                               group):
1002  target_names = group['targets']
1003  module_types = group['types']
1004  module_sources = set()
1005
1006  for name in target_names:
1007    target = gn.get_target(name)
1008    module_sources.update(gn_utils.label_to_path(src) for src in target.sources)
1009    for dep_label in target.transitive_proto_deps():
1010      dep = gn.get_target(dep_label.name)
1011      module_sources.update(gn_utils.label_to_path(src) for src in dep.sources)
1012
1013  for type in module_types:
1014    if type == 'filegroup':
1015      name = label_to_module_name(module_name) + '_filegroup_proto'
1016      module = Module('filegroup', name, name)
1017      module.comment = f'''GN: [{', '.join(target_names)}]'''
1018      module.srcs = module_sources
1019      blueprint.add_module(module)
1020    elif type == 'lite':
1021      name = label_to_module_name(module_name) + '_java_protos'
1022      module = Module('java_library', name, name)
1023      module.comment = f'''GN: [{', '.join(target_names)}]'''
1024      module.proto = {'type': 'lite', 'canonical_path_from_root': False}
1025      module.srcs = module_sources
1026      blueprint.add_module(module)
1027    elif type == 'python':
1028      name = label_to_module_name(module_name) + '_python_protos'
1029      module = Module('python_library_host', name, name)
1030      module.comment = f'''GN: [{', '.join(target_names)}]'''
1031      module.proto = {'canonical_path_from_root': False}
1032      module.srcs = module_sources
1033      blueprint.add_module(module)
1034    else:
1035      raise Error('Unhandled proto group type: {}'.format(group.type))
1036
1037
1038def _get_cflags(target: GnParser.Target):
1039  cflags = {flag for flag in target.cflags if re.match(cflag_allowlist, flag)}
1040  cflags |= set("-D%s" % define
1041                for define in target.defines
1042                if re.match(define_allowlist, define))
1043  return cflags
1044
1045
1046def create_modules_from_target(blueprint: Blueprint, gn: GnParser,
1047                               gn_target_name: str) -> Optional[Module]:
1048  """Generate module(s) for a given GN target.
1049
1050    Given a GN target name, generate one or more corresponding modules into a
1051    blueprint. The only case when this generates >1 module is proto libraries.
1052
1053    Args:
1054        blueprint: Blueprint instance which is being generated.
1055        gn: gn_utils.GnParser object.
1056        gn_target_name: GN target for module generation.
1057    """
1058  if gn_target_name in blueprint.gn_target_to_module:
1059    return blueprint.gn_target_to_module[gn_target_name]
1060
1061  target = gn.get_target(gn_target_name)
1062  bp_module_name = label_to_module_name(gn_target_name)
1063  name_without_toolchain = gn_utils.label_without_toolchain(target.name)
1064  if target.type == 'executable':
1065    if target.toolchain == gn_utils.HOST_TOOLCHAIN:
1066      module_type = 'cc_binary_host'
1067    elif target.testonly:
1068      module_type = 'cc_test'
1069    else:
1070      module_type = 'cc_binary'
1071    module = Module(module_type, bp_module_name, gn_target_name)
1072  elif target.type == 'static_library':
1073    module = Module('cc_library_static', bp_module_name, gn_target_name)
1074  elif target.type == 'shared_library':
1075    module = Module('cc_library_shared', bp_module_name, gn_target_name)
1076  elif target.type == 'source_set':
1077    module = Module('filegroup', bp_module_name, gn_target_name)
1078  elif target.type == 'group':
1079    # "group" targets are resolved recursively by gn_utils.get_target().
1080    # There's nothing we need to do at this level for them.
1081    return None
1082  elif target.type == 'proto_library':
1083    module = create_proto_modules(blueprint, gn, target)
1084    if module is None:
1085      return None
1086  elif target.type == 'action':
1087    if target.custom_action_type == 'sql_amalgamation':
1088      return create_amalgamated_sql_module(blueprint, gn, target)
1089    if target.custom_action_type == 'tp_tables':
1090      return create_tp_tables_module(blueprint, gn, target)
1091
1092    if target.custom_action_type == 'cc_proto_descriptor':
1093      module = create_cc_proto_descriptor_module(blueprint, target)
1094    elif name_without_toolchain == gn_utils.GEN_VERSION_TARGET:
1095      module = create_gen_version_module(blueprint, target, bp_module_name)
1096    else:
1097      raise Error('Unhandled action: {}'.format(target.name))
1098  else:
1099    raise Error('Unknown target %s (%s)' % (target.name, target.type))
1100
1101  blueprint.add_module(module)
1102  module.host_supported = (name_without_toolchain in target_host_supported)
1103  module.vendor_available = (name_without_toolchain in target_vendor_available)
1104  module.product_available = (name_without_toolchain in target_product_available)
1105  module.init_rc.update(target_initrc.get(target.name, []))
1106  if target.type != 'proto_library':
1107    # proto_library embeds a "root" filegroup in its srcs.
1108    # Skip to prevent adding dups
1109    module.srcs.update(
1110      gn_utils.label_to_path(src)
1111      for src in target.sources
1112      if is_supported_source_file(src))
1113
1114  if name_without_toolchain in needs_libfts:
1115    module.musl.static_libs.add('libfts')
1116
1117  if target.type in gn_utils.LINKER_UNIT_TYPES:
1118    module.cflags.update(_get_cflags(target))
1119
1120  module_is_compiled = module.type not in ('genrule', 'filegroup')
1121  if module_is_compiled:
1122    # Don't try to inject library/source dependencies into genrules or
1123    # filegroups because they are not compiled in the traditional sense.
1124    module.defaults.update([defaults_module])
1125    for lib in target.libs:
1126      # Generally library names should be mangled as 'libXXX', unless they
1127      # are HAL libraries (e.g., [email protected]) or AIDL c++ / NDK
1128      # libraries (e.g. "android.hardware.power.stats-V1-cpp")
1129      android_lib = lib if '@' in lib or "-cpp" in lib or "-ndk" in lib \
1130        else 'lib' + lib
1131      if lib in shared_library_allowlist:
1132        module.add_android_shared_lib(android_lib)
1133      if lib in static_library_allowlist:
1134        module.add_android_static_lib(android_lib)
1135
1136  # If the module is a static library, export all the generated headers.
1137  if module.type == 'cc_library_static':
1138    module.export_generated_headers = module.generated_headers
1139
1140  # Merge in additional hardcoded arguments.
1141  for key, add_val in additional_args.get(module.name, []):
1142    curr = getattr(module, key)
1143    if add_val and isinstance(add_val, set) and isinstance(curr, set):
1144      curr.update(add_val)
1145    elif isinstance(add_val, str) and (not curr or isinstance(curr, str)):
1146      setattr(module, key, add_val)
1147    elif isinstance(add_val, bool) and (not curr or isinstance(curr, bool)):
1148      setattr(module, key, add_val)
1149    elif isinstance(add_val, dict) and isinstance(curr, dict):
1150      curr.update(add_val)
1151    elif isinstance(add_val, dict) and isinstance(curr, Target):
1152      curr.__dict__.update(add_val)
1153    else:
1154      raise Error('Unimplemented type %r of additional_args: %r' %
1155                  (type(add_val), key))
1156
1157  # dep_name is an unmangled GN target name (e.g. //foo:bar(toolchain)).
1158  all_deps = target.non_proto_or_source_set_deps()
1159  all_deps |= target.transitive_source_set_deps()
1160  all_deps |= target.transitive_proto_deps()
1161  for dep in all_deps:
1162    # If the dependency refers to a library which we can replace with an
1163    # Android equivalent, stop recursing and patch the dependency in.
1164    # Don't recurse into //buildtools, builtin_deps are intercepted at
1165    # the //gn:xxx level.
1166    dep_name = dep.name
1167    if dep_name.startswith('//buildtools'):
1168      continue
1169
1170    # Ignore the dependency on the gen_buildflags genrule. That is run
1171    # separately in this generator and the generated file is copied over
1172    # into the repo (see usage of |buildflags_dir| in this script).
1173    if dep_name.startswith(gn_utils.BUILDFLAGS_TARGET):
1174      continue
1175
1176    dep_module = create_modules_from_target(blueprint, gn, dep_name)
1177
1178    # For filegroups and genrule, recurse but don't apply the deps.
1179    if not module_is_compiled:
1180      continue
1181
1182    # |builtin_deps| override GN deps with Android-specific ones. See the
1183    # config in the top of this file.
1184    if gn_utils.label_without_toolchain(dep_name) in builtin_deps:
1185      builtin_deps[gn_utils.label_without_toolchain(dep_name)](module)
1186      continue
1187
1188    # Don't recurse in any other //gn dep if not handled by builtin_deps.
1189    if dep_name.startswith('//gn:'):
1190      continue
1191
1192    if dep_module is None:
1193      continue
1194    if dep_module.type == 'cc_library_shared':
1195      module.shared_libs.add(dep_module.name)
1196    elif dep_module.type == 'cc_library_static':
1197      module.static_libs.add(dep_module.name)
1198    elif dep_module.type == 'filegroup':
1199      module.srcs.add(':' + dep_module.name)
1200    elif dep_module.type == 'genrule':
1201      module.generated_headers.update(dep_module.genrule_headers)
1202      module.srcs.update(dep_module.genrule_srcs)
1203      module.shared_libs.update(dep_module.genrule_shared_libs)
1204    elif dep_module.type == 'cc_binary':
1205      continue  # Ignore executables deps (used by cmdline integration tests).
1206    else:
1207      raise Error('Unknown dep %s (%s) for target %s' %
1208                  (dep_module.name, dep_module.type, module.name))
1209
1210  return module
1211
1212
1213def create_blueprint_for_targets(gn: GnParser, targets: List[str]):
1214  """Generate a blueprint for a list of GN targets."""
1215  blueprint = Blueprint()
1216
1217  # Default settings used by all modules.
1218  defaults = Module('cc_defaults', defaults_module, '//gn:default_deps')
1219
1220  # We have to use include_dirs passing the path relative to the android tree.
1221  # This is because: (i) perfetto_cc_defaults is used also by
1222  # test/**/Android.bp; (ii) if we use local_include_dirs instead, paths
1223  # become relative to the Android.bp that *uses* cc_defaults (not the one
1224  # that defines it).s
1225  defaults.include_dirs = {
1226      tree_path, tree_path + '/include', tree_path + '/' + buildflags_dir,
1227      tree_path + '/src/profiling/memory/include'
1228  }
1229  defaults.cflags.update([
1230      '-Wno-error=return-type',
1231      '-Wno-sign-compare',
1232      '-Wno-sign-promo',
1233      '-Wno-unused-parameter',
1234      '-fvisibility=hidden',
1235      '-O2',
1236  ])
1237  defaults.user_debug_flag = True
1238  defaults.lto = True
1239
1240  blueprint.add_module(defaults)
1241  for target in targets:
1242    create_modules_from_target(blueprint, gn, target)
1243  return blueprint
1244
1245
1246def main():
1247  parser = argparse.ArgumentParser(
1248      description='Generate Android.bp from a GN description.')
1249  parser.add_argument(
1250      '--check-only',
1251      help='Don\'t keep the generated files',
1252      action='store_true')
1253  parser.add_argument(
1254      '--desc',
1255      help='GN description (e.g., gn desc out --format=json --all-toolchains "//*"'
1256  )
1257  parser.add_argument(
1258      '--extras',
1259      help='Extra targets to include at the end of the Blueprint file',
1260      default=os.path.join(gn_utils.repo_root(), 'Android.bp.extras'),
1261  )
1262  parser.add_argument(
1263      '--output',
1264      help='Blueprint file to create',
1265      default=os.path.join(gn_utils.repo_root(), 'Android.bp'),
1266  )
1267  parser.add_argument(
1268      'targets',
1269      nargs=argparse.REMAINDER,
1270      help='Targets to include in the blueprint (e.g., "//:perfetto_tests")')
1271  args = parser.parse_args()
1272
1273  if args.desc:
1274    with open(args.desc) as f:
1275      desc = json.load(f)
1276  else:
1277    desc = gn_utils.create_build_description(gn_args)
1278
1279  gn = gn_utils.GnParser(desc)
1280  blueprint = create_blueprint_for_targets(gn, args.targets or default_targets)
1281  project_root = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
1282  tool_name = os.path.relpath(os.path.abspath(__file__), project_root)
1283
1284  # TODO(primiano): enable this on Android after the TODO in
1285  # perfetto_component.gni is fixed.
1286  # Check for ODR violations
1287  # for target_name in default_targets:
1288  # checker = gn_utils.ODRChecker(gn, target_name)
1289
1290  # Add any proto groups to the blueprint.
1291  for name, group in proto_groups.items():
1292    create_proto_group_modules(blueprint, gn, name, group)
1293
1294  output = [
1295      """// Copyright (C) 2017 The Android Open Source Project
1296//
1297// Licensed under the Apache License, Version 2.0 (the "License");
1298// you may not use this file except in compliance with the License.
1299// You may obtain a copy of the License at
1300//
1301//      http://www.apache.org/licenses/LICENSE-2.0
1302//
1303// Unless required by applicable law or agreed to in writing, software
1304// distributed under the License is distributed on an "AS IS" BASIS,
1305// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1306// See the License for the specific language governing permissions and
1307// limitations under the License.
1308//
1309// This file is automatically generated by %s. Do not edit.
1310""" % (tool_name)
1311  ]
1312  blueprint.to_string(output)
1313  with open(args.extras, 'r') as r:
1314    for line in r:
1315      output.append(line.rstrip("\n\r"))
1316
1317  out_files = []
1318
1319  # Generate the Android.bp file.
1320  out_files.append(args.output + '.swp')
1321  with open(out_files[-1], 'w') as f:
1322    f.write('\n'.join(output))
1323    # Text files should have a trailing EOL.
1324    f.write('\n')
1325
1326  # Generate the perfetto_build_flags.h file.
1327  out_files.append(os.path.join(buildflags_dir, 'perfetto_build_flags.h.swp'))
1328  gn_utils.gen_buildflags(gn_args, out_files[-1])
1329
1330  # Either check the contents or move the files to their final destination.
1331  return gn_utils.check_or_commit_generated_files(out_files, args.check_only)
1332
1333
1334if __name__ == '__main__':
1335  sys.exit(main())
1336