blob: af7d95de52a88f54427e02f28ef4009101e7b33c [file] [log] [blame]
Primiano Tucci34bc5592021-02-19 17:53:36 +01001#!/usr/bin/env python3
Sami Kyostila865d1d32017-12-12 18:37:04 +00002# 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
Lalit Magantife422eb2020-11-12 14:00:09 +000029import collections
Sami Kyostila865d1d32017-12-12 18:37:04 +000030import json
31import os
32import re
33import sys
34
Sami Kyostila3c88a1d2019-05-22 18:29:42 +010035import gn_utils
36
Matthew Clarkson9a5dfa52019-10-03 09:54:04 +010037from compat import itervalues
38
Florian Mayer246c1422019-09-18 15:40:38 +010039ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
40
Sami Kyostilab27619f2017-12-13 19:22:16 +000041# Arguments for the GN output directory.
Primiano Tucci9c411652019-08-27 07:13:59 +020042gn_args = ' '.join([
43 'is_debug=false',
Primiano Tucci7e05fc12019-08-27 17:29:47 +020044 'is_perfetto_build_generator=true',
Primiano Tucci9c411652019-08-27 07:13:59 +020045 'perfetto_build_with_android=true',
46 'target_cpu="arm"',
47 'target_os="android"',
48])
Sami Kyostilab27619f2017-12-13 19:22:16 +000049
Primiano Tucci02c11762019-08-30 00:57:59 +020050# Default targets to translate to the blueprint file.
51default_targets = [
52 '//:libperfetto_client_experimental',
53 '//:libperfetto',
54 '//:perfetto_integrationtests',
55 '//:perfetto_unittests',
56 '//protos/perfetto/trace:perfetto_trace_protos',
57 '//src/android_internal:libperfetto_android_internal',
58 '//src/perfetto_cmd:perfetto',
59 '//src/perfetto_cmd:trigger_perfetto',
60 '//src/profiling/memory:heapprofd_client',
Florian Mayer23f79372020-06-16 14:37:06 +020061 '//src/profiling/memory:heapprofd_client_api',
Florian Mayer72e87362020-12-11 19:37:25 +000062 '//src/profiling/memory:heapprofd_api_noop',
Primiano Tucci02c11762019-08-30 00:57:59 +020063 '//src/profiling/memory:heapprofd',
Florian Mayer50f07a62020-07-15 17:15:58 +010064 '//src/profiling/memory:heapprofd_standalone_client',
Ryan Savitski462b5db2019-11-20 19:06:46 +000065 '//src/profiling/perf:traced_perf',
Primiano Tucci02c11762019-08-30 00:57:59 +020066 '//src/traced/probes:traced_probes',
67 '//src/traced/service:traced',
Lalit Magantie0986f32020-09-17 15:35:47 +010068 '//src/trace_processor:trace_processor_shell',
Primiano Tuccifbf4a732019-12-11 00:32:15 +000069 '//test/cts:perfetto_cts_deps',
Lalit Maganti9782f492020-01-10 18:13:13 +000070 '//test/cts:perfetto_cts_jni_deps',
Primiano Tuccicbbe4802020-02-20 13:19:11 +000071 '//test:perfetto_gtest_logcat_printer',
Primiano Tuccif0d7ef82019-10-04 15:35:24 +010072]
73
74# Host targets
75ipc_plugin = '//src/ipc/protoc_plugin:ipc_plugin(%s)' % gn_utils.HOST_TOOLCHAIN
76protozero_plugin = '//src/protozero/protoc_plugin:protozero_plugin(%s)' % (
77 gn_utils.HOST_TOOLCHAIN)
Primiano Tucci57dd66b2019-10-15 23:09:04 +010078cppgen_plugin = '//src/protozero/protoc_plugin:cppgen_plugin(%s)' % (
79 gn_utils.HOST_TOOLCHAIN)
80
Primiano Tuccif0d7ef82019-10-04 15:35:24 +010081default_targets += [
Primiano Tuccif0d7ef82019-10-04 15:35:24 +010082 '//tools/trace_to_text:trace_to_text(%s)' % gn_utils.HOST_TOOLCHAIN,
83 protozero_plugin,
84 ipc_plugin,
Primiano Tucci02c11762019-08-30 00:57:59 +020085]
86
Primiano Tucci02c11762019-08-30 00:57:59 +020087# Defines a custom init_rc argument to be applied to the corresponding output
88# blueprint target.
89target_initrc = {
Primiano Tuccif0d7ef82019-10-04 15:35:24 +010090 '//src/traced/service:traced': {'perfetto.rc'},
91 '//src/profiling/memory:heapprofd': {'heapprofd.rc'},
Ryan Savitski29082bf2020-02-12 15:13:51 +000092 '//src/profiling/perf:traced_perf': {'traced_perf.rc'},
Primiano Tucci02c11762019-08-30 00:57:59 +020093}
94
95target_host_supported = [
Hector Dearman04cfac72019-09-24 22:05:55 +010096 '//:libperfetto',
Lalit Magantie0986f32020-09-17 15:35:47 +010097 '//protos/perfetto/trace:perfetto_trace_protos',
98 '//src/trace_processor:trace_processor_shell',
Primiano Tucci02c11762019-08-30 00:57:59 +020099]
100
Sami Kyostila865d1d32017-12-12 18:37:04 +0000101# All module names are prefixed with this string to avoid collisions.
102module_prefix = 'perfetto_'
103
104# Shared libraries which are directly translated to Android system equivalents.
Primiano Tuccia3645202020-08-03 16:28:18 +0200105shared_library_allowlist = [
Hector Dearman64f2e052019-12-04 20:51:14 +0000106 'android',
Hector Dearman92d7d112019-12-05 15:19:57 +0000107 'android.hardware.atrace@1.0',
108 'android.hardware.health@2.0',
109 'android.hardware.power.stats@1.0',
Raymond Chiu8c4d9a22021-02-23 19:59:10 +0000110 "android.hardware.power.stats-V1-cpp",
Primiano Tucci676f0cc2018-12-03 20:03:26 +0100111 'base',
Sami Kyostilab5b71692018-01-12 12:16:44 +0000112 'binder',
Raymond Chiu8c4d9a22021-02-23 19:59:10 +0000113 'binder_ndk',
Hector Dearman92d7d112019-12-05 15:19:57 +0000114 'cutils',
Primiano Tucci676f0cc2018-12-03 20:03:26 +0100115 'hidlbase',
116 'hidltransport',
117 'hwbinder',
Ryan Savitski53ca60b2019-06-03 13:04:40 +0100118 'incident',
Sami Kyostila865d1d32017-12-12 18:37:04 +0000119 'log',
Sami Kyostilab5b71692018-01-12 12:16:44 +0000120 'services',
Hector Dearman92d7d112019-12-05 15:19:57 +0000121 'statssocket',
Collin Fijalkovichef96fb72021-01-06 16:14:33 -0800122 "tracingproxy",
Primiano Tucciedf099c2018-01-08 18:27:56 +0000123 'utils',
Sami Kyostila865d1d32017-12-12 18:37:04 +0000124]
125
Hector Dearman92d7d112019-12-05 15:19:57 +0000126# Static libraries which are directly translated to Android system equivalents.
Primiano Tuccia3645202020-08-03 16:28:18 +0200127static_library_allowlist = [
Hector Dearman92d7d112019-12-05 15:19:57 +0000128 'statslog_perfetto',
129]
130
Sami Kyostila865d1d32017-12-12 18:37:04 +0000131# Name of the module which settings such as compiler flags for all other
132# modules.
133defaults_module = module_prefix + 'defaults'
134
135# Location of the project in the Android source tree.
136tree_path = 'external/perfetto'
137
Lalit Maganti3b09a3f2020-09-14 13:28:44 +0100138# Path for the protobuf sources in the standalone build.
139buildtools_protobuf_src = '//buildtools/protobuf/src'
140
141# Location of the protobuf src dir in the Android source tree.
142android_protobuf_src = 'external/protobuf/src'
143
Primiano Tucciedf099c2018-01-08 18:27:56 +0000144# Compiler flags which are passed through to the blueprint.
Primiano Tuccia3645202020-08-03 16:28:18 +0200145cflag_allowlist = r'^-DPERFETTO.*$'
Primiano Tucciedf099c2018-01-08 18:27:56 +0000146
Florian Mayer3d5e7e62018-01-19 15:22:46 +0000147# Compiler defines which are passed through to the blueprint.
Primiano Tuccia3645202020-08-03 16:28:18 +0200148define_allowlist = r'^(GOOGLE_PROTO.*)|(ZLIB_.*)|(USE_MMAP)|(HAVE_HIDDEN)$'
Florian Mayer3d5e7e62018-01-19 15:22:46 +0000149
Primiano Tucci8e627442019-08-28 07:58:38 +0200150# The directory where the generated perfetto_build_flags.h will be copied into.
151buildflags_dir = 'include/perfetto/base/build_configs/android_tree'
152
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100153
154def enumerate_data_deps():
155 with open(os.path.join(ROOT_DIR, 'tools', 'test_data.txt')) as f:
156 lines = f.readlines()
157 for line in (line.strip() for line in lines if not line.startswith('#')):
Andrew Shulaev576054d2020-01-23 13:44:51 +0000158 assert os.path.exists(line), 'file %s should exist' % line
Primiano Tucci02691162020-01-21 13:30:13 +0000159 if line.startswith('test/data/'):
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100160 # Skip test data files that require GCS. They are only for benchmarks.
161 # We don't run benchmarks in the android tree.
162 continue
Primiano Tucci17e8ae92021-05-17 17:40:50 +0100163 if line.endswith('/.'):
164 yield line[:-1] + '**/*'
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100165 else:
166 yield line
167
168
Florian Mayerb6a921f2018-10-18 18:55:23 +0100169# Additional arguments to apply to Android.bp rules.
170additional_args = {
Florian Mayer23f79372020-06-16 14:37:06 +0200171 'heapprofd_client_api': [
Florian Mayer23f79372020-06-16 14:37:06 +0200172 ('static_libs', {'libasync_safe'}),
Florian Mayer33159f72020-07-01 13:41:32 +0100173 # heapprofd_client_api MUST NOT have global constructors. Because it
174 # is loaded in an __attribute__((constructor)) of libc, we cannot
175 # guarantee that the global constructors get run before it is used.
176 ('cflags', {'-Wglobal-constructors', '-Werror=global-constructors'}),
Florian Mayer2131e362020-07-15 16:30:35 +0100177 ('version_script', 'src/profiling/memory/heapprofd_client_api.map.txt'),
Florian Mayer7ed3a952021-01-08 10:55:25 +0000178 ('stubs', {
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100179 'versions': ['S'],
180 'symbol_file': 'src/profiling/memory/heapprofd_client_api.map.txt',
Florian Mayer5d09f5e2021-02-19 14:59:49 +0000181 }),
182 ('export_include_dirs', {'src/profiling/memory/include'}),
183 ],
184 'heapprofd_api_noop': [
185 ('version_script', 'src/profiling/memory/heapprofd_client_api.map.txt'),
186 ('stubs', {
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100187 'versions': ['S'],
188 'symbol_file': 'src/profiling/memory/heapprofd_client_api.map.txt',
Florian Mayer5d09f5e2021-02-19 14:59:49 +0000189 }),
190 ('export_include_dirs', {'src/profiling/memory/include'}),
Florian Mayer23f79372020-06-16 14:37:06 +0200191 ],
Primiano Tucci676f0cc2018-12-03 20:03:26 +0100192 'heapprofd_client': [
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100193 ('include_dirs', {'bionic/libc'}),
194 ('static_libs', {'libasync_safe'}),
Primiano Tucci676f0cc2018-12-03 20:03:26 +0100195 ],
Florian Mayer50f07a62020-07-15 17:15:58 +0100196 'heapprofd_standalone_client': [
197 ('static_libs', {'libasync_safe'}),
198 ('version_script', 'src/profiling/memory/heapprofd_client_api.map.txt'),
Florian Mayer5d09f5e2021-02-19 14:59:49 +0000199 ('export_include_dirs', {'src/profiling/memory/include'}),
Florian Mayer23b75a42020-07-30 15:21:25 +0100200 ('stl', 'libc++_static'),
Florian Mayer50f07a62020-07-15 17:15:58 +0100201 ],
Ryan Savitski703bcab2019-12-18 14:38:14 +0000202 'perfetto_unittests': [
203 ('data', set(enumerate_data_deps())),
204 ('include_dirs', {'bionic/libc/kernel'}),
205 ],
Florian Mayerac4f4962020-09-15 10:03:22 +0100206 'perfetto_integrationtests': [
Yabin Cuia50f7d92021-08-11 13:26:20 -0700207 ('cflags', {'-fno-finite-loops'}),
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100208 ('test_suites', {'general-tests'}),
209 ('test_config', 'PerfettoIntegrationTests.xml'),
Florian Mayerac4f4962020-09-15 10:03:22 +0100210 ],
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100211 'traced_probes': [('required', {
212 'libperfetto_android_internal', 'trigger_perfetto', 'traced_perf',
213 'mm_events'
214 }),],
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100215 'libperfetto_android_internal': [('static_libs', {'libhealthhalutils'}),],
Lalit Maganticdda9112019-11-27 14:19:49 +0000216 'trace_processor_shell': [
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100217 ('strip', {
218 'all': True
219 }),
220 ('host', {
221 'stl': 'libc++_static',
222 'dist': {
223 'targets': ['sdk_repo']
224 },
225 }),
Lalit Maganticdda9112019-11-27 14:19:49 +0000226 ],
Jiyong Parkd5ea0112020-04-28 18:22:00 +0900227 'libperfetto_client_experimental': [
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100228 ('apex_available', {
229 '//apex_available:platform', 'com.android.art',
230 'com.android.art.debug'
231 }),
232 ('min_sdk_version', 'S'),
233 ('shared_libs', {'liblog'}),
234 ('export_include_dirs', {'include', buildflags_dir}),
Jiyong Parkd5ea0112020-04-28 18:22:00 +0900235 ],
236 'perfetto_trace_protos': [
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100237 ('apex_available', {
238 '//apex_available:platform', 'com.android.art',
239 'com.android.art.debug'
240 }),
241 ('min_sdk_version', 'S'),
Jiyong Parkd5ea0112020-04-28 18:22:00 +0900242 ],
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100243 'libperfetto': [('export_include_dirs', {'include', buildflags_dir}),],
Florian Mayerb6a921f2018-10-18 18:55:23 +0100244}
245
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100246
Primiano Tuccifbf4a732019-12-11 00:32:15 +0000247def enable_gtest_and_gmock(module):
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100248 module.static_libs.add('libgmock')
Primiano Tuccifbf4a732019-12-11 00:32:15 +0000249 module.static_libs.add('libgtest')
Primiano Tuccicbbe4802020-02-20 13:19:11 +0000250 if module.name != 'perfetto_gtest_logcat_printer':
251 module.whole_static_libs.add('perfetto_gtest_logcat_printer')
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100252
Sami Kyostila865d1d32017-12-12 18:37:04 +0000253
Sami Kyostila865d1d32017-12-12 18:37:04 +0000254def enable_protobuf_full(module):
Lalit Magantia97798d2020-09-16 17:40:57 +0100255 if module.type == 'cc_binary_host':
256 module.static_libs.add('libprotobuf-cpp-full')
Lalit Magantie0986f32020-09-17 15:35:47 +0100257 elif module.host_supported:
258 module.host.static_libs.add('libprotobuf-cpp-full')
259 module.android.shared_libs.add('libprotobuf-cpp-full')
Lalit Magantia97798d2020-09-16 17:40:57 +0100260 else:
261 module.shared_libs.add('libprotobuf-cpp-full')
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100262
Sami Kyostila865d1d32017-12-12 18:37:04 +0000263
Sami Kyostila865d1d32017-12-12 18:37:04 +0000264def enable_protobuf_lite(module):
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100265 module.shared_libs.add('libprotobuf-cpp-lite')
266
Sami Kyostila865d1d32017-12-12 18:37:04 +0000267
Sami Kyostila865d1d32017-12-12 18:37:04 +0000268def enable_protoc_lib(module):
Lalit Maganti3d415ec2019-10-23 17:53:17 +0100269 if module.type == 'cc_binary_host':
270 module.static_libs.add('libprotoc')
271 else:
272 module.shared_libs.add('libprotoc')
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100273
Sami Kyostila865d1d32017-12-12 18:37:04 +0000274
Florian Mayera2fae262018-08-31 12:10:01 -0700275def enable_libunwindstack(module):
Florian Mayer50f07a62020-07-15 17:15:58 +0100276 if module.name != 'heapprofd_standalone_client':
277 module.shared_libs.add('libunwindstack')
278 module.shared_libs.add('libprocinfo')
279 module.shared_libs.add('libbase')
280 else:
281 module.static_libs.add('libunwindstack')
282 module.static_libs.add('libprocinfo')
283 module.static_libs.add('libbase')
284 module.static_libs.add('liblzma')
285 module.static_libs.add('libdexfile_support')
Martin Stjernholmbe2411d2021-08-26 21:15:10 +0100286 module.runtime_libs.add('libdexfile') # libdexfile_support dependency
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100287
Sami Kyostila865d1d32017-12-12 18:37:04 +0000288
289def enable_libunwind(module):
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100290 # libunwind is disabled on Darwin so we cannot depend on it.
291 pass
292
Sami Kyostila865d1d32017-12-12 18:37:04 +0000293
Lalit Maganti17aa2732019-02-08 15:47:26 +0000294def enable_sqlite(module):
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100295 if module.type == 'cc_binary_host':
296 module.static_libs.add('libsqlite')
Lalit Magantie0986f32020-09-17 15:35:47 +0100297 elif module.host_supported:
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100298 # Copy what the sqlite3 command line tool does.
299 module.android.shared_libs.add('libsqlite')
300 module.android.shared_libs.add('libandroidicu')
301 module.android.shared_libs.add('liblog')
302 module.android.shared_libs.add('libutils')
303 module.host.static_libs.add('libsqlite')
Lalit Magantie0986f32020-09-17 15:35:47 +0100304 else:
305 module.shared_libs.add('libsqlite')
306 module.shared_libs.add('libandroidicu')
307 module.shared_libs.add('liblog')
308 module.shared_libs.add('libutils')
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100309
Lalit Maganti17aa2732019-02-08 15:47:26 +0000310
Hector Dearmane0b993f2019-05-24 18:48:16 +0100311def enable_zlib(module):
Lalit Maganti3d415ec2019-10-23 17:53:17 +0100312 if module.type == 'cc_binary_host':
313 module.static_libs.add('libz')
Lalit Magantie0986f32020-09-17 15:35:47 +0100314 elif module.host_supported:
315 module.android.shared_libs.add('libz')
316 module.host.static_libs.add('libz')
Lalit Maganti3d415ec2019-10-23 17:53:17 +0100317 else:
318 module.shared_libs.add('libz')
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100319
Hector Dearmane0b993f2019-05-24 18:48:16 +0100320
Ryan Savitski56bc0c62020-01-27 13:50:02 +0000321def enable_uapi_headers(module):
322 module.include_dirs.add('bionic/libc/kernel')
323
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100324
Florian Mayer682f05a2020-08-11 10:16:54 +0100325def enable_bionic_libc_platform_headers_on_android(module):
326 module.header_libs.add('bionic_libc_platform_headers')
327
Ryan Savitski56bc0c62020-01-27 13:50:02 +0000328
Sami Kyostila865d1d32017-12-12 18:37:04 +0000329# Android equivalents for third-party libraries that the upstream project
330# depends on.
331builtin_deps = {
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100332 '//gn:default_deps':
333 lambda x: None,
334 '//gn:gtest_main':
335 lambda x: None,
336 '//gn:protoc':
337 lambda x: None,
338 '//gn:gtest_and_gmock':
339 enable_gtest_and_gmock,
340 '//gn:libunwind':
341 enable_libunwind,
342 '//gn:protobuf_full':
343 enable_protobuf_full,
344 '//gn:protobuf_lite':
345 enable_protobuf_lite,
346 '//gn:protoc_lib':
347 enable_protoc_lib,
348 '//gn:libunwindstack':
349 enable_libunwindstack,
350 '//gn:sqlite':
351 enable_sqlite,
352 '//gn:zlib':
353 enable_zlib,
354 '//gn:bionic_kernel_uapi_headers':
355 enable_uapi_headers,
Florian Mayer682f05a2020-08-11 10:16:54 +0100356 '//src/profiling/memory:bionic_libc_platform_headers_on_android':
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100357 enable_bionic_libc_platform_headers_on_android,
Sami Kyostila865d1d32017-12-12 18:37:04 +0000358}
359
360# ----------------------------------------------------------------------------
361# End of configuration.
362# ----------------------------------------------------------------------------
363
364
365class Error(Exception):
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100366 pass
Sami Kyostila865d1d32017-12-12 18:37:04 +0000367
368
369class ThrowingArgumentParser(argparse.ArgumentParser):
Sami Kyostila865d1d32017-12-12 18:37:04 +0000370
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100371 def __init__(self, context):
372 super(ThrowingArgumentParser, self).__init__()
373 self.context = context
374
375 def error(self, message):
376 raise Error('%s: %s' % (self.context, message))
Sami Kyostila865d1d32017-12-12 18:37:04 +0000377
378
Lalit Magantiedace412019-06-18 13:28:28 +0100379def write_blueprint_key_value(output, name, value, sort=True):
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100380 """Writes a Blueprint key-value pair to the output"""
Lalit Magantiedace412019-06-18 13:28:28 +0100381
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100382 if not value:
383 return
384 if isinstance(value, set):
385 value = sorted(value)
386 if isinstance(value, list):
Colin Cross84172332021-09-14 16:41:33 -0700387 output.append(' %s: [' % name)
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100388 for item in sorted(value) if sort else value:
Colin Cross84172332021-09-14 16:41:33 -0700389 output.append(' "%s",' % item)
390 output.append(' ],')
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100391 return
392 if isinstance(value, bool):
Colin Cross84172332021-09-14 16:41:33 -0700393 output.append(' %s: true,' % name)
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100394 return
395 if isinstance(value, Target):
396 value.to_string(output)
397 return
Lalit Maganticdda9112019-11-27 14:19:49 +0000398 if isinstance(value, dict):
399 kv_output = []
400 for k, v in value.items():
401 write_blueprint_key_value(kv_output, k, v)
402
Colin Cross84172332021-09-14 16:41:33 -0700403 output.append(' %s: {' % name)
Lalit Maganticdda9112019-11-27 14:19:49 +0000404 for line in kv_output:
Colin Cross84172332021-09-14 16:41:33 -0700405 output.append(' %s' % line)
406 output.append(' },')
Lalit Maganticdda9112019-11-27 14:19:49 +0000407 return
Colin Cross84172332021-09-14 16:41:33 -0700408 output.append(' %s: "%s",' % (name, value))
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100409
Lalit Magantiedace412019-06-18 13:28:28 +0100410
411class Target(object):
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100412 """A target-scoped part of a module"""
Lalit Magantiedace412019-06-18 13:28:28 +0100413
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100414 def __init__(self, name):
415 self.name = name
416 self.shared_libs = set()
417 self.static_libs = set()
Primiano Tuccicbbe4802020-02-20 13:19:11 +0000418 self.whole_static_libs = set()
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100419 self.cflags = set()
Florian Mayer637513a2020-12-04 19:15:49 +0000420 self.dist = dict()
421 self.strip = dict()
Lalit Magantie0986f32020-09-17 15:35:47 +0100422 self.stl = None
Lalit Magantiedace412019-06-18 13:28:28 +0100423
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100424 def to_string(self, output):
425 nested_out = []
426 self._output_field(nested_out, 'shared_libs')
427 self._output_field(nested_out, 'static_libs')
Primiano Tuccicbbe4802020-02-20 13:19:11 +0000428 self._output_field(nested_out, 'whole_static_libs')
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100429 self._output_field(nested_out, 'cflags')
Lalit Magantie0986f32020-09-17 15:35:47 +0100430 self._output_field(nested_out, 'stl')
Florian Mayer637513a2020-12-04 19:15:49 +0000431 self._output_field(nested_out, 'dist')
432 self._output_field(nested_out, 'strip')
Lalit Magantiedace412019-06-18 13:28:28 +0100433
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100434 if nested_out:
Colin Cross84172332021-09-14 16:41:33 -0700435 output.append(' %s: {' % self.name)
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100436 for line in nested_out:
Colin Cross84172332021-09-14 16:41:33 -0700437 output.append(' %s' % line)
438 output.append(' },')
Lalit Magantiedace412019-06-18 13:28:28 +0100439
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100440 def _output_field(self, output, name, sort=True):
441 value = getattr(self, name)
442 return write_blueprint_key_value(output, name, value, sort)
443
Lalit Magantiedace412019-06-18 13:28:28 +0100444
Sami Kyostila865d1d32017-12-12 18:37:04 +0000445class Module(object):
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100446 """A single module (e.g., cc_binary, cc_test) in a blueprint."""
Sami Kyostila865d1d32017-12-12 18:37:04 +0000447
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100448 def __init__(self, mod_type, name, gn_target):
449 self.type = mod_type
450 self.gn_target = gn_target
451 self.name = name
452 self.srcs = set()
453 self.comment = 'GN: ' + gn_utils.label_without_toolchain(gn_target)
454 self.shared_libs = set()
455 self.static_libs = set()
Primiano Tuccicbbe4802020-02-20 13:19:11 +0000456 self.whole_static_libs = set()
Martin Stjernholmbe2411d2021-08-26 21:15:10 +0100457 self.runtime_libs = set()
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100458 self.tools = set()
459 self.cmd = None
460 self.host_supported = False
461 self.init_rc = set()
462 self.out = set()
463 self.export_include_dirs = set()
464 self.generated_headers = set()
465 self.export_generated_headers = set()
466 self.defaults = set()
467 self.cflags = set()
468 self.include_dirs = set()
469 self.header_libs = set()
470 self.required = set()
471 self.user_debug_flag = False
472 self.tool_files = None
473 self.android = Target('android')
474 self.host = Target('host')
475 self.lto = None
Lalit Maganticdda9112019-11-27 14:19:49 +0000476 self.stl = None
477 self.dist = dict()
Lalit Magantiaccd64b2020-03-16 19:54:10 +0000478 self.strip = dict()
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100479 self.data = set()
Jiyong Parkd5ea0112020-04-28 18:22:00 +0900480 self.apex_available = set()
Primiano Tucci39097c52021-03-04 09:58:06 +0000481 self.min_sdk_version = None
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100482 # The genrule_XXX below are properties that must to be propagated back
483 # on the module(s) that depend on the genrule.
484 self.genrule_headers = set()
485 self.genrule_srcs = set()
486 self.genrule_shared_libs = set()
Florian Mayer2131e362020-07-15 16:30:35 +0100487 self.version_script = None
Florian Mayerac4f4962020-09-15 10:03:22 +0100488 self.test_suites = set()
Florian Mayerab23f442021-02-09 15:37:45 +0000489 self.test_config = None
Florian Mayer7ed3a952021-01-08 10:55:25 +0000490 self.stubs = {}
Sami Kyostila865d1d32017-12-12 18:37:04 +0000491
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100492 def to_string(self, output):
493 if self.comment:
494 output.append('// %s' % self.comment)
495 output.append('%s {' % self.type)
496 self._output_field(output, 'name')
497 self._output_field(output, 'srcs')
498 self._output_field(output, 'shared_libs')
499 self._output_field(output, 'static_libs')
Primiano Tuccicbbe4802020-02-20 13:19:11 +0000500 self._output_field(output, 'whole_static_libs')
Martin Stjernholmbe2411d2021-08-26 21:15:10 +0100501 self._output_field(output, 'runtime_libs')
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100502 self._output_field(output, 'tools')
503 self._output_field(output, 'cmd', sort=False)
504 self._output_field(output, 'host_supported')
505 self._output_field(output, 'init_rc')
506 self._output_field(output, 'out')
507 self._output_field(output, 'export_include_dirs')
508 self._output_field(output, 'generated_headers')
509 self._output_field(output, 'export_generated_headers')
510 self._output_field(output, 'defaults')
511 self._output_field(output, 'cflags')
512 self._output_field(output, 'include_dirs')
513 self._output_field(output, 'header_libs')
514 self._output_field(output, 'required')
Lalit Maganticdda9112019-11-27 14:19:49 +0000515 self._output_field(output, 'dist')
Lalit Magantiaccd64b2020-03-16 19:54:10 +0000516 self._output_field(output, 'strip')
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100517 self._output_field(output, 'tool_files')
518 self._output_field(output, 'data')
Lalit Maganticdda9112019-11-27 14:19:49 +0000519 self._output_field(output, 'stl')
Jiyong Parkd5ea0112020-04-28 18:22:00 +0900520 self._output_field(output, 'apex_available')
Primiano Tucci39097c52021-03-04 09:58:06 +0000521 self._output_field(output, 'min_sdk_version')
Florian Mayer2131e362020-07-15 16:30:35 +0100522 self._output_field(output, 'version_script')
Florian Mayerac4f4962020-09-15 10:03:22 +0100523 self._output_field(output, 'test_suites')
Florian Mayerab23f442021-02-09 15:37:45 +0000524 self._output_field(output, 'test_config')
Florian Mayer7ed3a952021-01-08 10:55:25 +0000525 self._output_field(output, 'stubs')
Lalit Magantid8b1a1d2018-05-23 14:41:43 +0100526
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100527 target_out = []
528 self._output_field(target_out, 'android')
529 self._output_field(target_out, 'host')
530 if target_out:
Colin Cross84172332021-09-14 16:41:33 -0700531 output.append(' target: {')
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100532 for line in target_out:
Colin Cross84172332021-09-14 16:41:33 -0700533 output.append(' %s' % line)
534 output.append(' },')
Lalit Magantiedace412019-06-18 13:28:28 +0100535
Colin Cross162b48e2021-09-14 17:01:50 -0700536 if self.user_debug_flag:
Colin Cross84172332021-09-14 16:41:33 -0700537 output.append(' product_variables: {')
Colin Cross162b48e2021-09-14 17:01:50 -0700538 output.append(' debuggable: {')
539 output.append(
540 ' cflags: ["-DPERFETTO_BUILD_WITH_ANDROID_USERDEBUG"],')
541 output.append(' },')
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100542 output.append(' },')
Colin Cross84172332021-09-14 16:41:33 -0700543 if self.lto is not None:
544 output.append(' target: {')
545 output.append(' android: {')
546 output.append(' lto: {')
547 output.append(' thin: %s,' % 'true' if self.lto else 'false')
548 output.append(' },')
549 output.append(' },')
550 output.append(' },')
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100551 output.append('}')
552 output.append('')
Sami Kyostila865d1d32017-12-12 18:37:04 +0000553
Lalit Magantie0986f32020-09-17 15:35:47 +0100554 def add_android_static_lib(self, lib):
555 if self.type == 'cc_binary_host':
556 raise Exception('Adding Android static lib for host tool is unsupported')
557 elif self.host_supported:
558 self.android.static_libs.add(lib)
559 else:
560 self.static_libs.add(lib)
561
Lalit Magantie0986f32020-09-17 15:35:47 +0100562 def add_android_shared_lib(self, lib):
563 if self.type == 'cc_binary_host':
564 raise Exception('Adding Android shared lib for host tool is unsupported')
565 elif self.host_supported:
566 self.android.shared_libs.add(lib)
567 else:
568 self.shared_libs.add(lib)
569
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100570 def _output_field(self, output, name, sort=True):
571 value = getattr(self, name)
572 return write_blueprint_key_value(output, name, value, sort)
Sami Kyostila865d1d32017-12-12 18:37:04 +0000573
574
575class Blueprint(object):
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100576 """In-memory representation of an Android.bp file."""
Sami Kyostila865d1d32017-12-12 18:37:04 +0000577
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100578 def __init__(self):
579 self.modules = {}
Sami Kyostila865d1d32017-12-12 18:37:04 +0000580
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100581 def add_module(self, module):
582 """Adds a new module to the blueprint, replacing any existing module
Sami Kyostila865d1d32017-12-12 18:37:04 +0000583 with the same name.
584
585 Args:
586 module: Module instance.
587 """
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100588 self.modules[module.name] = module
Sami Kyostila865d1d32017-12-12 18:37:04 +0000589
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100590 def to_string(self, output):
591 for m in sorted(itervalues(self.modules), key=lambda m: m.name):
592 m.to_string(output)
Sami Kyostila865d1d32017-12-12 18:37:04 +0000593
594
Sami Kyostila865d1d32017-12-12 18:37:04 +0000595def label_to_module_name(label):
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100596 """Turn a GN label (e.g., //:perfetto_tests) into a module name."""
597 # If the label is explicibly listed in the default target list, don't prefix
598 # its name and return just the target name. This is so tools like
599 # "trace_to_text" stay as such in the Android tree.
600 label_without_toolchain = gn_utils.label_without_toolchain(label)
601 if label in default_targets or label_without_toolchain in default_targets:
602 return label_without_toolchain.split(':')[-1]
Primiano Tucci02c11762019-08-30 00:57:59 +0200603
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100604 module = re.sub(r'^//:?', '', label_without_toolchain)
605 module = re.sub(r'[^a-zA-Z0-9_]', '_', module)
606 if not module.startswith(module_prefix):
607 return module_prefix + module
608 return module
Sami Kyostila865d1d32017-12-12 18:37:04 +0000609
610
Sami Kyostila865d1d32017-12-12 18:37:04 +0000611def is_supported_source_file(name):
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100612 """Returns True if |name| can appear in a 'srcs' list."""
613 return os.path.splitext(name)[1] in ['.c', '.cc', '.proto']
Sami Kyostila865d1d32017-12-12 18:37:04 +0000614
615
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100616def create_proto_modules(blueprint, gn, target):
617 """Generate genrules for a proto GN target.
Sami Kyostila865d1d32017-12-12 18:37:04 +0000618
619 GN actions are used to dynamically generate files during the build. The
620 Soong equivalent is a genrule. This function turns a specific kind of
621 genrule which turns .proto files into source and header files into a pair
Sami Kyostila71625d72017-12-18 10:29:49 +0000622 equivalent genrules.
Sami Kyostila865d1d32017-12-12 18:37:04 +0000623
624 Args:
625 blueprint: Blueprint instance which is being generated.
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100626 target: gn_utils.Target object.
Sami Kyostila865d1d32017-12-12 18:37:04 +0000627
628 Returns:
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100629 The source_genrule module.
Sami Kyostila865d1d32017-12-12 18:37:04 +0000630 """
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100631 assert (target.type == 'proto_library')
Lalit Maganti117272f2020-09-11 14:01:18 +0100632
633 tools = {'aprotoc'}
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100634 cpp_out_dir = '$(genDir)/%s/' % tree_path
Lalit Maganti117272f2020-09-11 14:01:18 +0100635 target_module_name = label_to_module_name(target.name)
636
637 # In GN builds the proto path is always relative to the output directory
638 # (out/tmp.xxx).
Primiano Tucci3aa027d2019-11-22 21:43:43 +0000639 cmd = ['mkdir -p %s &&' % cpp_out_dir, '$(location aprotoc)']
Lalit Maganti117272f2020-09-11 14:01:18 +0100640 cmd += ['--proto_path=%s' % tree_path]
641
Lalit Maganti3b09a3f2020-09-14 13:28:44 +0100642 if buildtools_protobuf_src in target.proto_paths:
643 cmd += ['--proto_path=%s' % android_protobuf_src]
644
Lalit Maganti117272f2020-09-11 14:01:18 +0100645 # We don't generate any targets for source_set proto modules because
646 # they will be inlined into other modules if required.
647 if target.proto_plugin == 'source_set':
648 return None
649
650 # Descriptor targets only generate a single target.
651 if target.proto_plugin == 'descriptor':
652 out = '{}.bin'.format(target_module_name)
653
Lalit Magantife422eb2020-11-12 14:00:09 +0000654 cmd += ['--descriptor_set_out=$(out)']
Lalit Maganti117272f2020-09-11 14:01:18 +0100655 cmd += ['$(in)']
656
657 descriptor_module = Module('genrule', target_module_name, target.name)
658 descriptor_module.cmd = ' '.join(cmd)
659 descriptor_module.out = [out]
660 descriptor_module.tools = tools
661 blueprint.add_module(descriptor_module)
662
Lalit Magantife422eb2020-11-12 14:00:09 +0000663 # Recursively extract the .proto files of all the dependencies and
664 # add them to srcs.
665 target_queue = collections.deque([target.name])
666 seen_targets = set()
667 while target_queue:
668 dep = target_queue.popleft()
669 if dep in seen_targets:
670 continue
671 seen_targets.add(dep)
672
673 current_target = gn.get_target(dep)
674 descriptor_module.srcs.update(
675 gn_utils.label_to_path(src) for src in current_target.sources)
676 target_queue.extend(current_target.proto_deps)
677
Lalit Maganti117272f2020-09-11 14:01:18 +0100678 return descriptor_module
Sami Kyostila865d1d32017-12-12 18:37:04 +0000679
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100680 # We create two genrules for each proto target: one for the headers and
681 # another for the sources. This is because the module that depends on the
682 # generated files needs to declare two different types of dependencies --
683 # source files in 'srcs' and headers in 'generated_headers' -- and it's not
684 # valid to generate .h files from a source dependency and vice versa.
Lalit Maganti117272f2020-09-11 14:01:18 +0100685 source_module_name = target_module_name + '_gen'
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100686 source_module = Module('genrule', source_module_name, target.name)
687 blueprint.add_module(source_module)
688 source_module.srcs.update(
689 gn_utils.label_to_path(src) for src in target.sources)
Primiano Tucci20b760c2018-01-19 12:36:12 +0000690
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100691 header_module = Module('genrule', source_module_name + '_headers',
692 target.name)
693 blueprint.add_module(header_module)
694 header_module.srcs = set(source_module.srcs)
Primiano Tucci20b760c2018-01-19 12:36:12 +0000695
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100696 # TODO(primiano): at some point we should remove this. This was introduced
697 # by aosp/1108421 when adding "protos/" to .proto include paths, in order to
698 # avoid doing multi-repo changes and allow old clients in the android tree
699 # to still do the old #include "perfetto/..." rather than
700 # #include "protos/perfetto/...".
701 header_module.export_include_dirs = {'.', 'protos'}
Sami Kyostila865d1d32017-12-12 18:37:04 +0000702
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100703 source_module.genrule_srcs.add(':' + source_module.name)
704 source_module.genrule_headers.add(header_module.name)
Sami Kyostila865d1d32017-12-12 18:37:04 +0000705
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100706 if target.proto_plugin == 'proto':
Primiano Tucci3aa027d2019-11-22 21:43:43 +0000707 suffixes = ['pb']
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100708 source_module.genrule_shared_libs.add('libprotobuf-cpp-lite')
Primiano Tucci7b6a7882020-01-20 22:34:31 +0000709 cmd += ['--cpp_out=lite=true:' + cpp_out_dir]
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100710 elif target.proto_plugin == 'protozero':
711 suffixes = ['pbzero']
712 plugin = create_modules_from_target(blueprint, gn, protozero_plugin)
713 tools.add(plugin.name)
714 cmd += ['--plugin=protoc-gen-plugin=$(location %s)' % plugin.name]
715 cmd += ['--plugin_out=wrapper_namespace=pbzero:' + cpp_out_dir]
Primiano Tucci57dd66b2019-10-15 23:09:04 +0100716 elif target.proto_plugin == 'cppgen':
717 suffixes = ['gen']
718 plugin = create_modules_from_target(blueprint, gn, cppgen_plugin)
719 tools.add(plugin.name)
720 cmd += ['--plugin=protoc-gen-plugin=$(location %s)' % plugin.name]
Primiano Tuccie8020f92019-11-26 13:24:01 +0000721 cmd += ['--plugin_out=wrapper_namespace=gen:' + cpp_out_dir]
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100722 elif target.proto_plugin == 'ipc':
Primiano Tucci3aa027d2019-11-22 21:43:43 +0000723 suffixes = ['ipc']
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100724 plugin = create_modules_from_target(blueprint, gn, ipc_plugin)
725 tools.add(plugin.name)
726 cmd += ['--plugin=protoc-gen-plugin=$(location %s)' % plugin.name]
Primiano Tuccie8020f92019-11-26 13:24:01 +0000727 cmd += ['--plugin_out=wrapper_namespace=gen:' + cpp_out_dir]
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100728 else:
729 raise Error('Unsupported proto plugin: %s' % target.proto_plugin)
Sami Kyostila865d1d32017-12-12 18:37:04 +0000730
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100731 cmd += ['$(in)']
732 source_module.cmd = ' '.join(cmd)
733 header_module.cmd = source_module.cmd
734 source_module.tools = tools
735 header_module.tools = tools
Primiano Tucci20b760c2018-01-19 12:36:12 +0000736
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100737 for sfx in suffixes:
Matthew Clarkson63028d62019-10-10 15:48:23 +0100738 source_module.out.update('%s/%s' %
739 (tree_path, src.replace('.proto', '.%s.cc' % sfx))
740 for src in source_module.srcs)
741 header_module.out.update('%s/%s' %
742 (tree_path, src.replace('.proto', '.%s.h' % sfx))
743 for src in header_module.srcs)
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100744 return source_module
Sami Kyostila865d1d32017-12-12 18:37:04 +0000745
Sami Kyostila3c88a1d2019-05-22 18:29:42 +0100746
Lalit Maganti4c328e32021-11-09 19:29:50 +0000747def create_amalgamated_sql_metrics_module(blueprint, target):
Lalit Maganti3b09a3f2020-09-14 13:28:44 +0100748 bp_module_name = label_to_module_name(target.name)
749 module = Module('genrule', bp_module_name, target.name)
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100750 module.tool_files = [
Lalit Maganti4c328e32021-11-09 19:29:50 +0000751 'tools/gen_amalgamated_sql_metrics.py',
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100752 ]
753 module.cmd = ' '.join([
Lalit Maganti4c328e32021-11-09 19:29:50 +0000754 '$(location tools/gen_amalgamated_sql_metrics.py)',
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100755 '--cpp_out=$(out)',
756 '$(in)',
757 ])
Lalit Maganti117272f2020-09-11 14:01:18 +0100758 module.genrule_headers.add(module.name)
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100759 module.out.update(target.outputs)
760 module.srcs.update(gn_utils.label_to_path(src) for src in target.inputs)
761 blueprint.add_module(module)
762 return module
Sami Kyostila865d1d32017-12-12 18:37:04 +0000763
Sami Kyostila3c88a1d2019-05-22 18:29:42 +0100764
Lalit Maganti3b09a3f2020-09-14 13:28:44 +0100765def create_cc_proto_descriptor_module(blueprint, target):
766 bp_module_name = label_to_module_name(target.name)
767 module = Module('genrule', bp_module_name, target.name)
Lalit Maganti117272f2020-09-11 14:01:18 +0100768 module.tool_files = [
769 'tools/gen_cc_proto_descriptor.py',
770 ]
771 module.cmd = ' '.join([
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100772 '$(location tools/gen_cc_proto_descriptor.py)', '--gen_dir=$(genDir)',
773 '--cpp_out=$(out)', '$(in)'
Lalit Maganti117272f2020-09-11 14:01:18 +0100774 ])
775 module.genrule_headers.add(module.name)
776 module.srcs.update(
777 ':' + label_to_module_name(dep) for dep in target.proto_deps)
778 module.out.update(target.outputs)
779 blueprint.add_module(module)
780 return module
781
782
Primiano Tucciec590132020-11-16 14:16:44 +0100783def create_gen_version_module(blueprint, target, bp_module_name):
784 module = Module('genrule', bp_module_name, gn_utils.GEN_VERSION_TARGET)
785 script_path = gn_utils.label_to_path(target.script)
786 module.genrule_headers.add(bp_module_name)
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100787 module.tool_files = [script_path]
Primiano Tucciec590132020-11-16 14:16:44 +0100788 module.out.update(target.outputs)
789 module.srcs.update(gn_utils.label_to_path(src) for src in target.inputs)
790 module.cmd = ' '.join([
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100791 'python3 $(location %s)' % script_path, '--no_git',
792 '--changelog=$(location CHANGELOG)', '--cpp_out=$(out)'
Primiano Tucciec590132020-11-16 14:16:44 +0100793 ])
794 blueprint.add_module(module)
795 return module
796
797
Florian Mayer3d5e7e62018-01-19 15:22:46 +0000798def _get_cflags(target):
Primiano Tuccia3645202020-08-03 16:28:18 +0200799 cflags = {flag for flag in target.cflags if re.match(cflag_allowlist, flag)}
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100800 cflags |= set("-D%s" % define
801 for define in target.defines
Primiano Tuccia3645202020-08-03 16:28:18 +0200802 if re.match(define_allowlist, define))
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100803 return cflags
Florian Mayer3d5e7e62018-01-19 15:22:46 +0000804
805
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100806def create_modules_from_target(blueprint, gn, gn_target_name):
807 """Generate module(s) for a given GN target.
Sami Kyostila865d1d32017-12-12 18:37:04 +0000808
809 Given a GN target name, generate one or more corresponding modules into a
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100810 blueprint. The only case when this generates >1 module is proto libraries.
Sami Kyostila865d1d32017-12-12 18:37:04 +0000811
812 Args:
813 blueprint: Blueprint instance which is being generated.
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100814 gn: gn_utils.GnParser object.
815 gn_target_name: GN target for module generation.
Sami Kyostila865d1d32017-12-12 18:37:04 +0000816 """
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100817 bp_module_name = label_to_module_name(gn_target_name)
818 if bp_module_name in blueprint.modules:
819 return blueprint.modules[bp_module_name]
820 target = gn.get_target(gn_target_name)
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100821
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100822 name_without_toolchain = gn_utils.label_without_toolchain(target.name)
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100823 if target.type == 'executable':
824 if target.toolchain == gn_utils.HOST_TOOLCHAIN:
825 module_type = 'cc_binary_host'
826 elif target.testonly:
827 module_type = 'cc_test'
Sami Kyostila865d1d32017-12-12 18:37:04 +0000828 else:
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100829 module_type = 'cc_binary'
830 module = Module(module_type, bp_module_name, gn_target_name)
831 elif target.type == 'static_library':
832 module = Module('cc_library_static', bp_module_name, gn_target_name)
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100833 elif target.type == 'shared_library':
834 module = Module('cc_library_shared', bp_module_name, gn_target_name)
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100835 elif target.type == 'source_set':
836 module = Module('filegroup', bp_module_name, gn_target_name)
837 elif target.type == 'group':
838 # "group" targets are resolved recursively by gn_utils.get_target().
839 # There's nothing we need to do at this level for them.
840 return None
841 elif target.type == 'proto_library':
842 module = create_proto_modules(blueprint, gn, target)
Lalit Maganti117272f2020-09-11 14:01:18 +0100843 if module is None:
844 return None
845 elif target.type == 'action':
Lalit Maganti4c328e32021-11-09 19:29:50 +0000846 if 'gen_amalgamated_sql_metrics' in target.name:
847 module = create_amalgamated_sql_metrics_module(blueprint, target)
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100848 elif re.match('.*gen_cc_.*_descriptor$', name_without_toolchain):
Lalit Maganti3b09a3f2020-09-14 13:28:44 +0100849 module = create_cc_proto_descriptor_module(blueprint, target)
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100850 elif target.type == 'action' and \
851 name_without_toolchain == gn_utils.GEN_VERSION_TARGET:
Primiano Tucciec590132020-11-16 14:16:44 +0100852 module = create_gen_version_module(blueprint, target, bp_module_name)
Hector Dearmana1d75242020-10-02 09:47:24 +0100853 else:
854 raise Error('Unhandled action: {}'.format(target.name))
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100855 else:
856 raise Error('Unknown target %s (%s)' % (target.name, target.type))
Sami Kyostila865d1d32017-12-12 18:37:04 +0000857
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100858 blueprint.add_module(module)
Lalit Maganti9c2318c2021-05-20 16:21:41 +0100859 module.host_supported = (name_without_toolchain in target_host_supported)
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100860 module.init_rc = target_initrc.get(target.name, [])
861 module.srcs.update(
862 gn_utils.label_to_path(src)
863 for src in target.sources
864 if is_supported_source_file(src))
Primiano Tucci6067e732018-01-08 16:19:40 +0000865
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100866 if target.type in gn_utils.LINKER_UNIT_TYPES:
867 module.cflags.update(_get_cflags(target))
Sami Kyostila865d1d32017-12-12 18:37:04 +0000868
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100869 module_is_compiled = module.type not in ('genrule', 'filegroup')
870 if module_is_compiled:
871 # Don't try to inject library/source dependencies into genrules or
872 # filegroups because they are not compiled in the traditional sense.
873 module.defaults = [defaults_module]
874 for lib in target.libs:
875 # Generally library names should be mangled as 'libXXX', unless they
Raymond Chiu8c4d9a22021-02-23 19:59:10 +0000876 # are HAL libraries (e.g., android.hardware.health@2.0) or AIDL c++
877 # libraries (e.g. "android.hardware.power.stats-V1-cpp")
878 android_lib = lib if '@' in lib or "-cpp" in lib else 'lib' + lib
Primiano Tuccia3645202020-08-03 16:28:18 +0200879 if lib in shared_library_allowlist:
Lalit Magantie0986f32020-09-17 15:35:47 +0100880 module.add_android_shared_lib(android_lib)
Primiano Tuccia3645202020-08-03 16:28:18 +0200881 if lib in static_library_allowlist:
Lalit Magantie0986f32020-09-17 15:35:47 +0100882 module.add_android_static_lib(android_lib)
Lalit Magantic5bcd792018-01-12 18:38:11 +0000883
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100884 # If the module is a static library, export all the generated headers.
885 if module.type == 'cc_library_static':
886 module.export_generated_headers = module.generated_headers
Ryan Savitskie65beca2019-01-29 18:29:13 +0000887
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100888 # Merge in additional hardcoded arguments.
889 for key, add_val in additional_args.get(module.name, []):
890 curr = getattr(module, key)
891 if add_val and isinstance(add_val, set) and isinstance(curr, set):
892 curr.update(add_val)
Lalit Maganticdda9112019-11-27 14:19:49 +0000893 elif isinstance(add_val, str) and (not curr or isinstance(curr, str)):
Lalit Maganti3d415ec2019-10-23 17:53:17 +0100894 setattr(module, key, add_val)
Florian Mayerac4f4962020-09-15 10:03:22 +0100895 elif isinstance(add_val, bool) and (not curr or isinstance(curr, bool)):
896 setattr(module, key, add_val)
Lalit Maganticdda9112019-11-27 14:19:49 +0000897 elif isinstance(add_val, dict) and isinstance(curr, dict):
898 curr.update(add_val)
Lalit Magantie0986f32020-09-17 15:35:47 +0100899 elif isinstance(add_val, dict) and isinstance(curr, Target):
900 curr.__dict__.update(add_val)
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100901 else:
Florian Mayer5d09f5e2021-02-19 14:59:49 +0000902 raise Error('Unimplemented type %r of additional_args: %r' %
903 (type(add_val), key))
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100904
905 # dep_name is an unmangled GN target name (e.g. //foo:bar(toolchain)).
906 for dep_name in target.deps | target.source_set_deps | target.proto_deps:
907 # If the dependency refers to a library which we can replace with an
908 # Android equivalent, stop recursing and patch the dependency in.
909 # Don't recurse into //buildtools, builtin_deps are intercepted at
910 # the //gn:xxx level.
911 if dep_name.startswith('//buildtools'):
912 continue
913
914 # Ignore the dependency on the gen_buildflags genrule. That is run
915 # separately in this generator and the generated file is copied over
916 # into the repo (see usage of |buildflags_dir| in this script).
917 if dep_name.startswith(gn_utils.BUILDFLAGS_TARGET):
918 continue
919
920 dep_module = create_modules_from_target(blueprint, gn, dep_name)
921
922 # For filegroups and genrule, recurse but don't apply the deps.
923 if not module_is_compiled:
924 continue
925
926 # |builtin_deps| override GN deps with Android-specific ones. See the
927 # config in the top of this file.
928 if gn_utils.label_without_toolchain(dep_name) in builtin_deps:
929 builtin_deps[gn_utils.label_without_toolchain(dep_name)](module)
930 continue
931
932 # Don't recurse in any other //gn dep if not handled by builtin_deps.
933 if dep_name.startswith('//gn:'):
934 continue
935
936 if dep_module is None:
937 continue
938 if dep_module.type == 'cc_library_shared':
939 module.shared_libs.add(dep_module.name)
940 elif dep_module.type == 'cc_library_static':
941 module.static_libs.add(dep_module.name)
942 elif dep_module.type == 'filegroup':
943 module.srcs.add(':' + dep_module.name)
944 elif dep_module.type == 'genrule':
945 module.generated_headers.update(dep_module.genrule_headers)
946 module.srcs.update(dep_module.genrule_srcs)
947 module.shared_libs.update(dep_module.genrule_shared_libs)
Primiano Tuccie094eec2020-03-18 16:58:21 +0000948 elif dep_module.type == 'cc_binary':
949 continue # Ignore executables deps (used by cmdline integration tests).
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100950 else:
951 raise Error('Unknown dep %s (%s) for target %s' %
952 (dep_module.name, dep_module.type, module.name))
953
954 return module
Sami Kyostila865d1d32017-12-12 18:37:04 +0000955
956
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100957def create_blueprint_for_targets(gn, desc, targets):
958 """Generate a blueprint for a list of GN targets."""
959 blueprint = Blueprint()
Sami Kyostila865d1d32017-12-12 18:37:04 +0000960
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100961 # Default settings used by all modules.
962 defaults = Module('cc_defaults', defaults_module, '//gn:default_deps')
Sami Kyostila865d1d32017-12-12 18:37:04 +0000963
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100964 # We have to use include_dirs passing the path relative to the android tree.
965 # This is because: (i) perfetto_cc_defaults is used also by
966 # test/**/Android.bp; (ii) if we use local_include_dirs instead, paths
967 # become relative to the Android.bp that *uses* cc_defaults (not the one
968 # that defines it).s
969 defaults.include_dirs = {
Florian Mayer5d09f5e2021-02-19 14:59:49 +0000970 tree_path, tree_path + '/include', tree_path + '/' + buildflags_dir,
971 tree_path + '/src/profiling/memory/include'
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100972 }
973 defaults.cflags = [
974 '-Wno-error=return-type',
975 '-Wno-sign-compare',
976 '-Wno-sign-promo',
977 '-Wno-unused-parameter',
978 '-fvisibility=hidden',
979 '-O2',
980 ]
981 defaults.user_debug_flag = True
982 defaults.lto = True
Sami Kyostila865d1d32017-12-12 18:37:04 +0000983
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100984 blueprint.add_module(defaults)
985 gn = gn_utils.GnParser(desc)
986 for target in targets:
987 create_modules_from_target(blueprint, gn, target)
988 return blueprint
Sami Kyostila865d1d32017-12-12 18:37:04 +0000989
990
991def main():
Primiano Tuccif0d7ef82019-10-04 15:35:24 +0100992 parser = argparse.ArgumentParser(
993 description='Generate Android.bp from a GN description.')
994 parser.add_argument(
995 '--check-only',
996 help='Don\'t keep the generated files',
997 action='store_true')
998 parser.add_argument(
999 '--desc',
Matthew Clarkson63028d62019-10-10 15:48:23 +01001000 help='GN description (e.g., gn desc out --format=json --all-toolchains "//*"'
1001 )
Primiano Tuccif0d7ef82019-10-04 15:35:24 +01001002 parser.add_argument(
1003 '--extras',
1004 help='Extra targets to include at the end of the Blueprint file',
1005 default=os.path.join(gn_utils.repo_root(), 'Android.bp.extras'),
1006 )
1007 parser.add_argument(
1008 '--output',
1009 help='Blueprint file to create',
1010 default=os.path.join(gn_utils.repo_root(), 'Android.bp'),
1011 )
1012 parser.add_argument(
1013 'targets',
1014 nargs=argparse.REMAINDER,
1015 help='Targets to include in the blueprint (e.g., "//:perfetto_tests")')
1016 args = parser.parse_args()
Sami Kyostila865d1d32017-12-12 18:37:04 +00001017
Primiano Tuccif0d7ef82019-10-04 15:35:24 +01001018 if args.desc:
1019 with open(args.desc) as f:
1020 desc = json.load(f)
1021 else:
1022 desc = gn_utils.create_build_description(gn_args)
Sami Kyostila865d1d32017-12-12 18:37:04 +00001023
Primiano Tuccif0d7ef82019-10-04 15:35:24 +01001024 gn = gn_utils.GnParser(desc)
1025 blueprint = create_blueprint_for_targets(gn, desc, args.targets or
1026 default_targets)
Alexander Timin129c37c2021-04-08 19:17:59 +00001027 project_root = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
1028 tool_name = os.path.relpath(os.path.abspath(__file__), project_root)
Primiano Tucci916f4e52020-10-16 20:40:33 +02001029
1030 # TODO(primiano): enable this on Android after the TODO in
1031 # perfetto_component.gni is fixed.
1032 # Check for ODR violations
1033 # for target_name in default_targets:
Lalit Maganti9c2318c2021-05-20 16:21:41 +01001034 # checker = gn_utils.ODRChecker(gn, target_name)
Primiano Tucci916f4e52020-10-16 20:40:33 +02001035
Primiano Tuccif0d7ef82019-10-04 15:35:24 +01001036 output = [
1037 """// Copyright (C) 2017 The Android Open Source Project
Sami Kyostila865d1d32017-12-12 18:37:04 +00001038//
1039// Licensed under the Apache License, Version 2.0 (the "License");
1040// you may not use this file except in compliance with the License.
1041// You may obtain a copy of the License at
1042//
1043// http://www.apache.org/licenses/LICENSE-2.0
1044//
1045// Unless required by applicable law or agreed to in writing, software
1046// distributed under the License is distributed on an "AS IS" BASIS,
1047// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1048// See the License for the specific language governing permissions and
1049// limitations under the License.
1050//
1051// This file is automatically generated by %s. Do not edit.
Alexander Timin129c37c2021-04-08 19:17:59 +00001052""" % (tool_name)
Primiano Tuccif0d7ef82019-10-04 15:35:24 +01001053 ]
1054 blueprint.to_string(output)
1055 with open(args.extras, 'r') as r:
1056 for line in r:
1057 output.append(line.rstrip("\n\r"))
Primiano Tucci9c411652019-08-27 07:13:59 +02001058
Primiano Tuccif0d7ef82019-10-04 15:35:24 +01001059 out_files = []
Primiano Tucci9c411652019-08-27 07:13:59 +02001060
Primiano Tuccif0d7ef82019-10-04 15:35:24 +01001061 # Generate the Android.bp file.
1062 out_files.append(args.output + '.swp')
1063 with open(out_files[-1], 'w') as f:
1064 f.write('\n'.join(output))
Florian Mayerbbbd1ff2020-10-23 13:25:13 +01001065 # Text files should have a trailing EOL.
1066 f.write('\n')
Sami Kyostila865d1d32017-12-12 18:37:04 +00001067
Primiano Tuccif0d7ef82019-10-04 15:35:24 +01001068 # Generate the perfetto_build_flags.h file.
1069 out_files.append(os.path.join(buildflags_dir, 'perfetto_build_flags.h.swp'))
1070 gn_utils.gen_buildflags(gn_args, out_files[-1])
Sami Kyostila865d1d32017-12-12 18:37:04 +00001071
Primiano Tuccif0d7ef82019-10-04 15:35:24 +01001072 # Either check the contents or move the files to their final destination.
1073 return gn_utils.check_or_commit_generated_files(out_files, args.check_only)
Primiano Tucci9c411652019-08-27 07:13:59 +02001074
1075
Sami Kyostila865d1d32017-12-12 18:37:04 +00001076if __name__ == '__main__':
Primiano Tuccif0d7ef82019-10-04 15:35:24 +01001077 sys.exit(main())