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